Skip to content

Commit

Permalink
feat!: remove ssr proxy for externalized modules (#14521)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy committed Oct 19, 2023
1 parent 7acb016 commit 5786837
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 96 deletions.
26 changes: 26 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,32 @@ See the [troubleshooting guide](/guide/troubleshooting.html#vite-cjs-node-api-de

## General Changes

### SSR externalized modules value now matches production

In Vite 4, SSR externalized modules are wrapped with `.default` and `.__esModule` handling for better interoperability, but it doesn't match the production behaviour when loaded by the runtime environment (e.g. Node.js), causing hard-to-catch inconsistencies. By default, all direct project dependencies are SSR externalized.

Vite 5 now removes the `.default` and `.__esModule` handling to match the production behaviour. In practice, this shouldn't affect properly-packaged dependencies, but if you encounter new issues loading modules, you can try these refactors:

```js
// Before:
import { foo } from 'bar'

// After:
import _bar from 'bar'
const { foo } = _bar
```

```js
// Before:
import foo from 'bar'

// After:
import * as _foo from 'bar'
const foo = _foo.default
```

Note that these changes matches the Node.js behaviour, so you can also run the imports in Node.js to test it out. If you prefer to stick with the previous behaviour, you can set `legacy.proxySsrExternalModules` to `true`.

### `worker.plugins` is now a function

In Vite 4, `worker.plugins` accepted an array of plugins (`(Plugin | Plugin[])[]`). From Vite 5, it needs to be configured as a function that returns an array of plugins (`() => (Plugin | Plugin[])[]`). This change is required so parallel worker builds run more consistently and predictably.
Expand Down
44 changes: 16 additions & 28 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ import {
createFilter,
isBuiltin,
isExternalUrl,
isFilePathESM,
isNodeBuiltin,
isObject,
lookupFile,
mergeAlias,
mergeConfig,
normalizeAlias,
Expand Down Expand Up @@ -314,8 +314,16 @@ export interface ExperimentalOptions {

export interface LegacyOptions {
/**
* No longer needed for now, but kept for backwards compatibility.
* In Vite 4, SSR-externalized modules (modules not bundled and loaded by Node.js at runtime)
* are implicitly proxied in dev to automatically handle `default` and `__esModule` access.
* However, this does not correctly reflect how it works in the Node.js runtime, causing
* inconsistencies between dev and prod.
*
* In Vite 5, the proxy is removed so dev and prod are consistent, but if you still require
* the old behaviour, you can enable this option. If so, please leave your feedback at
* https://github.com/vitejs/vite/discussions/14697.
*/
proxySsrExternalModules?: boolean
}

export interface ResolvedWorkerOptions {
Expand Down Expand Up @@ -978,19 +986,7 @@ export async function loadConfigFromFile(
return null
}

let isESM = false
if (/\.m[jt]s$/.test(resolvedPath)) {
isESM = true
} else if (/\.c[jt]s$/.test(resolvedPath)) {
isESM = false
} else {
// check package.json for type: "module" and set `isESM` to true
try {
const pkg = lookupFile(configRoot, ['package.json'])
isESM =
!!pkg && JSON.parse(fs.readFileSync(pkg, 'utf-8')).type === 'module'
} catch (e) {}
}
const isESM = isFilePathESM(resolvedPath)

try {
const bundled = await bundleConfigFile(resolvedPath, isESM)
Expand Down Expand Up @@ -1076,18 +1072,6 @@ async function bundleConfigFile(
false,
)?.id
}
const isESMFile = (id: string): boolean => {
if (id.endsWith('.mjs')) return true
if (id.endsWith('.cjs')) return false

const nearestPackageJson = findNearestPackageData(
path.dirname(id),
packageCache,
)
return (
!!nearestPackageJson && nearestPackageJson.data.type === 'module'
)
}

// externalize bare imports
build.onResolve(
Expand Down Expand Up @@ -1135,7 +1119,11 @@ async function bundleConfigFile(
if (idFsPath && isImport) {
idFsPath = pathToFileURL(idFsPath).href
}
if (idFsPath && !isImport && isESMFile(idFsPath)) {
if (
idFsPath &&
!isImport &&
isFilePathESM(idFsPath, packageCache)
) {
throw new Error(
`${JSON.stringify(
id,
Expand Down
10 changes: 2 additions & 8 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
isBuiltin,
isDataUrl,
isExternalUrl,
isFilePathESM,
isInNodeModules,
isNonDriveRelativeAbsolutePath,
isObject,
Expand Down Expand Up @@ -822,8 +823,6 @@ export function tryNodeResolve(
})
}

const ext = path.extname(resolved)

if (
!options.ssrOptimizeCheck &&
(!isInNodeModules(resolved) || // linked
Expand Down Expand Up @@ -859,12 +858,7 @@ export function tryNodeResolve(
(!options.ssrOptimizeCheck && !isBuild && ssr) ||
// Only optimize non-external CJS deps during SSR by default
(ssr &&
!(
ext === '.cjs' ||
(ext === '.js' &&
findNearestPackageData(path.dirname(resolved), options.packageCache)
?.data.type !== 'module')
) &&
isFilePathESM(resolved, options.packageCache) &&
!(include?.includes(pkgId) || include?.includes(id)))

if (options.ssrOptimizeCheck) {
Expand Down

0 comments on commit 5786837

Please sign in to comment.