diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index a9249548aca131..0242d6a9a5bb23 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -566,6 +566,17 @@ export interface LegacyOptions { * that security weakness.** */ skipWebSocketTokenCheck?: boolean + /** + * Opt-in to the pre-Vite 8 CJS interop behavior, which was inconsistent. + * + * In pre-Vite 8 versions, Vite had inconsistent CJS interop behavior. This was due to + * the different behavior of esbuild and the Rollup commonjs plugin. + * Vite 8+ uses Rolldown for both the dependency optimization in dev and the production build, + * which aligns the behavior to esbuild. + * + * See the Vite 8 migration guide for more details. + */ + inconsistentCjsInterop?: boolean } export interface ResolvedWorkerOptions { diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index b2550eb6dd9c7f..6c470966473454 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -441,7 +441,9 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { imports.length, ) - let _isNodeModeResult: boolean | undefined + let _isNodeModeResult = config.legacy?.inconsistentCjsInterop + ? false + : undefined const isNodeMode = () => { _isNodeModeResult ??= isFilePathESM(importer, config.packageCache) return _isNodeModeResult diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts index a0cd0d2d80f5e2..dc3d66130525af 100644 --- a/packages/vite/src/node/plugins/index.ts +++ b/packages/vite/src/node/plugins/index.ts @@ -85,6 +85,7 @@ export async function resolvePlugins( asSrc: true, optimizeDeps: true, externalize: true, + legacyInconsistentCjsInterop: config.legacy?.inconsistentCjsInterop, }, isWorker ? { ...config, consumer: 'client', optimizeDepsPluginNames: [] } diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index d19320c42d6f5b..281273871bd360 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -167,6 +167,11 @@ interface ResolvePluginOptions { * @internal */ idOnly?: boolean + + /** + * Enable when `legacy.inconsistentCjsInterop` is true. See that option for more details. + */ + legacyInconsistentCjsInterop?: boolean } export interface InternalResolveOptions @@ -283,6 +288,7 @@ export function oxcResolvePlugin( external: options.external, noExternal: noExternal, dedupe: options.dedupe, + legacyInconsistentCjsInterop: options.legacyInconsistentCjsInterop, finalizeBareSpecifier: !depsOptimizerEnabled ? undefined : (resolvedId, rawId, importer) => { @@ -553,6 +559,7 @@ export function resolvePlugin( id: ensureVersionQuery(res, id, options, depsOptimizer), packageJsonPath: findNearestPackagePath( res, + options.legacyInconsistentCjsInterop, options.packageCache, isBuild, ), @@ -573,6 +580,7 @@ export function resolvePlugin( id: ensureVersionQuery(res, id, options, depsOptimizer), packageJsonPath: findNearestPackagePath( res, + options.legacyInconsistentCjsInterop, options.packageCache, isBuild, ), @@ -629,7 +637,9 @@ export function resolvePlugin( return { id: res, moduleSideEffects: resPkg.hasSideEffects(res), - packageJsonPath: path.join(resPkg.dir, 'package.json'), + packageJsonPath: options.legacyInconsistentCjsInterop + ? undefined + : path.join(resPkg.dir, 'package.json'), } } } @@ -653,6 +663,7 @@ export function resolvePlugin( id: ensureVersionQuery(res, id, options, depsOptimizer), packageJsonPath: findNearestPackagePath( res, + options.legacyInconsistentCjsInterop, options.packageCache, isBuild, ), @@ -670,6 +681,7 @@ export function resolvePlugin( id: ensureVersionQuery(res, id, options, depsOptimizer), packageJsonPath: findNearestPackagePath( res, + options.legacyInconsistentCjsInterop, options.packageCache, isBuild, ), @@ -1169,6 +1181,7 @@ export function tryNodeResolve( moduleSideEffects: pkg.hasSideEffects(resolved), packageJsonPath: findNearestPackagePath( resolved, + options.legacyInconsistentCjsInterop, options.packageCache, isBuild, ), @@ -1518,7 +1531,9 @@ function tryResolveBrowserMapping( result = { id: res, moduleSideEffects: resPkg.hasSideEffects(res), - packageJsonPath: path.join(resPkg.dir, 'package.json'), + packageJsonPath: options.legacyInconsistentCjsInterop + ? undefined + : path.join(resPkg.dir, 'package.json'), } } } @@ -1654,10 +1669,11 @@ function isDirectory(path: string): boolean { function findNearestPackagePath( file: string, + legacyInconsistentCjsInterop: boolean | undefined, packageCache: PackageCache | undefined, isBuild: boolean, ) { - if (!isBuild) return + if (!isBuild || legacyInconsistentCjsInterop) return const pkgData = findNearestPackageData(file, packageCache) return pkgData ? path.join(pkgData.dir, 'package.json') : null }