Skip to content

Commit

Permalink
feat: native build plugins (vitejs#45) (vitejs#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
IWANABETHATGUY authored and sapphi-red committed Nov 6, 2024
1 parent ff77f98 commit a9e70bc
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 31 deletions.
32 changes: 27 additions & 5 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
LoggingFunction,
ModuleFormat,
OutputOptions,
RolldownPlugin,
RollupBuild,
RollupError,
RollupLog,
Expand All @@ -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'
Expand Down Expand Up @@ -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.
Expand All @@ -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(),
],
}
}
Expand Down
75 changes: 49 additions & 26 deletions packages/vite/src/node/plugins/importAnalysisBuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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 }
}
},
Expand Down Expand Up @@ -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]
}

0 comments on commit a9e70bc

Please sign in to comment.