From abfa804acd1a527bd4ebab45f1241fb4adcd826c Mon Sep 17 00:00:00 2001 From: Jonathan Romano Date: Thu, 23 Feb 2023 02:21:24 -0500 Subject: [PATCH] feat: support rollup plugin this.load in plugin container context (#11469) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 翠 / green --- .../server/__tests__/pluginContainer.spec.ts | 38 +++++++++++++++++++ .../vite/src/node/server/pluginContainer.ts | 30 ++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts b/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts index 642b1f5608ba3a..089a45497a593e 100644 --- a/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts +++ b/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts @@ -147,6 +147,44 @@ describe('plugin container', () => { expect.assertions(2) }) }) + + describe('load', () => { + beforeEach(() => { + moduleGraph = new ModuleGraph((id) => resolveId(id)) + }) + + it('can resolve a secondary module', async () => { + const entryUrl = '/x.js' + + const plugin: Plugin = { + name: 'p1', + resolveId(id) { + return id + }, + load(id) { + if (id === entryUrl) return { code: '1', meta: { x: 1 } } + else return { code: '2', meta: { x: 2 } } + }, + async transform(code, id) { + if (id === entryUrl) + return { + code: `${ + (await this.load({ id: '/secondary.js' })).meta.x || undefined + }`, + } + return { code } + }, + } + + const container = await getPluginContainer({ + plugins: [plugin], + }) + await moduleGraph.ensureEntryFromUrl(entryUrl, false) + const loadResult: any = await container.load(entryUrl) + const result: any = await container.transform(loadResult.code, entryUrl) + expect(result.code).equals('2') + }) + }) }) async function getPluginContainer( diff --git a/packages/vite/src/node/server/pluginContainer.ts b/packages/vite/src/node/server/pluginContainer.ts index d2441cccdb6e77..2aa340234c9788 100644 --- a/packages/vite/src/node/server/pluginContainer.ts +++ b/packages/vite/src/node/server/pluginContainer.ts @@ -42,9 +42,11 @@ import type { LoadResult, MinimalPluginContext, ModuleInfo, + ModuleOptions, NormalizedInputOptions, OutputOptions, ParallelPluginHooks, + PartialNull, PartialResolvedId, ResolvedId, RollupError, @@ -126,8 +128,6 @@ export interface PluginContainer { type PluginContext = Omit< RollupPluginContext, - // not supported - | 'load' // not documented | 'cache' // deprecated @@ -221,6 +221,10 @@ export async function createPluginContainer( if (key in info) { return info[key] } + // Don't throw an error when returning from an async function + if (key === 'then') { + return undefined + } throw Error( `[vite] The "${key}" property of ModuleInfo is not supported.`, ) @@ -306,6 +310,28 @@ export async function createPluginContainer( return out as ResolvedId | null } + async load( + options: { + id: string + resolveDependencies?: boolean + } & Partial>, + ): Promise { + // We may not have added this to our module graph yet, so ensure it exists + await moduleGraph?.ensureEntryFromUrl(options.id) + // Not all options passed to this function make sense in the context of loading individual files, + // but we can at least update the module info properties we support + updateModuleInfo(options.id, options) + + await container.load(options.id, { ssr: this.ssr }) + const moduleInfo = this.getModuleInfo(options.id) + // This shouldn't happen due to calling ensureEntryFromUrl, but 1) our types can't ensure that + // and 2) moduleGraph may not have been provided (though in the situations where that happens, + // we should never have plugins calling this.load) + if (!moduleInfo) + throw Error(`Failed to load module with id ${options.id}`) + return moduleInfo + } + getModuleInfo(id: string) { return getModuleInfo(id) }