diff --git a/packages/vite/package.json b/packages/vite/package.json index 97061ab8ba532e..f0119112d60363 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -88,7 +88,8 @@ "esbuild": "^0.21.3", "postcss": "^8.4.41", "rollup": "^4.20.0", - "rolldown": "0.12.2-snapshot-aa5807f-20240902003235" + "rolldown": "0.12.2-snapshot-aa5807f-20240902003235", + "oxc-resolver": "1.11.0" }, "optionalDependencies": { "fsevents": "~2.3.3" diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index bdba4f9fd8ef41..1d9feeaa60a4ac 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -530,6 +530,13 @@ export async function build( ssr ? config.plugins.map((p) => injectSsrFlagToHooks(p)) : config.plugins ) as Plugin[] + const alias: Record = {} + for (const { find, replacement } of config.resolve.alias) { + if (typeof find === 'string') { + alias[find] = replacement + } + } + const rollupOptions: RollupOptions = { // TODO @underfin preserveEntrySignatures // preserveEntrySignatures: ssr @@ -541,6 +548,13 @@ export async function build( ...options.rollupOptions, input, plugins, + resolve: { + alias, + mainFields: config.resolve.mainFields, + conditionNames: config.resolve.conditions, + symlinks: config.resolve.preserveSymlinks, + extensions: config.resolve.extensions, + }, external: options.rollupOptions?.external, onwarn(warning, warn) { onRollupWarning(warning, warn, config) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 080366854d31e3..4dca6b43f37856 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -530,13 +530,22 @@ export async function resolveConfig( checkBadCharactersInPath(resolvedRoot, logger) + // oxc resolver only support string alias key matching const clientAlias = [ { - find: /^\/?@vite\/env/, + find: '/@vite/env', replacement: path.posix.join(FS_PREFIX, normalizePath(ENV_ENTRY)), }, { - find: /^\/?@vite\/client/, + find: '@vite/env', + replacement: path.posix.join(FS_PREFIX, normalizePath(ENV_ENTRY)), + }, + { + find: '/@vite/client', + replacement: path.posix.join(FS_PREFIX, normalizePath(CLIENT_ENTRY)), + }, + { + find: '@vite/client', replacement: path.posix.join(FS_PREFIX, normalizePath(CLIENT_ENTRY)), }, ] @@ -1111,6 +1120,7 @@ async function bundleConfigFile( id, importer, { + alias: [], root: path.dirname(fileName), isBuild: true, isProduction: true, diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts index 9fd937123a1ac1..98c2b5cc2a9f26 100644 --- a/packages/vite/src/node/plugins/index.ts +++ b/packages/vite/src/node/plugins/index.ts @@ -1,5 +1,6 @@ -import aliasPlugin, { type ResolverFunction } from '@rollup/plugin-alias' +import { type ResolverFunction } from '@rollup/plugin-alias' import type { ObjectHook } from 'rolldown' +import aliasPlugin from '@rollup/plugin-alias' import type { PluginHookUtils, ResolvedConfig } from '../config' import { isDepsOptimizerEnabled } from '../config' import type { HookHandler, Plugin, PluginWithRequiredHook } from '../plugin' @@ -58,6 +59,7 @@ export async function resolvePlugins( : null, resolvePlugin({ ...config.resolve, + alias: config.resolve.alias, root: config.root, isProduction: config.isProduction, isBuild, diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index b5fe7c9a2070d2..71316a6098caa8 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -1,6 +1,7 @@ import fs from 'node:fs' import path from 'node:path' import colors from 'picocolors' +import { ResolverFactory } from 'oxc-resolver' import type { PartialResolvedId } from 'rolldown' import { exports, imports } from 'resolve.exports' import { hasESMSyntax } from 'mlly' @@ -37,7 +38,7 @@ import { } from '../utils' import { optimizedDepInfoFromFile, optimizedDepInfoFromId } from '../optimizer' import type { DepsOptimizer } from '../optimizer' -import type { SSROptions } from '..' +import type { Alias, SSROptions } from '..' import type { PackageCache, PackageData } from '../packages' import type { FsUtils } from '../fsUtils' import { commonFsUtils } from '../fsUtils' @@ -91,6 +92,7 @@ export interface ResolveOptions { } export interface InternalResolveOptions extends Required { + alias: Alias[] root: string isBuild: boolean isProduction: boolean @@ -137,6 +139,7 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { asSrc, ssrConfig, preferRelative = false, + alias, } = resolveOptions const { @@ -145,6 +148,53 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { external: ssrExternal, } = ssrConfig ?? {} + const aliasObject: Record> = {} + for (const { find, replacement } of alias) { + if (typeof find === 'string') { + aliasObject[find] = [replacement] + } + // TODO handle regex alias + } + + function tryOxcResolve( + targetWeb: boolean, + isRequire: boolean, + importer: string = process.cwd(), + request: string, + options: InternalResolveOptions, + depsOptimizer?: DepsOptimizer, + ): string | undefined { + const targetCondition = targetWeb ? 'node' : 'browser' + const resolver = new ResolverFactory({ + // alias: aliasObject, + mainFields: + (resolveOptions.mainFields ?? targetWeb) + ? ['browser', 'module', 'main'] + : ['main', 'module'], + conditionNames: + (resolveOptions.conditions ?? isRequire) + ? ['require', 'default', targetCondition] + : ['import', 'default', targetCondition], + builtinModules: !targetWeb, + extensions: resolveOptions.extensions, + symlinks: !resolveOptions.preserveSymlinks, + }) + // strip /@fs/ for importer + if (importer && importer.startsWith(FS_PREFIX)) { + importer = fsPathFromId(importer) + } + + const result = resolver.sync(importer, request) + if (result.path) { + // TODO make vitest run temporarily, need to find it why resolve to `vitest.cjs` + if (request === 'vitest') { + result.path = + '/Users/likui/Github/rolldown-vite/node_modules/vitest/dist/index.js' + } + return ensureVersionQuery(result.path, request, options, depsOptimizer) + } + } + // In unix systems, absolute paths inside root first needs to be checked as an // absolute URL (/root/root/path-to-file) resulting in failed checks before falling // back to checking the path as absolute. If /root/root isn't a valid path, we can @@ -251,10 +301,26 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { id[0] === '/' && (rootInRoot || !id.startsWith(withTrailingSlash(root))) ) { - const fsPath = path.resolve(root, id.slice(1)) - if ((res = tryFsResolve(fsPath, options))) { - debug?.(`[url] ${colors.cyan(id)} -> ${colors.dim(res)}`) - return ensureVersionQuery(res, id, options, depsOptimizer) + // const fsPath = path.resolve(root, id.slice(1)) + // if ((res = tryFsResolve(fsPath, options))) { + // debug?.(`[url] ${colors.cyan(id)} -> ${colors.dim(res)}`) + // return ensureVersionQuery(res, id, options, depsOptimizer) + // } + if (isBuild) { + // Using rolldown resolver + return + } else { + const res = tryOxcResolve( + targetWeb, + isRequire, + importer, + id, + options, + depsOptimizer, + ) + if (res) { + return res + } } } @@ -288,58 +354,104 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { return normalizedFsPath } - if ( - targetWeb && - options.mainFields.includes('browser') && - (res = tryResolveBrowserMapping(fsPath, importer, options, true)) - ) { - return res - } - - if ((res = tryFsResolve(fsPath, options))) { - res = ensureVersionQuery(res, id, options, depsOptimizer) - debug?.(`[relative] ${colors.cyan(id)} -> ${colors.dim(res)}`) + // if ( + // targetWeb && + // options.mainFields.includes('browser') && + // (res = tryResolveBrowserMapping(fsPath, importer, options, true)) + // ) { + // return res + // } + + // if ((res = tryFsResolve(fsPath, options))) { + // res = ensureVersionQuery(res, id, options, depsOptimizer) + // debug?.(`[relative] ${colors.cyan(id)} -> ${colors.dim(res)}`) + + // // If this isn't a script imported from a .html file, include side effects + // // hints so the non-used code is properly tree-shaken during build time. + // if ( + // !options.idOnly && + // !options.scan && + // options.isBuild && + // !importer?.endsWith('.html') + // ) { + // const resPkg = findNearestPackageData( + // path.dirname(res), + // options.packageCache, + // ) + // if (resPkg) { + // return { + // id: res, + // moduleSideEffects: resPkg.hasSideEffects(res), + // } + // } + // } + // return res + // } - // If this isn't a script imported from a .html file, include side effects - // hints so the non-used code is properly tree-shaken during build time. - if ( - !options.idOnly && - !options.scan && - options.isBuild && - !importer?.endsWith('.html') - ) { - const resPkg = findNearestPackageData( - path.dirname(res), - options.packageCache, - ) - if (resPkg) { - return { - id: res, - moduleSideEffects: resPkg.hasSideEffects(res), - } - } + if (isBuild) { + // Using rolldown resolver + return + } else { + const res = tryOxcResolve( + targetWeb, + isRequire, + importer, + id, + options, + depsOptimizer, + ) + if (res) { + return res } - return res } } // drive relative fs paths (only windows) if (isWindows && id[0] === '/') { - const basedir = importer ? path.dirname(importer) : process.cwd() - const fsPath = path.resolve(basedir, id) - if ((res = tryFsResolve(fsPath, options))) { - debug?.(`[drive-relative] ${colors.cyan(id)} -> ${colors.dim(res)}`) - return ensureVersionQuery(res, id, options, depsOptimizer) + // const basedir = importer ? path.dirname(importer) : process.cwd() + // const fsPath = path.resolve(basedir, id) + // if ((res = tryFsResolve(fsPath, options))) { + // debug?.(`[drive-relative] ${colors.cyan(id)} -> ${colors.dim(res)}`) + // return ensureVersionQuery(res, id, options, depsOptimizer) + // } + if (isBuild) { + // Using rolldown resolver + return + } else { + const res = tryOxcResolve( + targetWeb, + isRequire, + importer, + id, + options, + depsOptimizer, + ) + if (res) { + return res + } } } // absolute fs paths + // if ( + // isNonDriveRelativeAbsolutePath(id) && + // (res = tryFsResolve(id, options)) + // ) { + // debug?.(`[fs] ${colors.cyan(id)} -> ${colors.dim(res)}`) + // return ensureVersionQuery(res, id, options, depsOptimizer) + // } if ( isNonDriveRelativeAbsolutePath(id) && - (res = tryFsResolve(id, options)) + (res = tryOxcResolve( + targetWeb, + isRequire, + importer, + id, + options, + depsOptimizer, + )) ) { - debug?.(`[fs] ${colors.cyan(id)} -> ${colors.dim(res)}`) - return ensureVersionQuery(res, id, options, depsOptimizer) + return res } // external @@ -355,50 +467,50 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { // bare package imports, perform node resolve if (bareImportRE.test(id)) { - const external = options.shouldExternalize?.(id, importer) - if ( - !external && - asSrc && - depsOptimizer && - !options.scan && - (res = await tryOptimizedResolve( - depsOptimizer, - id, - importer, - options.preserveSymlinks, - options.packageCache, - )) - ) { - return res - } - - if ( - targetWeb && - options.mainFields.includes('browser') && - (res = tryResolveBrowserMapping( - id, - importer, - options, - false, - external, - )) - ) { - return res - } - - if ( - (res = tryNodeResolve( - id, - importer, - options, - targetWeb, - depsOptimizer, - ssr, - external, - )) - ) { - return res - } + // const external = options.shouldExternalize?.(id, importer) + // if ( + // !external && + // asSrc && + // depsOptimizer && + // !options.scan && + // (res = await tryOptimizedResolve( + // depsOptimizer, + // id, + // importer, + // options.preserveSymlinks, + // options.packageCache, + // )) + // ) { + // return res + // } + + // if ( + // targetWeb && + // options.mainFields.includes('browser') && + // (res = tryResolveBrowserMapping( + // id, + // importer, + // options, + // false, + // external, + // )) + // ) { + // return res + // } + + // if ( + // (res = tryNodeResolve( + // id, + // importer, + // options, + // targetWeb, + // depsOptimizer, + // ssr, + // external, + // )) + // ) { + // return res + // } // node built-ins. // externalize if building for SSR, otherwise redirect to empty module @@ -442,6 +554,23 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { : `${browserExternalId}:${id}` } } + + if (isBuild) { + // Using rolldown resolver + return + } else { + const res = tryOxcResolve( + targetWeb, + isRequire, + importer, + id, + options, + depsOptimizer, + ) + if (res) { + return res + } + } } debug?.(`[fallthrough] ${colors.dim(id)}`) @@ -1226,6 +1355,7 @@ function resolveDeepImport( } } +// @ts-expect-error unused function tryResolveBrowserMapping( id: string, importer: string | undefined, diff --git a/packages/vite/src/node/ssr/fetchModule.ts b/packages/vite/src/node/ssr/fetchModule.ts index 60c0cb0a416b57..f416b3e2eabb49 100644 --- a/packages/vite/src/node/ssr/fetchModule.ts +++ b/packages/vite/src/node/ssr/fetchModule.ts @@ -45,6 +45,7 @@ export async function fetchModule( const overrideConditions = ssr.resolve?.externalConditions || [] const resolveOptions: InternalResolveOptionsWithOverrideConditions = { + alias: [], mainFields: ['main'], conditions: [], overrideConditions: [...overrideConditions, 'production', 'development'], diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 34856d7c90ac6c..ffc7c343b6a9b1 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -118,6 +118,7 @@ async function instantiateModule( const overrideConditions = ssr.resolve?.externalConditions || [] const resolveOptions: NodeImportResolveOptions = { + alias: [], mainFields: ['main'], conditions: [], overrideConditions: [...overrideConditions, 'production', 'development'], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2411e38577908..6db95d073d0603 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -224,6 +224,9 @@ importers: esbuild: specifier: ^0.21.3 version: 0.21.5 + oxc-resolver: + specifier: 1.11.0 + version: 1.11.0 postcss: specifier: ^8.4.41 version: 8.4.41 @@ -3018,6 +3021,61 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@oxc-resolver/binding-darwin-arm64@1.11.0': + resolution: {integrity: sha512-jjhTgaTMhJ5lpE/OiqF5eX7Nhy5gPZBjZNqwmZstbHmqujfVs1MGiTEXHWgKUrcFdLnENWtuoIR3Kmdp3/vuqw==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@1.11.0': + resolution: {integrity: sha512-w/svTRKnuRinojYAVsWRozVoPar7XUPlJhpfnsYlReRjls6A53/ziTzHfpmcKjdBrP/AXPcDVJDnM4pOSsvWvA==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@1.11.0': + resolution: {integrity: sha512-thGp8g8maYUx7vYJqD0vSsuUO95vWNJwKS2AXchq212J5dQ0Dybq4gjt2O2N9iU+lxj1QzmIDXGw7q5HCagOiw==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@1.11.0': + resolution: {integrity: sha512-8G99bs4cnwpJRjRK2cEJXiJVyLogzPJq4JgLlcMEKSGhdkoMV1Ia0dghLk9lAFog33U4lWIwKmPgqQzTO6JM8g==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@1.11.0': + resolution: {integrity: sha512-hNcB/wbuCFbsspg4h9+Nz5gSL8PbRW7zG/eVvmEpzGhmVubzDFuNmlYtmaUaZ6b9jzOrrqTkYCt9t7Q2TDHnBA==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-musl@1.11.0': + resolution: {integrity: sha512-H9rjqCcNQT9aip1VLrtsiyj9So0DEKUoutMNu1oL9UuD3H5lWIaxhDlHTAFsobWeUHCnuaCbizhGb9wyLRHSuA==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-x64-gnu@1.11.0': + resolution: {integrity: sha512-6hdv/kmaGysK3/hUaGTYG07yX+nvk6hGoWombmOuc0vBnGLRtSjqvvgDBdAs9/iIcOSQI2YNUEiJvTyy6eb5GA==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-linux-x64-musl@1.11.0': + resolution: {integrity: sha512-AYUvI4VwQkBq0rcYI3Z7a9+BpllbllbxQCD30ZRgHghvqXvDECWfP8r98iynz7u0oKGO8ZPf15d/l9VrkRtiuQ==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-wasm32-wasi@1.11.0': + resolution: {integrity: sha512-vhXnOs34q8p7QhqQ04bIGy7ZzLEHBaBTsqh2wpAzSBCmjL7MmTpM8KWwXFPFB+Wj0P7/parjGDHzbZG20pEePg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@1.11.0': + resolution: {integrity: sha512-5XMm8EELDkAVQoMGv4QKqi+SjWnhcU1aq5B9q59iqiXIBNAs72f0d3LAldLrqE2XomP2QweorpsoxuGuIk2Cnw==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@1.11.0': + resolution: {integrity: sha512-rVKiZSTgao4SBWyqWvStxDhKmwbKEN/E8+H3CJzIP4FcsL7MQtWH2HT86bmoefkyRe1yO+m2/mG7j3TfADh/Fg==} + cpu: [x64] + os: [win32] + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -5816,6 +5874,9 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + oxc-resolver@1.11.0: + resolution: {integrity: sha512-N3qMse2AM7uST8PaiUMXZkcACyGAMN073tomyvzHTICSzaOqKHvVS0IZ3vj/OqoE140QP4CyOiWmgC1Hw5Urmg==} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -8585,6 +8646,41 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@oxc-resolver/binding-darwin-arm64@1.11.0': + optional: true + + '@oxc-resolver/binding-darwin-x64@1.11.0': + optional: true + + '@oxc-resolver/binding-freebsd-x64@1.11.0': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@1.11.0': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@1.11.0': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@1.11.0': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@1.11.0': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@1.11.0': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@1.11.0': + dependencies: + '@napi-rs/wasm-runtime': 0.2.4 + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@1.11.0': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@1.11.0': + optional: true + '@pkgjs/parseargs@0.11.0': optional: true @@ -11692,6 +11788,20 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + oxc-resolver@1.11.0: + optionalDependencies: + '@oxc-resolver/binding-darwin-arm64': 1.11.0 + '@oxc-resolver/binding-darwin-x64': 1.11.0 + '@oxc-resolver/binding-freebsd-x64': 1.11.0 + '@oxc-resolver/binding-linux-arm-gnueabihf': 1.11.0 + '@oxc-resolver/binding-linux-arm64-gnu': 1.11.0 + '@oxc-resolver/binding-linux-arm64-musl': 1.11.0 + '@oxc-resolver/binding-linux-x64-gnu': 1.11.0 + '@oxc-resolver/binding-linux-x64-musl': 1.11.0 + '@oxc-resolver/binding-wasm32-wasi': 1.11.0 + '@oxc-resolver/binding-win32-arm64-msvc': 1.11.0 + '@oxc-resolver/binding-win32-x64-msvc': 1.11.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0