Skip to content

Commit b9a6ba0

Browse files
authoredJun 6, 2023
feat(config): friendly ESM file require error (#13283)
1 parent a11b6f6 commit b9a6ba0

File tree

2 files changed

+89
-27
lines changed

2 files changed

+89
-27
lines changed
 

‎docs/guide/troubleshooting.md

+17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@ You will need to either:
1515
- Switch to another package manager (e.g. `pnpm`, `yarn`)
1616
- Remove `&` from the path to your project
1717

18+
## Config
19+
20+
### This package is ESM only
21+
22+
When importing a ESM only package by `require`, the following error happens.
23+
24+
> Failed to resolve "foo". This package is ESM only but it was tried to load by `require`.
25+
26+
> "foo" resolved to an ESM file. ESM file cannot be loaded by `require`.
27+
28+
ESM files cannot be loaded by [`require`](<https://nodejs.org/docs/latest-v18.x/api/esm.html#require:~:text=Using%20require%20to%20load%20an%20ES%20module%20is%20not%20supported%20because%20ES%20modules%20have%20asynchronous%20execution.%20Instead%2C%20use%20import()%20to%20load%20an%20ES%20module%20from%20a%20CommonJS%20module.>).
29+
30+
We recommend converting your config to ESM by either:
31+
32+
- adding `"type": "module"` to the nearest `package.json`
33+
- renaming `vite.config.js`/`vite.config.ts` to `vite.config.mjs`/`vite.config.mts`
34+
1835
## Dev Server
1936

2037
### Requests are stalled forever

‎packages/vite/src/node/config.ts

+72-27
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,7 @@ import {
5151
ENV_ENTRY,
5252
FS_PREFIX,
5353
} from './constants'
54-
import type {
55-
InternalResolveOptions,
56-
InternalResolveOptionsWithOverrideConditions,
57-
ResolveOptions,
58-
} from './plugins/resolve'
54+
import type { InternalResolveOptions, ResolveOptions } from './plugins/resolve'
5955
import { resolvePlugin, tryNodeResolve } from './plugins/resolve'
6056
import type { LogLevel, Logger } from './logger'
6157
import { createLogger } from './logger'
@@ -1003,20 +999,45 @@ async function bundleConfigFile(
1003999
{
10041000
name: 'externalize-deps',
10051001
setup(build) {
1006-
const options: InternalResolveOptionsWithOverrideConditions = {
1007-
root: path.dirname(fileName),
1008-
isBuild: true,
1009-
isProduction: true,
1010-
preferRelative: false,
1011-
tryIndex: true,
1012-
mainFields: [],
1013-
browserField: false,
1014-
conditions: [],
1015-
overrideConditions: ['node'],
1016-
dedupe: [],
1017-
extensions: DEFAULT_EXTENSIONS,
1018-
preserveSymlinks: false,
1019-
packageCache: new Map(),
1002+
const packageCache = new Map()
1003+
const resolveByViteResolver = (
1004+
id: string,
1005+
importer: string,
1006+
isRequire: boolean,
1007+
) => {
1008+
return tryNodeResolve(
1009+
id,
1010+
importer,
1011+
{
1012+
root: path.dirname(fileName),
1013+
isBuild: true,
1014+
isProduction: true,
1015+
preferRelative: false,
1016+
tryIndex: true,
1017+
mainFields: [],
1018+
browserField: false,
1019+
conditions: [],
1020+
overrideConditions: ['node'],
1021+
dedupe: [],
1022+
extensions: DEFAULT_EXTENSIONS,
1023+
preserveSymlinks: false,
1024+
packageCache,
1025+
isRequire,
1026+
},
1027+
false,
1028+
)?.id
1029+
}
1030+
const isESMFile = (id: string): boolean => {
1031+
if (id.endsWith('.mjs')) return true
1032+
if (id.endsWith('.cjs')) return false
1033+
1034+
const nearestPackageJson = findNearestPackageData(
1035+
path.dirname(id),
1036+
packageCache,
1037+
)
1038+
return (
1039+
!!nearestPackageJson && nearestPackageJson.data.type === 'module'
1040+
)
10201041
}
10211042

10221043
// externalize bare imports
@@ -1036,16 +1057,40 @@ async function bundleConfigFile(
10361057
return { external: true }
10371058
}
10381059

1039-
const isIdESM = isESM || kind === 'dynamic-import'
1040-
let idFsPath = tryNodeResolve(
1041-
id,
1042-
importer,
1043-
{ ...options, isRequire: !isIdESM },
1044-
false,
1045-
)?.id
1046-
if (idFsPath && isIdESM) {
1060+
const isImport = isESM || kind === 'dynamic-import'
1061+
let idFsPath: string | undefined
1062+
try {
1063+
idFsPath = resolveByViteResolver(id, importer, !isImport)
1064+
} catch (e) {
1065+
if (!isImport) {
1066+
let canResolveWithImport = false
1067+
try {
1068+
canResolveWithImport = !!resolveByViteResolver(
1069+
id,
1070+
importer,
1071+
false,
1072+
)
1073+
} catch {}
1074+
if (canResolveWithImport) {
1075+
throw new Error(
1076+
`Failed to resolve ${JSON.stringify(
1077+
id,
1078+
)}. This package is ESM only but it was tried to load by \`require\`. See http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only for more details.`,
1079+
)
1080+
}
1081+
}
1082+
throw e
1083+
}
1084+
if (idFsPath && isImport) {
10471085
idFsPath = pathToFileURL(idFsPath).href
10481086
}
1087+
if (idFsPath && !isImport && isESMFile(idFsPath)) {
1088+
throw new Error(
1089+
`${JSON.stringify(
1090+
id,
1091+
)} resolved to an ESM file. ESM file cannot be loaded by \`require\`. See http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only for more details.`,
1092+
)
1093+
}
10491094
return {
10501095
path: idFsPath,
10511096
external: true,

0 commit comments

Comments
 (0)
Please sign in to comment.