From 97a4abe1f1dc257f2aa20ca69c191f04212dec00 Mon Sep 17 00:00:00 2001 From: shulaoda <165626830+shulaoda@users.noreply.github.com> Date: Wed, 10 Dec 2025 17:33:03 +0800 Subject: [PATCH] feat: init --- package.json | 2 +- packages/vite/package.json | 2 +- packages/vite/src/node/config.ts | 7 +- packages/vite/src/node/plugins/asset.ts | 20 +- .../src/node/plugins/assetImportMetaUrl.ts | 27 ++- packages/vite/src/node/plugins/css.ts | 83 ++++++++- .../src/node/plugins/dynamicImportVars.ts | 6 + packages/vite/src/node/plugins/html.ts | 45 ++++- .../src/node/plugins/importAnalysisBuild.ts | 27 +++ .../vite/src/node/plugins/importMetaGlob.ts | 6 + packages/vite/src/node/plugins/manifest.ts | 61 +++++++ packages/vite/src/node/plugins/wasm.ts | 9 + playground/assets/__tests__/assets.spec.ts | 16 +- .../__tests__/js-sourcemap.spec.ts | 7 +- playground/package.json | 2 +- pnpm-lock.yaml | 172 ++++++++++-------- 16 files changed, 397 insertions(+), 95 deletions(-) diff --git a/package.json b/package.json index 41617de11afb44..10eefd03f6f2fa 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "picocolors": "^1.1.1", "playwright-chromium": "^1.57.0", "prettier": "3.7.3", - "rolldown": "1.0.0-beta.53", + "rolldown": "https://pkg.pr.new/rolldown@127a02b", "rollup": "^4.43.0", "simple-git-hooks": "^2.13.1", "tsx": "^4.21.0", diff --git a/packages/vite/package.json b/packages/vite/package.json index 8ad45eb0ff7282..10471eb3b1f89f 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -87,7 +87,7 @@ "lightningcss": "^1.30.2", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rolldown": "1.0.0-beta.53", + "rolldown": "https://pkg.pr.new/rolldown@127a02b", "tinyglobby": "^0.2.15" }, "optionalDependencies": { diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index c23f4bd996503c..34b5c43129698d 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -550,7 +550,7 @@ export interface ExperimentalOptions { * * - 'resolver' (deprecated, will be removed in v8 stable): Enable only the native resolver plugin. * - 'v1' (will be deprecated, will be removed in v8 stable): Enable the first stable set of native plugins (including resolver). - * - true: Enable all native plugins (currently an alias of 'v1', it will map to a newer one in the future versions). + * - true: Enable all native plugins (including newly added ones beyond 'v1'). * * @experimental * @default 'v1' @@ -768,7 +768,7 @@ const configDefaults = Object.freeze({ importGlobRestoreExtension: false, renderBuiltUrl: undefined, hmrPartialAccept: false, - enableNativePlugin: process.env._VITE_TEST_JS_PLUGIN ? false : 'v1', + enableNativePlugin: process.env._VITE_TEST_JS_PLUGIN ? false : true, }, future: { removePluginHookHandleHotUpdate: undefined, @@ -2060,8 +2060,9 @@ function resolveNativePluginEnabledLevel( case 'resolver': return 0 case 'v1': - case true: return 1 + case true: + return 2 case false: return -1 default: diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 4ec192676dce0a..f35594daac7df7 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -2,6 +2,7 @@ import path from 'node:path' import fsp from 'node:fs/promises' import { Buffer } from 'node:buffer' import * as mrmime from 'mrmime' +import { viteAssetPlugin as nativeAssetPlugin } from 'rolldown/experimental' import type { NormalizedOutputOptions, PluginContext, @@ -15,7 +16,7 @@ import { createToImportMetaURLBasedRelativeRuntime, toOutputFilePathInJS, } from '../build' -import type { Plugin } from '../plugin' +import { type Plugin, perEnvironmentPlugin } from '../plugin' import type { ResolvedConfig } from '../config' import { checkPublicFile } from '../publicDir' import { @@ -148,6 +149,23 @@ export function renderAssetUrlInJS( * Also supports loading plain strings with import text from './foo.txt?raw' */ export function assetPlugin(config: ResolvedConfig): Plugin { + if (config.command === 'build' && config.nativePluginEnabledLevel >= 2) { + return perEnvironmentPlugin('native:asset', (env) => { + return nativeAssetPlugin({ + root: env.config.root, + isLib: !!env.config.build.lib, + isSsr: !!env.config.build.ssr, + isWorker: env.config.isWorker, + urlBase: env.config.base, + publicDir: env.config.publicDir, + decodedBase: env.config.decodedBase, + isSkipAssets: !env.config.build.emitAssets, + assetInlineLimit: env.config.build.assetsInlineLimit, + assetsInclude: env.config.rawAssetsInclude, + }) + }) + } + registerCustomMime() return { diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index 5d31786176e2b1..56be7eed868209 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -2,7 +2,8 @@ import path from 'node:path' import MagicString from 'magic-string' import { stripLiteral } from 'strip-literal' import { exactRegex } from '@rolldown/pluginutils' -import type { Plugin } from '../plugin' +import { viteAssetImportMetaUrlPlugin } from 'rolldown/experimental' +import { type Plugin, perEnvironmentPlugin } from '../plugin' import type { ResolvedConfig } from '../config' import { injectQuery, @@ -44,6 +45,30 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { asSrc: true, } + if (config.command === 'build' && config.nativePluginEnabledLevel >= 2) { + return perEnvironmentPlugin('vite:native-asset-import-meta-url', (env) => { + if (env.config.consumer === 'client') { + return viteAssetImportMetaUrlPlugin({ + root: env.config.root, + isLib: !!env.config.build.lib, + publicDir: env.config.publicDir, + clientEntry: CLIENT_ENTRY, + assetInlineLimit: env.config.build.assetsInlineLimit, + tryFsResolve: (file) => tryFsResolve(file, fsResolveOptions), + assetResolver: (url, importer) => { + assetResolver ??= createBackCompatIdResolver(env.config, { + extensions: [], + mainFields: [], + tryIndex: false, + preferRelative: true, + }) + return assetResolver(env, url, importer) + }, + }) + } + }) + } + return { name: 'vite:asset-import-meta-url', diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 3f321fd551d5b1..43a1bec977bef1 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -27,6 +27,7 @@ import type { TransformAttributeResult as LightningCssTransformAttributeResult, TransformResult as LightningCssTransformResult, } from 'lightningcss' +import { viteCSSPlugin, viteCSSPostPlugin } from 'rolldown/experimental' import type { LightningCSSOptions } from '#types/internal/lightningcssOptions' import type { LessPreprocessorBaseOptions, @@ -89,7 +90,7 @@ import type { ResolveIdFn } from '../idResolver' import { PartialEnvironment } from '../baseEnvironment' import type { TransformPluginContext } from '../server/pluginContainer' import { searchForWorkspaceRoot } from '../server/searchRoot' -import { type DevEnvironment } from '..' +import { type DevEnvironment, perEnvironmentPlugin } from '..' import type { PackageCache } from '../packages' import { findNearestMainPackageData } from '../packages' import { nodeResolveWithVite } from '../nodeResolve' @@ -311,6 +312,49 @@ export function cssPlugin(config: ResolvedConfig): Plugin { }) } + if (isBuild && config.nativePluginEnabledLevel >= 2) { + return perEnvironmentPlugin('vite:native-css', (env) => { + return [ + { + name: 'vite:css-compat', + buildStart() { + preprocessorWorkerController = createPreprocessorWorkerController( + normalizeMaxWorkers(config.css.preprocessorMaxWorkers), + ) + preprocessorWorkerControllerCache.set( + config, + preprocessorWorkerController, + ) + }, + + buildEnd() { + preprocessorWorkerController?.close() + }, + }, + viteCSSPlugin({ + root: env.config.root, + isLib: !!env.config.build.lib, + publicDir: env.config.publicDir, + async compileCSS(url, importer, resolver) { + return compileCSS( + env, + url, + importer, + preprocessorWorkerController!, + (url, importer) => { + return resolver.call(url, importer) + }, + ) + }, + resolveUrl(url, importer) { + return idResolver(env, url, importer) + }, + assetInlineLimit: env.config.build.assetsInlineLimit, + }), + ] + }) + } + return { name: 'vite:css', @@ -506,6 +550,43 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { return cssBundleName } + if (config.command === 'build' && config.nativePluginEnabledLevel >= 2) { + return perEnvironmentPlugin('native:css-post', (env) => { + let libCssFilename: string | undefined + if (env.config.build.lib) { + const libOptions = env.config.build.lib + if (typeof libOptions.cssFileName === 'string') { + libCssFilename = `${libOptions.cssFileName}.css` + } else if (typeof libOptions.fileName === 'string') { + libCssFilename = `${libOptions.fileName}.css` + } + } + return [ + viteCSSPostPlugin({ + root: env.config.root, + isLib: !!env.config.build.lib, + isSsr: !!env.config.build.ssr, + isWorker: env.config.isWorker, + isClient: env.config.consumer === 'client', + cssCodeSplit: env.config.build.cssCodeSplit, + sourcemap: !!env.config.build.sourcemap, + assetsDir: env.config.build.assetsDir, + urlBase: env.config.base, + decodedBase: env.config.decodedBase, + libCssFilename, + cssMinify: env.config.build.cssMinify + ? async (content, inline) => { + return await minifyCSS(content, env.config, inline) + } + : undefined, + renderBuiltUrl: env.config.experimental.renderBuiltUrl, + isOutputOptionsForLegacyChunks: + env.config.isOutputOptionsForLegacyChunks, + }), + ] + }) + } + return { name: 'vite:css-post', diff --git a/packages/vite/src/node/plugins/dynamicImportVars.ts b/packages/vite/src/node/plugins/dynamicImportVars.ts index a41f165be705fe..98599d75e5b278 100644 --- a/packages/vite/src/node/plugins/dynamicImportVars.ts +++ b/packages/vite/src/node/plugins/dynamicImportVars.ts @@ -184,6 +184,12 @@ export function dynamicImportVarsPlugin(config: ResolvedConfig): Plugin { resolver(id, importer) { return resolve(environment, id, importer) }, + isV2: + config.nativePluginEnabledLevel >= 2 + ? { + sourcemap: !!environment.config.build.sourcemap, + } + : undefined, }) }) } diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 02305b45387c38..8d7073e42bd827 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -17,7 +17,15 @@ import type { } from 'parse5' import { stripLiteral } from 'strip-literal' import escapeHtml from 'escape-html' -import type { MinimalPluginContextWithoutEnvironment, Plugin } from '../plugin' +import { + viteHtmlInlineProxyPlugin as nativeHtmlInlineProxyPlugin, + viteHtmlPlugin, +} from 'rolldown/experimental' +import { + type MinimalPluginContextWithoutEnvironment, + type Plugin, + perEnvironmentPlugin, +} from '../plugin' import type { ViteDevServer } from '../server' import { decodeURIIfPossible, @@ -41,6 +49,7 @@ import { cleanUrl } from '../../shared/utils' import { perEnvironmentState } from '../environment' import { getNodeAssetAttributes } from '../assetSource' import type { Logger } from '../logger' +import { VERSION } from '../constants' import { assetUrlRE, getPublicAssetFilename, @@ -101,6 +110,12 @@ export const htmlProxyMap: WeakMap< export const htmlProxyResult: Map = new Map() export function htmlInlineProxyPlugin(config: ResolvedConfig): Plugin { + if (config.command === 'build' && config.nativePluginEnabledLevel >= 2) { + return nativeHtmlInlineProxyPlugin({ + root: config.root, + }) + } + // Should do this when `constructor` rather than when `buildStart`, // `buildStart` will be triggered multiple times then the cached result will be emptied. // https://github.com/vitejs/vite/issues/6372 @@ -366,6 +381,34 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { // Same reason with `htmlInlineProxyPlugin` isAsyncScriptMap.set(config, new Map()) + if (config.command === 'build' && config.nativePluginEnabledLevel >= 2) { + return perEnvironmentPlugin('native:vite-html', (env) => { + return viteHtmlPlugin({ + root: env.config.root, + isLib: !!env.config.build.lib, + isSsr: !!env.config.build.ssr, + urlBase: env.config.base, + publicDir: env.config.publicDir, + decodedBase: env.config.decodedBase, + modulePreload: env.config.build.modulePreload, + cssCodeSplit: env.config.build.cssCodeSplit, + assetInlineLimit: env.config.build.assetsInlineLimit, + preHooks, + normalHooks, + postHooks, + async applyHtmlTransforms(html, hooks, pluginContext, ctx) { + pluginContext.meta.viteVersion = VERSION + return applyHtmlTransforms( + html, + hooks as IndexHtmlTransformHook[], + pluginContext, + ctx, + ) + }, + }) + }) + } + return { name: 'vite:build-html', diff --git a/packages/vite/src/node/plugins/importAnalysisBuild.ts b/packages/vite/src/node/plugins/importAnalysisBuild.ts index 53faae2872bc1d..62f81eec0632e5 100644 --- a/packages/vite/src/node/plugins/importAnalysisBuild.ts +++ b/packages/vite/src/node/plugins/importAnalysisBuild.ts @@ -744,6 +744,33 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin[] { }, } + if (config.nativePluginEnabledLevel >= 2) { + return [ + perEnvironmentPlugin('native:import-analysis-build', (env) => { + const preloadCode = getPreloadCode( + env, + !!renderBuiltUrl, + isRelativeBase, + ) + return nativeBuildImportAnalysisPlugin({ + preloadCode, + insertPreload: getInsertPreload(env), + // this field looks redundant, put a dummy value for now + optimizeModulePreloadRelativePaths: false, + renderBuiltUrl: !!renderBuiltUrl, + isRelativeBase, + v2: { + isSsr: !!env.config.build.ssr, + urlBase: env.config.base, + decodedBase: env.config.decodedBase, + modulePreload: env.config.build.modulePreload, + renderBuiltUrl: env.config.experimental.renderBuiltUrl, + }, + }) + }), + ] + } + if (config.nativePluginEnabledLevel >= 1) { delete plugin.transform delete plugin.resolveId diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index 796894d44f454a..699d98af0cb4f6 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -46,6 +46,12 @@ export function importGlobPlugin(config: ResolvedConfig): Plugin { return nativeImportGlobPlugin({ root: config.root, restoreQueryExtension: config.experimental.importGlobRestoreExtension, + isV2: + config.nativePluginEnabledLevel >= 2 + ? { + sourcemap: !!config.build.sourcemap, + } + : undefined, }) } diff --git a/packages/vite/src/node/plugins/manifest.ts b/packages/vite/src/node/plugins/manifest.ts index 59a23d99dd8ed6..b80e4c020c8c12 100644 --- a/packages/vite/src/node/plugins/manifest.ts +++ b/packages/vite/src/node/plugins/manifest.ts @@ -72,6 +72,67 @@ export function manifestPlugin(config: ResolvedConfig): Plugin { }, } }) + if (config.build.manifest && config.nativePluginEnabledLevel >= 2) { + return perEnvironmentPlugin('native:manifest', (env) => { + if (!env.config.build.manifest) return false + + const root = env.config.root + const outPath = + env.config.build.manifest === true + ? '.vite/manifest.json' + : env.config.build.manifest + + const envs: Record = {} + + return [ + { + name: 'native:manifest-envs', + buildStart() { + envs[env.name] = this.environment + }, + }, + nativeManifestPlugin({ + root, + outPath, + isEnableV2: true, + isOutputOptionsForLegacyChunks: + env.config.isOutputOptionsForLegacyChunks, + cssEntries() { + return Object.fromEntries( + cssEntriesMap.get(envs[env.name])!.entries(), + ) + }, + }), + { + name: 'native:manifest-compatible', + generateBundle(_, bundle) { + const asset = bundle[outPath] + if (asset.type === 'asset') { + const output = + this.environment.config.build.rolldownOptions.output + const outputLength = Array.isArray(output) ? output.length : 1 + if (outputLength === 1) { + return + } + + const state = getState(this) + state.outputCount++ + state.manifest = Object.assign( + state.manifest, + JSON.parse(asset.source.toString()), + ) + if (state.outputCount >= outputLength) { + asset.source = JSON.stringify(state.manifest, undefined, 2) + state.reset() + } else { + delete bundle[outPath] + } + } + }, + }, + ] + }) + } if (config.build.manifest && config.nativePluginEnabledLevel >= 1) { return perEnvironmentPlugin('native:manifest', (environment) => { if (!environment.config.build.manifest) return false diff --git a/packages/vite/src/node/plugins/wasm.ts b/packages/vite/src/node/plugins/wasm.ts index 5b3ad98b3fc92c..7a45ab3b138b55 100644 --- a/packages/vite/src/node/plugins/wasm.ts +++ b/packages/vite/src/node/plugins/wasm.ts @@ -57,6 +57,15 @@ export const wasmHelperPlugin = (config: ResolvedConfig): Plugin => { if (config.command === 'build' && config.nativePluginEnabledLevel >= 1) { return nativeWasmHelperPlugin({ decodedBase: config.decodedBase, + v2: + config.nativePluginEnabledLevel >= 2 + ? { + root: config.root, + isLib: !!config.build.lib, + publicDir: config.publicDir, + assetInlineLimit: config.build.assetsInlineLimit, + } + : undefined, }) } diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 1b60ddd0d16a41..718eb3461546ef 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -762,12 +762,16 @@ test('should not rewrite non-relative urls in html', async () => { expect(await link.getAttribute('href')).toBe('data:,') }) -test.runIf(isBuild)('assets inside