diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 3bf5984664b0d6..afc51467c7397e 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -8,6 +8,7 @@ import type { LoggingFunction, ModuleFormat, OutputOptions, + RolldownPlugin, RollupBuild, RollupError, RollupLog, @@ -16,6 +17,10 @@ import type { // RollupWatcher, // WatcherOptions, } from 'rolldown' +import { + loadFallbackPlugin as nativeLoadFallbackPlugin, + manifestPlugin as nativeManifestPlugin, +} from 'rolldown/experimental' import type { RollupCommonJSOptions } from 'dep-types/commonjs' import type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' import type { TransformOptions } from 'esbuild' @@ -463,13 +468,15 @@ export function resolveBuildEnvironmentOptions( export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{ pre: Plugin[] - post: Plugin[] + post: RolldownPlugin[] }> { + const enableNativePlugin = config.experimental.enableNativePlugin // TODO: support commonjs options? return { pre: [ completeSystemWrapPlugin(), - dataURIPlugin(), + // rolldown has builtin support datauri, use a switch to control it for convenience + ...(enableNativePlugin ? [] : [dataURIPlugin()]), /** * environment.config.build.rollupOptions.plugins isn't supported * when builder.sharedConfigBuild or builder.sharedPlugins is enabled. @@ -486,13 +493,28 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{ ...(config.isWorker ? [webWorkerPostPlugin()] : []), ], post: [ - buildImportAnalysisPlugin(config), + ...buildImportAnalysisPlugin(config), ...(config.esbuild !== false ? [buildEsbuildPlugin(config)] : []), terserPlugin(config), ...(!config.isWorker - ? [manifestPlugin(), ssrManifestPlugin(), buildReporterPlugin(config)] + ? [ + config.build.manifest && enableNativePlugin + ? // TODO: make this environment-specific + nativeManifestPlugin({ + root: config.root, + outPath: + config.build.manifest === true + ? '.vite/manifest.json' + : config.build.manifest, + }) + : manifestPlugin(), + ssrManifestPlugin(), + buildReporterPlugin(config), + ] : []), - buildLoadFallbackPlugin(), + enableNativePlugin + ? nativeLoadFallbackPlugin() + : buildLoadFallbackPlugin(), ], } } diff --git a/packages/vite/src/node/plugins/importAnalysisBuild.ts b/packages/vite/src/node/plugins/importAnalysisBuild.ts index 669355d90d1c2c..bb24f9610194dd 100644 --- a/packages/vite/src/node/plugins/importAnalysisBuild.ts +++ b/packages/vite/src/node/plugins/importAnalysisBuild.ts @@ -8,6 +8,7 @@ import { init, parse as parseImports } from 'es-module-lexer' import type { SourceMap } from 'rolldown' import type { RawSourceMap } from '@ampproject/remapping' import convertSourceMap from 'convert-source-map' +import { buildImportAnalysisPlugin as nativeBuildImportAnalysisPlugin } from 'rolldown/experimental' import { combineSourcemaps, generateCodeFrame, @@ -170,16 +171,43 @@ function preload( /** * Build only. During serve this is performed as part of ./importAnalysis. */ -export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { +export function buildImportAnalysisPlugin(config: ResolvedConfig): [Plugin] { const getInsertPreload = (environment: Environment) => environment.config.consumer === 'client' && !config.isWorker && !config.build.lib + const enableNativePlugin = config.experimental.enableNativePlugin const renderBuiltUrl = config.experimental.renderBuiltUrl const isRelativeBase = config.base === './' || config.base === '' - return { + // TODO: make this environment-specific + const { modulePreload } = config.build // this.environment.config.build + + const scriptRel = + modulePreload && modulePreload.polyfill + ? `'modulepreload'` + : `/* @__PURE__ */ (${detectScriptRel.toString()})()` + + // There are two different cases for the preload list format in __vitePreload + // + // __vitePreload(() => import(asyncChunk), [ ...deps... ]) + // + // This is maintained to keep backwards compatibility as some users developed plugins + // using regex over this list to workaround the fact that module preload wasn't + // configurable. + const assetsURL = + renderBuiltUrl || isRelativeBase + ? // If `experimental.renderBuiltUrl` is used, the dependencies might be relative to the current chunk. + // If relative base is used, the dependencies are relative to the current chunk. + // The importerUrl is passed as third parameter to __vitePreload in this case + `function(dep, importerUrl) { return new URL(dep, importerUrl).href }` + : // If the base isn't relative, then the deps are relative to the projects `outDir` and the base + // is appended inside __vitePreload too. + `function(dep) { return ${JSON.stringify(config.base)}+dep }` + const preloadCode = `const scriptRel = ${scriptRel};const assetsURL = ${assetsURL};const seen = {};export const ${preloadMethod} = ${preload.toString()}` + + const jsPlugin = { name: 'vite:build-import-analysis', resolveId(id) { if (id === preloadHelperId) { @@ -189,30 +217,6 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { load(id) { if (id === preloadHelperId) { - const { modulePreload } = this.environment.config.build - - const scriptRel = - modulePreload && modulePreload.polyfill - ? `'modulepreload'` - : `/* @__PURE__ */ (${detectScriptRel.toString()})()` - - // There are two different cases for the preload list format in __vitePreload - // - // __vitePreload(() => import(asyncChunk), [ ...deps... ]) - // - // This is maintained to keep backwards compatibility as some users developed plugins - // using regex over this list to workaround the fact that module preload wasn't - // configurable. - const assetsURL = - renderBuiltUrl || isRelativeBase - ? // If `experimental.renderBuiltUrl` is used, the dependencies might be relative to the current chunk. - // If relative base is used, the dependencies are relative to the current chunk. - // The importerUrl is passed as third parameter to __vitePreload in this case - `function(dep, importerUrl) { return new URL(dep, importerUrl).href }` - : // If the base isn't relative, then the deps are relative to the projects `outDir` and the base - // is appended inside __vitePreload too. - `function(dep) { return ${JSON.stringify(config.base)}+dep }` - const preloadCode = `const scriptRel = ${scriptRel};const assetsURL = ${assetsURL};const seen = {};export const ${preloadMethod} = ${preload.toString()}` return { code: preloadCode, moduleSideEffects: false } } }, @@ -718,5 +722,24 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { } } }, + } as Plugin + if (enableNativePlugin) { + delete jsPlugin.transform + delete jsPlugin.resolveId + delete jsPlugin.load } + return [ + jsPlugin, + enableNativePlugin + ? nativeBuildImportAnalysisPlugin({ + preloadCode: preloadCode, + // @ts-expect-error make this environment-specific + insertPreload: getInsertPreload({ config: { consumer: 'client' } }), + /// this field looks redundant, put a dummy value for now + optimizeModulePreloadRelativePaths: false, + renderBuiltUrl: Boolean(renderBuiltUrl), + isRelativeBase: isRelativeBase, + }) + : null, + ].filter(Boolean) as [Plugin] }