Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Persistent cache #4120

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion packages/vite/src/node/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { injectQuery, isWindows } from '../utils'
import { asyncPool, injectQuery, isWindows } from '../utils'

if (isWindows) {
// this test will work incorrectly on unix systems
Expand Down Expand Up @@ -38,3 +38,19 @@ test('path with unicode, space, and %', () => {
'/usr/vite/東京 %20 hello?direct'
)
})

test('asyncPool', async () => {
const finished: number[] = []
await asyncPool({
concurrency: 3,
items: [1, 6, 4, 2, 5, 3],
fn: (nb) =>
new Promise<void>((resolve) =>
setTimeout(() => {
finished.push(nb)
resolve()
}, nb * 10)
)
})
expect(finished).toEqual([1, 2, 4, 6, 3, 5])
})
52 changes: 29 additions & 23 deletions packages/vite/src/node/server/moduleGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { FSWatcher } from 'chokidar'
import { performance } from 'perf_hooks'
import { isDirectCSSRequest } from '../plugins/css'
import {
asyncPool,
cleanUrl,
createDebugger,
ensureWatchedFile,
Expand Down Expand Up @@ -266,38 +267,43 @@ export class ModuleGraph {
try {
cache = JSON.parse(fs.readFileSync(cacheLocation, { encoding: 'utf-8' }))
} catch {
// This can happen when the process is killed while writing to disc.
// This can happen when the process is killed while writing to disk.
isDebug && debugModuleGraph('Corrupted cache, cache not loaded')
return
}
if (cache.configHash !== this.getCacheHash()) {
isDebug && debugModuleGraph("Config hash didn't match, cache not loaded")
return
}
for (const [url, value] of Object.entries(cache.files)) {
const id = (await this.resolveId(url, false))?.id || url
let loadResult = await this.load(id)
if (!loadResult) {
try {
loadResult = await fs.promises.readFile(id, 'utf-8')
} catch (e) {
if (e.code !== 'ENOENT') throw e
await asyncPool({
concurrency: 10,
items: Object.entries(cache.files),
fn: async ([url, value]) => {
const id = (await this.resolveId(url, false))?.id || url
let loadResult = await this.load(id)
if (!loadResult) {
try {
loadResult = await fs.promises.readFile(id, 'utf-8')
} catch (e) {
if (e.code !== 'ENOENT') throw e
}
}
if (!loadResult) {
isDebug && debugModuleGraph(`Module ${url} not found`)
return
}
const code =
typeof loadResult === 'object' ? loadResult.code : loadResult
if (getEtag(code, { weak: true }) !== value.sourceEtag) {
isDebug && debugModuleGraph(`Module ${url} changed`)
return
}
const module = await this.ensureEntryFromUrl(url)
ensureWatchedFile(this.watcher, module.file, this.config.root)
module.sourceEtag = value.sourceEtag
module.transformResult = value.transformResult
}
if (!loadResult) {
isDebug && debugModuleGraph(`Module ${url} not found`)
continue
}
const code = typeof loadResult === 'object' ? loadResult.code : loadResult
if (getEtag(code, { weak: true }) !== value.sourceEtag) {
isDebug && debugModuleGraph(`Module ${url} changed`)
continue
}
const module = await this.ensureEntryFromUrl(url)
ensureWatchedFile(this.watcher, module.file, this.config.root)
module.sourceEtag = value.sourceEtag
module.transformResult = value.transformResult
}
})
isDebug &&
debugModuleGraph(
timeFrom(start),
Expand Down
6 changes: 3 additions & 3 deletions packages/vite/src/node/server/transformRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ async function doTransform(
url
))
} else {
const transformResult = (mod.transformResult = {
mod.transformResult = {
code,
map: map as SourceMap,
etag: getEtag(code, { weak: true })
})
}
server.moduleGraph.queueSaveCache()
return transformResult
return mod.transformResult
}
}
23 changes: 23 additions & 0 deletions packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,3 +663,26 @@ export function parseRequest(id: string): Record<string, string> | null {
}
return Object.fromEntries(new URLSearchParams(search.slice(1)))
}

// TS rewrite of https://github.com/rxaviers/async-pool/blob/master/lib/es7.js
// Credits: Rafael Xavier de Souza http://rafael.xavier.blog.br
export async function asyncPool<Item, Result>({
concurrency,
items,
fn
}: {
concurrency: number
items: Item[]
fn: (item: Item) => Promise<Result>
}): Promise<Result[]> {
const promises: Promise<Result>[] = []
const pool = new Set<Promise<Result>>()
for (const item of items) {
const promise = fn(item)
promises.push(promise)
pool.add(promise)
promise.then(() => pool.delete(promise))
if (pool.size >= concurrency) await Promise.race(pool)
}
return Promise.all(promises)
}