From 43d6c92ea7d7a5a4c5adb2093c73acee15e5bdd6 Mon Sep 17 00:00:00 2001 From: patak Date: Fri, 14 Apr 2023 20:31:17 +0200 Subject: [PATCH 01/12] refactor: simplify crawlEndFinder --- packages/vite/src/node/optimizer/index.ts | 1 - packages/vite/src/node/optimizer/optimizer.ts | 103 +++++------------- .../vite/src/node/plugins/optimizedDeps.ts | 2 - 3 files changed, 25 insertions(+), 81 deletions(-) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 91727064d7b89a..1e84bdea805058 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -60,7 +60,6 @@ export interface DepsOptimizer { delayDepsOptimizerUntil: (id: string, done: () => Promise) => void registerWorkersSource: (id: string) => void resetRegisteredIds: () => void - ensureFirstRun: () => void close: () => Promise diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index a7131db778cf1c..636c3f80166b01 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -117,7 +117,6 @@ async function createDepsOptimizer( registerWorkersSource, delayDepsOptimizerUntil, resetRegisteredIds, - ensureFirstRun, close, options: getDepOptimizationConfig(config, ssr), } @@ -706,26 +705,21 @@ async function createDepsOptimizer( crawlEndFinder.delayDepsOptimizerUntil(id, done) } } - function ensureFirstRun() { - crawlEndFinder?.ensureFirstRun() - } } -const runOptimizerIfIdleAfterMs = 50 +const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { - ensureFirstRun: () => void registerWorkersSource: (id: string) => void delayDepsOptimizerUntil: (id: string, done: () => Promise) => void cancel: () => void } function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { - let registeredIds: { id: string; done: () => Promise }[] = [] + const registeredIds = new Set() const seenIds = new Set() const workersSources = new Set() - const waitingOn = new Map void>() - let firstRunEnsured = false + let timeoutHandle: NodeJS.Timeout | undefined let crawlEndCalled = false let cancelled = false @@ -740,91 +734,45 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { } } - // If all the inputs are dependencies, we aren't going to get any - // delayDepsOptimizerUntil(id) calls. We need to guard against this - // by forcing a rerun if no deps have been registered - function ensureFirstRun() { - if (!firstRunEnsured && seenIds.size === 0) { - setTimeout(() => { - if (seenIds.size === 0) { - callOnCrawlEnd() - } - }, runOptimizerIfIdleAfterMs) - } - firstRunEnsured = true - } - function registerWorkersSource(id: string): void { workersSources.add(id) + // Avoid waiting for this id, as it may be blocked by the rollup // bundling process of the worker that also depends on the optimizer - registeredIds = registeredIds.filter((registered) => registered.id !== id) + registeredIds.delete(id) - const resolve = waitingOn.get(id) - // Forced resolve to avoid waiting for the bundling of the worker to finish - resolve?.() + checkIfCrawlEndAfterTimeout() } function delayDepsOptimizerUntil(id: string, done: () => Promise): void { if (!seenIds.has(id)) { seenIds.add(id) - registeredIds.push({ id, done }) - callOnCrawlEndWhenIdle() + if (!workersSources.has(id)) { + registeredIds.add(id) + done().finally(() => markIdAsDone(id)) + } } } + function markIdAsDone(id: string): void { + registeredIds.delete(id) + checkIfCrawlEndAfterTimeout() + } - async function callOnCrawlEndWhenIdle() { - if (cancelled || waitingOn.size > 0) return - - const processingRegisteredIds = registeredIds - registeredIds = [] - - const donePromises = processingRegisteredIds.map(async (registeredId) => { - // During build, we need to cancel workers - let resolve: () => void - const waitUntilDone = new Promise((_resolve) => { - resolve = _resolve - registeredId - .done() - .catch(() => { - // Ignore errors - }) - .finally(() => resolve()) - }) - waitingOn.set(registeredId.id, () => resolve()) - - await waitUntilDone - waitingOn.delete(registeredId.id) - }) - - const afterLoad = () => { - if (cancelled) return - if ( - registeredIds.length > 0 && - registeredIds.every((registeredId) => - workersSources.has(registeredId.id), - ) - ) { - return - } - - if (registeredIds.length > 0) { - callOnCrawlEndWhenIdle() - } else { - callOnCrawlEnd() - } - } + function checkIfCrawlEndAfterTimeout() { + if (cancelled || registeredIds.size > 0) return - await Promise.allSettled(donePromises) - if (registeredIds.length > 0) { - afterLoad() - } else { - setTimeout(afterLoad, runOptimizerIfIdleAfterMs) - } + if (timeoutHandle) clearTimeout(timeoutHandle) + timeoutHandle = setTimeout( + callOnCrawlEndWhenIdle, + callCrawlEndIfIdleAfterMs, + ) + } + async function callOnCrawlEndWhenIdle() { + if (cancelled || registeredIds.size > 0) return + callOnCrawlEnd() } return { - ensureFirstRun, registerWorkersSource, delayDepsOptimizerUntil, cancel, @@ -854,7 +802,6 @@ async function createDevSsrDepsOptimizer( registerWorkersSource: (id: string) => {}, delayDepsOptimizerUntil: (id: string, done: () => Promise) => {}, resetRegisteredIds: () => {}, - ensureFirstRun: () => {}, close: async () => {}, options: config.ssr.optimizeDeps, diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index a91c961fddba6c..24b886b6a5fe23 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -120,8 +120,6 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { return } - depsOptimizer?.ensureFirstRun() - const file = cleanUrl(id) // Search in both the currently optimized and newly discovered deps // If all the inputs are dependencies, we aren't going to get any From 72be105282a5e07d7a8dd5460e32d846ba51f8d4 Mon Sep 17 00:00:00 2001 From: patak Date: Fri, 14 Apr 2023 21:07:56 +0200 Subject: [PATCH 02/12] fix: handle rejected load() promises --- packages/vite/src/node/optimizer/optimizer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index 636c3f80166b01..c7c0a0f5d766b6 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -749,7 +749,9 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { seenIds.add(id) if (!workersSources.has(id)) { registeredIds.add(id) - done().finally(() => markIdAsDone(id)) + done() + .catch(() => {}) + .finally(() => markIdAsDone(id)) } } } From 969ff9f32f620d6d18bf246b9e517035fb06928e Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 08:07:36 +0200 Subject: [PATCH 03/12] refactor: simplify id registration during build --- packages/vite/src/node/optimizer/optimizer.ts | 24 +++++++++++++-- .../vite/src/node/plugins/optimizedDeps.ts | 30 +++++++------------ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index c7c0a0f5d766b6..fb26715659a769 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -701,8 +701,12 @@ async function createDepsOptimizer( crawlEndFinder?.registerWorkersSource(id) } function delayDepsOptimizerUntil(id: string, done: () => Promise) { - if (crawlEndFinder && !depsOptimizer.isOptimizedDepFile(id)) { - crawlEndFinder.delayDepsOptimizerUntil(id, done) + if (crawlEndFinder) { + if (depsOptimizer.isOptimizedDepFile(id)) { + crawlEndFinder.ensureFirstRun() + } else { + crawlEndFinder.delayDepsOptimizerUntil(id, done) + } } } } @@ -712,6 +716,7 @@ const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { registerWorkersSource: (id: string) => void delayDepsOptimizerUntil: (id: string, done: () => Promise) => void + ensureFirstRun: () => void cancel: () => void } @@ -720,13 +725,13 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { const seenIds = new Set() const workersSources = new Set() let timeoutHandle: NodeJS.Timeout | undefined - let crawlEndCalled = false let cancelled = false function cancel() { cancelled = true } + let crawlEndCalled = false function callOnCrawlEnd() { if (!cancelled && !crawlEndCalled) { crawlEndCalled = true @@ -760,6 +765,18 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { checkIfCrawlEndAfterTimeout() } + let firstRunEnsured = false + function ensureFirstRun() { + if (!firstRunEnsured && seenIds.size === 0) { + setTimeout(() => { + if (seenIds.size === 0) { + callOnCrawlEnd() + } + }, 200) + } + firstRunEnsured = true + } + function checkIfCrawlEndAfterTimeout() { if (cancelled || registeredIds.size > 0) return @@ -777,6 +794,7 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { return { registerWorkersSource, delayDepsOptimizerUntil, + ensureFirstRun, cancel, } } diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index 24b886b6a5fe23..4f0595b77a5c3a 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -90,33 +90,23 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { buildStartCalled = true }, - async resolveId(id, importer, options) { + async resolveId(id) { const depsOptimizer = getDepsOptimizer(config) - if (!depsOptimizer) return - - if (depsOptimizer.isOptimizedDepFile(id)) { + if (depsOptimizer?.isOptimizedDepFile(id)) { return id - } else { - if (options?.custom?.['vite:pre-alias']) { - // Skip registering the id if it is being resolved from the pre-alias plugin - // When a optimized dep is aliased, we need to avoid waiting for it before optimizing - return - } - const resolved = await this.resolve(id, importer, { - ...options, - skipSelf: true, - }) - if (resolved) { - depsOptimizer.delayDepsOptimizerUntil(resolved.id, async () => { - await this.load(resolved) - }) - } } }, async load(id) { const depsOptimizer = getDepsOptimizer(config) - if (!depsOptimizer?.isOptimizedDepFile(id)) { + + if (!depsOptimizer) return + + depsOptimizer.delayDepsOptimizerUntil(id, async () => { + await this.load({ id }) + }) + + if (!depsOptimizer.isOptimizedDepFile(id)) { return } From de0323f2e2d9a1bc7e551986f00667970469b964 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 08:26:01 +0200 Subject: [PATCH 04/12] refactor: spawn markIdAsDone, avoid this.load during build --- packages/vite/src/node/optimizer/index.ts | 3 ++- packages/vite/src/node/optimizer/optimizer.ts | 20 +++++++++++-------- .../vite/src/node/plugins/optimizedDeps.ts | 8 +++++--- packages/vite/src/node/plugins/preAlias.ts | 1 - .../vite/src/node/server/transformRequest.ts | 8 ++++++-- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 1e84bdea805058..2aef372a26c2c9 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -57,7 +57,8 @@ export interface DepsOptimizer { isOptimizedDepFile: (id: string) => boolean isOptimizedDepUrl: (url: string) => boolean getOptimizedDepId: (depInfo: OptimizedDepInfo) => string - delayDepsOptimizerUntil: (id: string, done: () => Promise) => void + delayDepsOptimizerUntil: (id: string) => void + markIdAsDone: (id: string) => void registerWorkersSource: (id: string) => void resetRegisteredIds: () => void diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index fb26715659a769..7b8fd13a112a52 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -116,6 +116,7 @@ async function createDepsOptimizer( isBuild ? depInfo.file : `${depInfo.file}?v=${depInfo.browserHash}`, registerWorkersSource, delayDepsOptimizerUntil, + markIdAsDone, resetRegisteredIds, close, options: getDepOptimizationConfig(config, ssr), @@ -700,22 +701,26 @@ async function createDepsOptimizer( function registerWorkersSource(id: string) { crawlEndFinder?.registerWorkersSource(id) } - function delayDepsOptimizerUntil(id: string, done: () => Promise) { + function delayDepsOptimizerUntil(id: string) { if (crawlEndFinder) { if (depsOptimizer.isOptimizedDepFile(id)) { crawlEndFinder.ensureFirstRun() } else { - crawlEndFinder.delayDepsOptimizerUntil(id, done) + crawlEndFinder.delayDepsOptimizerUntil(id) } } } + function markIdAsDone(id: string) { + crawlEndFinder?.markIdAsDone(id) + } } const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { registerWorkersSource: (id: string) => void - delayDepsOptimizerUntil: (id: string, done: () => Promise) => void + delayDepsOptimizerUntil: (id: string) => void + markIdAsDone: (id: string) => void ensureFirstRun: () => void cancel: () => void } @@ -749,14 +754,11 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { checkIfCrawlEndAfterTimeout() } - function delayDepsOptimizerUntil(id: string, done: () => Promise): void { + function delayDepsOptimizerUntil(id: string): void { if (!seenIds.has(id)) { seenIds.add(id) if (!workersSources.has(id)) { registeredIds.add(id) - done() - .catch(() => {}) - .finally(() => markIdAsDone(id)) } } } @@ -794,6 +796,7 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { return { registerWorkersSource, delayDepsOptimizerUntil, + markIdAsDone, ensureFirstRun, cancel, } @@ -820,7 +823,8 @@ async function createDevSsrDepsOptimizer( // the optimizer blocks the server start run: () => {}, registerWorkersSource: (id: string) => {}, - delayDepsOptimizerUntil: (id: string, done: () => Promise) => {}, + delayDepsOptimizerUntil: (id: string) => {}, + markIdAsDone: (id: string) => {}, resetRegisteredIds: () => {}, close: async () => {}, diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index 4f0595b77a5c3a..264b96c8c23a34 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -102,9 +102,7 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { if (!depsOptimizer) return - depsOptimizer.delayDepsOptimizerUntil(id, async () => { - await this.load({ id }) - }) + depsOptimizer.delayDepsOptimizerUntil(id) if (!depsOptimizer.isOptimizedDepFile(id)) { return @@ -128,6 +126,10 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { // we are sure that the file has been properly save to disk return fsp.readFile(file, 'utf-8') }, + + moduleParsed(info) { + getDepsOptimizer(config)?.markIdAsDone(info.id) + }, } } diff --git a/packages/vite/src/node/plugins/preAlias.ts b/packages/vite/src/node/plugins/preAlias.ts index 7aa33ef2fdc7c2..e3bcc5bf3a29dd 100644 --- a/packages/vite/src/node/plugins/preAlias.ts +++ b/packages/vite/src/node/plugins/preAlias.ts @@ -52,7 +52,6 @@ export function preAliasPlugin(config: ResolvedConfig): Plugin { const resolved = await this.resolve(id, importer, { ...options, - custom: { ...options.custom, 'vite:pre-alias': true }, skipSelf: true, }) if (resolved && !depsOptimizer.isOptimizedDepFile(resolved.id)) { diff --git a/packages/vite/src/node/server/transformRequest.ts b/packages/vite/src/node/server/transformRequest.ts index 2b74b25b526f06..08e3272e5c5d33 100644 --- a/packages/vite/src/node/server/transformRequest.ts +++ b/packages/vite/src/node/server/transformRequest.ts @@ -147,10 +147,14 @@ async function doTransform( (await pluginContainer.resolveId(url, undefined, { ssr }))?.id ?? url - const result = loadAndTransform(id, url, server, options, timestamp) + const depsOptimizer = getDepsOptimizer(config, ssr) + depsOptimizer?.delayDepsOptimizerUntil(id) - getDepsOptimizer(config, ssr)?.delayDepsOptimizerUntil(id, () => result) + const result = loadAndTransform(id, url, server, options, timestamp) + if (depsOptimizer) { + result.catch(() => {}).finally(() => depsOptimizer.markIdAsDone(id)) + } return result } From 1294327d116299a83a8959714256395001566b57 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 08:46:49 +0200 Subject: [PATCH 05/12] Revert "refactor: spawn markIdAsDone, avoid this.load during build" This reverts commit de0323f2e2d9a1bc7e551986f00667970469b964. --- packages/vite/src/node/optimizer/index.ts | 3 +-- packages/vite/src/node/optimizer/optimizer.ts | 20 ++++++++----------- .../vite/src/node/plugins/optimizedDeps.ts | 8 +++----- packages/vite/src/node/plugins/preAlias.ts | 1 + .../vite/src/node/server/transformRequest.ts | 8 ++------ 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 2aef372a26c2c9..1e84bdea805058 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -57,8 +57,7 @@ export interface DepsOptimizer { isOptimizedDepFile: (id: string) => boolean isOptimizedDepUrl: (url: string) => boolean getOptimizedDepId: (depInfo: OptimizedDepInfo) => string - delayDepsOptimizerUntil: (id: string) => void - markIdAsDone: (id: string) => void + delayDepsOptimizerUntil: (id: string, done: () => Promise) => void registerWorkersSource: (id: string) => void resetRegisteredIds: () => void diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index 7b8fd13a112a52..fb26715659a769 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -116,7 +116,6 @@ async function createDepsOptimizer( isBuild ? depInfo.file : `${depInfo.file}?v=${depInfo.browserHash}`, registerWorkersSource, delayDepsOptimizerUntil, - markIdAsDone, resetRegisteredIds, close, options: getDepOptimizationConfig(config, ssr), @@ -701,26 +700,22 @@ async function createDepsOptimizer( function registerWorkersSource(id: string) { crawlEndFinder?.registerWorkersSource(id) } - function delayDepsOptimizerUntil(id: string) { + function delayDepsOptimizerUntil(id: string, done: () => Promise) { if (crawlEndFinder) { if (depsOptimizer.isOptimizedDepFile(id)) { crawlEndFinder.ensureFirstRun() } else { - crawlEndFinder.delayDepsOptimizerUntil(id) + crawlEndFinder.delayDepsOptimizerUntil(id, done) } } } - function markIdAsDone(id: string) { - crawlEndFinder?.markIdAsDone(id) - } } const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { registerWorkersSource: (id: string) => void - delayDepsOptimizerUntil: (id: string) => void - markIdAsDone: (id: string) => void + delayDepsOptimizerUntil: (id: string, done: () => Promise) => void ensureFirstRun: () => void cancel: () => void } @@ -754,11 +749,14 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { checkIfCrawlEndAfterTimeout() } - function delayDepsOptimizerUntil(id: string): void { + function delayDepsOptimizerUntil(id: string, done: () => Promise): void { if (!seenIds.has(id)) { seenIds.add(id) if (!workersSources.has(id)) { registeredIds.add(id) + done() + .catch(() => {}) + .finally(() => markIdAsDone(id)) } } } @@ -796,7 +794,6 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { return { registerWorkersSource, delayDepsOptimizerUntil, - markIdAsDone, ensureFirstRun, cancel, } @@ -823,8 +820,7 @@ async function createDevSsrDepsOptimizer( // the optimizer blocks the server start run: () => {}, registerWorkersSource: (id: string) => {}, - delayDepsOptimizerUntil: (id: string) => {}, - markIdAsDone: (id: string) => {}, + delayDepsOptimizerUntil: (id: string, done: () => Promise) => {}, resetRegisteredIds: () => {}, close: async () => {}, diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index 264b96c8c23a34..4f0595b77a5c3a 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -102,7 +102,9 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { if (!depsOptimizer) return - depsOptimizer.delayDepsOptimizerUntil(id) + depsOptimizer.delayDepsOptimizerUntil(id, async () => { + await this.load({ id }) + }) if (!depsOptimizer.isOptimizedDepFile(id)) { return @@ -126,10 +128,6 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { // we are sure that the file has been properly save to disk return fsp.readFile(file, 'utf-8') }, - - moduleParsed(info) { - getDepsOptimizer(config)?.markIdAsDone(info.id) - }, } } diff --git a/packages/vite/src/node/plugins/preAlias.ts b/packages/vite/src/node/plugins/preAlias.ts index e3bcc5bf3a29dd..7aa33ef2fdc7c2 100644 --- a/packages/vite/src/node/plugins/preAlias.ts +++ b/packages/vite/src/node/plugins/preAlias.ts @@ -52,6 +52,7 @@ export function preAliasPlugin(config: ResolvedConfig): Plugin { const resolved = await this.resolve(id, importer, { ...options, + custom: { ...options.custom, 'vite:pre-alias': true }, skipSelf: true, }) if (resolved && !depsOptimizer.isOptimizedDepFile(resolved.id)) { diff --git a/packages/vite/src/node/server/transformRequest.ts b/packages/vite/src/node/server/transformRequest.ts index 08e3272e5c5d33..2b74b25b526f06 100644 --- a/packages/vite/src/node/server/transformRequest.ts +++ b/packages/vite/src/node/server/transformRequest.ts @@ -147,14 +147,10 @@ async function doTransform( (await pluginContainer.resolveId(url, undefined, { ssr }))?.id ?? url - const depsOptimizer = getDepsOptimizer(config, ssr) - depsOptimizer?.delayDepsOptimizerUntil(id) - const result = loadAndTransform(id, url, server, options, timestamp) - if (depsOptimizer) { - result.catch(() => {}).finally(() => depsOptimizer.markIdAsDone(id)) - } + getDepsOptimizer(config, ssr)?.delayDepsOptimizerUntil(id, () => result) + return result } From d95649de5bd1ccbb3d4470d849955cbfbd13a6f6 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 08:51:00 +0200 Subject: [PATCH 06/12] Revert "refactor: simplify id registration during build" This reverts commit 969ff9f32f620d6d18bf246b9e517035fb06928e. --- packages/vite/src/node/optimizer/optimizer.ts | 24 ++------------- .../vite/src/node/plugins/optimizedDeps.ts | 30 ++++++++++++------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index fb26715659a769..c7c0a0f5d766b6 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -701,12 +701,8 @@ async function createDepsOptimizer( crawlEndFinder?.registerWorkersSource(id) } function delayDepsOptimizerUntil(id: string, done: () => Promise) { - if (crawlEndFinder) { - if (depsOptimizer.isOptimizedDepFile(id)) { - crawlEndFinder.ensureFirstRun() - } else { - crawlEndFinder.delayDepsOptimizerUntil(id, done) - } + if (crawlEndFinder && !depsOptimizer.isOptimizedDepFile(id)) { + crawlEndFinder.delayDepsOptimizerUntil(id, done) } } } @@ -716,7 +712,6 @@ const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { registerWorkersSource: (id: string) => void delayDepsOptimizerUntil: (id: string, done: () => Promise) => void - ensureFirstRun: () => void cancel: () => void } @@ -725,13 +720,13 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { const seenIds = new Set() const workersSources = new Set() let timeoutHandle: NodeJS.Timeout | undefined + let crawlEndCalled = false let cancelled = false function cancel() { cancelled = true } - let crawlEndCalled = false function callOnCrawlEnd() { if (!cancelled && !crawlEndCalled) { crawlEndCalled = true @@ -765,18 +760,6 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { checkIfCrawlEndAfterTimeout() } - let firstRunEnsured = false - function ensureFirstRun() { - if (!firstRunEnsured && seenIds.size === 0) { - setTimeout(() => { - if (seenIds.size === 0) { - callOnCrawlEnd() - } - }, 200) - } - firstRunEnsured = true - } - function checkIfCrawlEndAfterTimeout() { if (cancelled || registeredIds.size > 0) return @@ -794,7 +777,6 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { return { registerWorkersSource, delayDepsOptimizerUntil, - ensureFirstRun, cancel, } } diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index 4f0595b77a5c3a..24b886b6a5fe23 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -90,23 +90,33 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { buildStartCalled = true }, - async resolveId(id) { + async resolveId(id, importer, options) { const depsOptimizer = getDepsOptimizer(config) - if (depsOptimizer?.isOptimizedDepFile(id)) { + if (!depsOptimizer) return + + if (depsOptimizer.isOptimizedDepFile(id)) { return id + } else { + if (options?.custom?.['vite:pre-alias']) { + // Skip registering the id if it is being resolved from the pre-alias plugin + // When a optimized dep is aliased, we need to avoid waiting for it before optimizing + return + } + const resolved = await this.resolve(id, importer, { + ...options, + skipSelf: true, + }) + if (resolved) { + depsOptimizer.delayDepsOptimizerUntil(resolved.id, async () => { + await this.load(resolved) + }) + } } }, async load(id) { const depsOptimizer = getDepsOptimizer(config) - - if (!depsOptimizer) return - - depsOptimizer.delayDepsOptimizerUntil(id, async () => { - await this.load({ id }) - }) - - if (!depsOptimizer.isOptimizedDepFile(id)) { + if (!depsOptimizer?.isOptimizedDepFile(id)) { return } From af366a23827fcd399d3378aa83406f79c9e28b64 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 09:03:36 +0200 Subject: [PATCH 07/12] fix: add back ensureFirstRun guard --- packages/vite/src/node/optimizer/index.ts | 1 + packages/vite/src/node/optimizer/optimizer.ts | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 1e84bdea805058..91727064d7b89a 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -60,6 +60,7 @@ export interface DepsOptimizer { delayDepsOptimizerUntil: (id: string, done: () => Promise) => void registerWorkersSource: (id: string) => void resetRegisteredIds: () => void + ensureFirstRun: () => void close: () => Promise diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index c7c0a0f5d766b6..0767233bdc7a1f 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -117,6 +117,7 @@ async function createDepsOptimizer( registerWorkersSource, delayDepsOptimizerUntil, resetRegisteredIds, + ensureFirstRun, close, options: getDepOptimizationConfig(config, ssr), } @@ -705,6 +706,9 @@ async function createDepsOptimizer( crawlEndFinder.delayDepsOptimizerUntil(id, done) } } + function ensureFirstRun() { + crawlEndFinder?.ensureFirstRun() + } } const callCrawlEndIfIdleAfterMs = 50 @@ -712,6 +716,7 @@ const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { registerWorkersSource: (id: string) => void delayDepsOptimizerUntil: (id: string, done: () => Promise) => void + ensureFirstRun: () => void cancel: () => void } @@ -720,13 +725,13 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { const seenIds = new Set() const workersSources = new Set() let timeoutHandle: NodeJS.Timeout | undefined - let crawlEndCalled = false let cancelled = false function cancel() { cancelled = true } + let crawlEndCalled = false function callOnCrawlEnd() { if (!cancelled && !crawlEndCalled) { crawlEndCalled = true @@ -760,6 +765,18 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { checkIfCrawlEndAfterTimeout() } + let firstRunEnsured = false + function ensureFirstRun() { + if (!firstRunEnsured && seenIds.size === 0) { + setTimeout(() => { + if (seenIds.size === 0) { + callOnCrawlEnd() + } + }, 200) + } + firstRunEnsured = true + } + function checkIfCrawlEndAfterTimeout() { if (cancelled || registeredIds.size > 0) return @@ -777,6 +794,7 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { return { registerWorkersSource, delayDepsOptimizerUntil, + ensureFirstRun, cancel, } } @@ -804,6 +822,7 @@ async function createDevSsrDepsOptimizer( registerWorkersSource: (id: string) => {}, delayDepsOptimizerUntil: (id: string, done: () => Promise) => {}, resetRegisteredIds: () => {}, + ensureFirstRun: () => {}, close: async () => {}, options: config.ssr.optimizeDeps, From b79a1d4d37a59ebe67aabf55c29f88586dfd79f6 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 09:14:01 +0200 Subject: [PATCH 08/12] chore: reduce diff --- packages/vite/src/node/optimizer/optimizer.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index 0767233bdc7a1f..4a5c08df852b11 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -739,6 +739,21 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { } } + // If all the inputs are dependencies, we aren't going to get any + // delayDepsOptimizerUntil(id) calls. We need to guard against this + // by forcing a rerun if no deps have been registered + let firstRunEnsured = false + function ensureFirstRun() { + if (!firstRunEnsured && seenIds.size === 0) { + setTimeout(() => { + if (seenIds.size === 0) { + callOnCrawlEnd() + } + }, 200) + } + firstRunEnsured = true + } + function registerWorkersSource(id: string): void { workersSources.add(id) @@ -765,18 +780,6 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { checkIfCrawlEndAfterTimeout() } - let firstRunEnsured = false - function ensureFirstRun() { - if (!firstRunEnsured && seenIds.size === 0) { - setTimeout(() => { - if (seenIds.size === 0) { - callOnCrawlEnd() - } - }, 200) - } - firstRunEnsured = true - } - function checkIfCrawlEndAfterTimeout() { if (cancelled || registeredIds.size > 0) return From 9cac1cec5bdca1056e6382b79b8570c2445389da Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 09:15:01 +0200 Subject: [PATCH 09/12] chore: reduce diff --- packages/vite/src/node/optimizer/optimizer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/optimizer/optimizer.ts b/packages/vite/src/node/optimizer/optimizer.ts index 4a5c08df852b11..f82dbe0f3bcf85 100644 --- a/packages/vite/src/node/optimizer/optimizer.ts +++ b/packages/vite/src/node/optimizer/optimizer.ts @@ -714,9 +714,9 @@ async function createDepsOptimizer( const callCrawlEndIfIdleAfterMs = 50 interface CrawlEndFinder { + ensureFirstRun: () => void registerWorkersSource: (id: string) => void delayDepsOptimizerUntil: (id: string, done: () => Promise) => void - ensureFirstRun: () => void cancel: () => void } @@ -795,9 +795,9 @@ function setupOnCrawlEnd(onCrawlEnd: () => void): CrawlEndFinder { } return { + ensureFirstRun, registerWorkersSource, delayDepsOptimizerUntil, - ensureFirstRun, cancel, } } From 95c25a2e2ef50b8a59a10d1c005ac8577a221118 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 09:17:17 +0200 Subject: [PATCH 10/12] chore: add ensureFirstRun guard back --- packages/vite/src/node/plugins/optimizedDeps.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index 24b886b6a5fe23..a91c961fddba6c 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -120,6 +120,8 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { return } + depsOptimizer?.ensureFirstRun() + const file = cleanUrl(id) // Search in both the currently optimized and newly discovered deps // If all the inputs are dependencies, we aren't going to get any From 1df535093eff48ca3ca1a8191ec2ddf0634f820d Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 11:53:50 +0200 Subject: [PATCH 11/12] perf: avoid double-resolving ids during build --- packages/vite/src/node/plugins/optimizedDeps.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vite/src/node/plugins/optimizedDeps.ts b/packages/vite/src/node/plugins/optimizedDeps.ts index a91c961fddba6c..f832e5da395c6c 100644 --- a/packages/vite/src/node/plugins/optimizedDeps.ts +++ b/packages/vite/src/node/plugins/optimizedDeps.ts @@ -110,6 +110,7 @@ export function optimizedDepsBuildPlugin(config: ResolvedConfig): Plugin { depsOptimizer.delayDepsOptimizerUntil(resolved.id, async () => { await this.load(resolved) }) + return resolved } } }, From f258d38c483328a9b41ced7a9d848df1425c98e1 Mon Sep 17 00:00:00 2001 From: patak Date: Sat, 15 Apr 2023 20:58:27 +0200 Subject: [PATCH 12/12] test: check no missing deps in build time --- playground/optimize-deps/__tests__/optimize-deps.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts index f023d1c22ded8d..73e7593a31e288 100644 --- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts +++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts @@ -6,6 +6,7 @@ import { isBuild, isServe, page, + serverLogs, viteTestUrl, } from '~utils' @@ -214,3 +215,10 @@ test('pre bundle css require', async () => { expect(await getColor('.css-require')).toBe('red') }) + +test.runIf(isBuild)('no missing deps during build', async () => { + serverLogs.forEach((log) => { + // no warning from esbuild css minifier + expect(log).not.toMatch('Missing dependency found after crawling ended') + }) +})