From 727e891961d011a5efe3aa1c84ee4cc15383391c Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:08:21 +0900 Subject: [PATCH] feat: environment aware native plugins --- packages/vite/src/node/build.ts | 27 ++++--- packages/vite/src/node/plugin.ts | 34 ++++++++ .../src/node/plugins/importAnalysisBuild.ts | 77 ++++++++++++------- packages/vite/src/node/plugins/index.ts | 23 +++++- 4 files changed, 121 insertions(+), 40 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index e413f6fbb2a12a..620a5489ee5d71 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -53,7 +53,10 @@ import { partialEncodeURIPath, requireResolveFromRootWithFallback, } from './utils' -import { resolveEnvironmentPlugins } from './plugin' +import { + createBuiltinPluginWithEnvironmentSupport, + resolveEnvironmentPlugins, +} from './plugin' import { manifestPlugin } from './plugins/manifest' import type { Logger } from './logger' import { dataURIPlugin } from './plugins/dataUri' @@ -499,14 +502,20 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{ ...(!config.isWorker ? [ config.build.manifest && enableNativePlugin - ? // TODO: make this environment-specific - nativeManifestPlugin({ - root: config.root, - outPath: - config.build.manifest === true - ? '.vite/manifest.json' - : config.build.manifest, - }) + ? createBuiltinPluginWithEnvironmentSupport( + 'native:manifest', + (environment) => { + if (!environment.config.build.manifest) return false + + return nativeManifestPlugin({ + root: environment.config.root, + outPath: + environment.config.build.manifest === true + ? '.vite/manifest.json' + : environment.config.build.manifest, + }) + }, + ) : manifestPlugin(), ssrManifestPlugin(), ...(enableBuildReport ? [buildReporterPlugin(config)] : []), diff --git a/packages/vite/src/node/plugin.ts b/packages/vite/src/node/plugin.ts index eac11e0f9ff2e7..28b5799e54eef1 100644 --- a/packages/vite/src/node/plugin.ts +++ b/packages/vite/src/node/plugin.ts @@ -343,4 +343,38 @@ export function resolveEnvironmentPlugins(environment: Environment): Plugin[] { (plugin) => !plugin.applyToEnvironment || plugin.applyToEnvironment(environment), ) + .map((plugin) => + plugin.api && 'getBuiltinPlugin' in plugin.api + ? plugin.api.getBuiltinPlugin?.(environment) + : plugin, + ) +} + +export function createBuiltinPluginWithEnvironmentSupport( + name: string, + plugin: (environment: Environment) => BP | false, +): Plugin<{ + getBuiltinPlugin: (environment: Environment) => BP | undefined +}> { + const pluginForEnvironment = new WeakMap() + + return { + name, + applyToEnvironment(environment) { + if (pluginForEnvironment.has(environment)) { + return true + } + + const pluginForEnv = plugin(environment) + if (pluginForEnv) { + pluginForEnvironment.set(environment, pluginForEnv) + } + return !!pluginForEnv + }, + api: { + getBuiltinPlugin(environment) { + return pluginForEnvironment.get(environment) + }, + }, + } } diff --git a/packages/vite/src/node/plugins/importAnalysisBuild.ts b/packages/vite/src/node/plugins/importAnalysisBuild.ts index bb24f9610194dd..9892f7fc78e400 100644 --- a/packages/vite/src/node/plugins/importAnalysisBuild.ts +++ b/packages/vite/src/node/plugins/importAnalysisBuild.ts @@ -15,7 +15,10 @@ import { isInNodeModules, numberToPos, } from '../utils' -import type { Plugin } from '../plugin' +import { + type Plugin, + createBuiltinPluginWithEnvironmentSupport, +} from '../plugin' import type { ResolvedConfig } from '../config' import { toOutputFilePathInJS } from '../build' import { genSourceMapUrl } from '../server/sourcemap' @@ -168,21 +171,12 @@ function preload( }) } -/** - * Build only. During serve this is performed as part of ./importAnalysis. - */ -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 === '' - - // TODO: make this environment-specific - const { modulePreload } = config.build // this.environment.config.build +function getPreloadCode( + environment: Environment, + renderBuiltUrlBoolean: boolean, + isRelativeBase: boolean, +) { + const { modulePreload } = environment.config.build const scriptRel = modulePreload && modulePreload.polyfill @@ -197,15 +191,30 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): [Plugin] { // using regex over this list to workaround the fact that module preload wasn't // configurable. const assetsURL = - renderBuiltUrl || isRelativeBase + renderBuiltUrlBoolean || 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 }` + `function(dep) { return ${JSON.stringify(environment.config.base)}+dep }` const preloadCode = `const scriptRel = ${scriptRel};const assetsURL = ${assetsURL};const seen = {};export const ${preloadMethod} = ${preload.toString()}` + return preloadCode +} + +/** + * Build only. During serve this is performed as part of ./importAnalysis. + */ +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 === '' const jsPlugin = { name: 'vite:build-import-analysis', @@ -217,6 +226,11 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): [Plugin] { load(id) { if (id === preloadHelperId) { + const preloadCode = getPreloadCode( + this.environment, + !!renderBuiltUrl, + isRelativeBase, + ) return { code: preloadCode, moduleSideEffects: false } } }, @@ -731,15 +745,24 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): [Plugin] { 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, - }) + ? createBuiltinPluginWithEnvironmentSupport( + 'native:import-analysis-build', + (environment) => { + const preloadCode = getPreloadCode( + environment, + !!renderBuiltUrl, + isRelativeBase, + ) + return nativeBuildImportAnalysisPlugin({ + preloadCode, + insertPreload: getInsertPreload(environment), + // this field looks redundant, put a dummy value for now + optimizeModulePreloadRelativePaths: false, + renderBuiltUrl: !!renderBuiltUrl, + isRelativeBase, + }) + }, + ) : null, ].filter(Boolean) as [Plugin] } diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts index acaf6b5d8b8ef4..527bf5fa8fe170 100644 --- a/packages/vite/src/node/plugins/index.ts +++ b/packages/vite/src/node/plugins/index.ts @@ -12,7 +12,12 @@ import { } from 'rolldown/experimental' import type { PluginHookUtils, ResolvedConfig } from '../config' import { isDepOptimizationDisabled } from '../optimizer' -import type { HookHandler, Plugin, PluginWithRequiredHook } from '../plugin' +import { + type HookHandler, + type Plugin, + type PluginWithRequiredHook, + createBuiltinPluginWithEnvironmentSupport, +} from '../plugin' import { watchPackageDataPlugin } from '../packages' import { getFsUtils } from '../fsUtils' import { jsonPlugin } from './json' @@ -77,9 +82,19 @@ export async function resolvePlugins( modulePreload !== false && modulePreload.polyfill ? enableNativePlugin - ? nativeModulePreloadPolyfillPlugin({ - skip: Boolean(config.command !== 'build' || config.build.ssr), - }) + ? createBuiltinPluginWithEnvironmentSupport( + 'native:modulepreload-polyfill', + (environment) => { + if ( + config.command !== 'build' || + environment.config.consumer !== 'client' + ) + return false + return nativeModulePreloadPolyfillPlugin({ + skip: false, + }) + }, + ) : modulePreloadPolyfillPlugin(config) : null, enableNativePlugin