From b178c90c7d175ea31f8b67dccad3918f820357a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Fri, 3 Jan 2025 04:39:25 +0900 Subject: [PATCH] fix: skip the plugin if it has been called before with the same id and importer (#19016) --- .../server/__tests__/pluginContainer.spec.ts | 57 +++++++++++++++++++ .../vite/src/node/server/pluginContainer.ts | 32 ++++++++--- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts b/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts index f0934219797556..acfcb1a29f578e 100644 --- a/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts +++ b/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts @@ -258,6 +258,63 @@ describe('plugin container', () => { const result = await environment.pluginContainer.resolveId('foo') expect(result).toStrictEqual({ id: 'success' }) }) + + it('should skip the plugin if it has been called before with the same id and importer (1)', async () => { + const p1: Plugin = { + name: 'p1', + async resolveId(id, importer) { + return ( + (await this.resolve(id.replace(/\/modified$/, ''), importer, { + skipSelf: true, + })) ?? 'success' + ) + }, + } + const p2: Plugin = { + name: 'p2', + async resolveId(id, importer) { + return await this.resolve(id + '/modified', importer, { + skipSelf: true, + }) + }, + } + const environment = await getDevEnvironment({ plugins: [p1, p2] }) + const result = await environment.pluginContainer.resolveId('foo') + expect(result).toStrictEqual({ id: 'success' }) + }) + + it('should skip the plugin if it has been called before with the same id and importer (2)', async () => { + const p1: Plugin = { + name: 'p1', + async resolveId(id, importer) { + return ( + (await this.resolve(id.replace(/\/modified$/, ''), importer, { + skipSelf: true, + })) ?? 'failure1' + ) + }, + } + const p2: Plugin = { + name: 'p2', + async resolveId(id, importer) { + return await this.resolve(id + '/modified', importer, { + skipSelf: true, + }) + }, + } + const p3: Plugin = { + name: 'p3', + resolveId(id) { + if (id.endsWith('/modified')) { + return 'success' + } + return 'failure2' + }, + } + const environment = await getDevEnvironment({ plugins: [p1, p2, p3] }) + const result = await environment.pluginContainer.resolveId('foo') + expect(result).toStrictEqual({ id: 'success' }) + }) }) }) }) diff --git a/packages/vite/src/node/server/pluginContainer.ts b/packages/vite/src/node/server/pluginContainer.ts index 616a16a9885c74..c77e105fa2a969 100644 --- a/packages/vite/src/node/server/pluginContainer.ts +++ b/packages/vite/src/node/server/pluginContainer.ts @@ -148,6 +148,7 @@ export type SkipInformation = { id: string importer: string | undefined plugin: Plugin + called?: boolean } class EnvironmentPluginContainer { @@ -364,7 +365,7 @@ class EnvironmentPluginContainer { const mergedSkip = new Set(skip) for (const call of skipCalls ?? []) { - if (call.id === rawId && call.importer === importer) { + if (call.called || (call.id === rawId && call.importer === importer)) { mergedSkip.add(call.plugin) } } @@ -576,13 +577,28 @@ class PluginContext implements Omit { skipSelf?: boolean }, ) { - const skipCalls = - options?.skipSelf === false - ? this._resolveSkipCalls - : [ - ...(this._resolveSkipCalls || []), - { id, importer, plugin: this._plugin }, - ] + let skipCalls: readonly SkipInformation[] | undefined + if (options?.skipSelf === false) { + skipCalls = this._resolveSkipCalls + } else if (this._resolveSkipCalls) { + const skipCallsTemp = [...this._resolveSkipCalls] + const sameCallIndex = this._resolveSkipCalls.findIndex( + (c) => + c.id === id && c.importer === importer && c.plugin === this._plugin, + ) + if (sameCallIndex !== -1) { + skipCallsTemp[sameCallIndex] = { + ...skipCallsTemp[sameCallIndex], + called: true, + } + } else { + skipCallsTemp.push({ id, importer, plugin: this._plugin }) + } + skipCalls = skipCallsTemp + } else { + skipCalls = [{ id, importer, plugin: this._plugin }] + } + let out = await this._container.resolveId(id, importer, { attributes: options?.attributes, custom: options?.custom,