From 001d0e640938120c1fe777f359fcc26c9bfe15f7 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 21 May 2023 19:58:21 +0900 Subject: [PATCH 1/2] feat(config): friendly ESM file require error --- docs/guide/troubleshooting.md | 17 ++++++ packages/vite/src/node/config.ts | 99 +++++++++++++++++++++++--------- 2 files changed, 89 insertions(+), 27 deletions(-) diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md index c9eeab879c5c5a..7e539412b193a0 100644 --- a/docs/guide/troubleshooting.md +++ b/docs/guide/troubleshooting.md @@ -15,6 +15,23 @@ You will need to either: - Switch to another package manager (e.g. `pnpm`, `yarn`) - Remove `&` from the path to your project +## Config + +### This package is ESM only + +When importing a ESM only package by `require`, the following error happens. + +> Failed to resolve "foo". This package is ESM only but it was tried to load by `require`. + +> "foo" resolved to an ESM file. ESM file cannot be loaded by `require`. + +ESM files cannot be loaded by [`require`](). + +We recommend converting your config to ESM by either: + +- adding `"type": "module"` to the nearest `package.json` +- renaming `vite.config.js`/`vite.config.ts` to `vite.config.mjs`/`vite.config.mts` + ## Dev Server ### Requests are stalled forever diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 1933a5484b7565..65be05ed539956 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -51,11 +51,7 @@ import { ENV_ENTRY, FS_PREFIX, } from './constants' -import type { - InternalResolveOptions, - InternalResolveOptionsWithOverrideConditions, - ResolveOptions, -} from './plugins/resolve' +import type { InternalResolveOptions, ResolveOptions } from './plugins/resolve' import { resolvePlugin, tryNodeResolve } from './plugins/resolve' import type { LogLevel, Logger } from './logger' import { createLogger } from './logger' @@ -998,20 +994,45 @@ async function bundleConfigFile( { name: 'externalize-deps', setup(build) { - const options: InternalResolveOptionsWithOverrideConditions = { - root: path.dirname(fileName), - isBuild: true, - isProduction: true, - preferRelative: false, - tryIndex: true, - mainFields: [], - browserField: false, - conditions: [], - overrideConditions: ['node'], - dedupe: [], - extensions: DEFAULT_EXTENSIONS, - preserveSymlinks: false, - packageCache: new Map(), + const packageCache = new Map() + const resolveByViteResolver = ( + id: string, + importer: string, + require: boolean, + ) => { + return tryNodeResolve( + id, + importer, + { + root: path.dirname(fileName), + isBuild: true, + isProduction: true, + preferRelative: false, + tryIndex: true, + mainFields: [], + browserField: false, + conditions: [], + overrideConditions: ['node'], + dedupe: [], + extensions: DEFAULT_EXTENSIONS, + preserveSymlinks: false, + packageCache, + isRequire: require, + }, + 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 @@ -1031,16 +1052,40 @@ async function bundleConfigFile( return { external: true } } - const isIdESM = isESM || kind === 'dynamic-import' - let idFsPath = tryNodeResolve( - id, - importer, - { ...options, isRequire: !isIdESM }, - false, - )?.id - if (idFsPath && isIdESM) { + const isImport = isESM || kind === 'dynamic-import' + let idFsPath: string | undefined + try { + idFsPath = resolveByViteResolver(id, importer, !isImport) + } catch (e) { + if (!isImport) { + let canResolveWithRequire = false + try { + canResolveWithRequire = !!resolveByViteResolver( + id, + importer, + false, + ) + } catch {} + if (canResolveWithRequire) { + throw new Error( + `Failed to resolve ${JSON.stringify( + id, + )}. 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.`, + ) + } + } + throw e + } + if (idFsPath && isImport) { idFsPath = pathToFileURL(idFsPath).href } + if (idFsPath && !isImport && isESMFile(idFsPath)) { + throw new Error( + `${JSON.stringify( + id, + )} 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.`, + ) + } return { path: idFsPath, external: true, From bdc7797fab924e5406c8df996117a4b72cb94509 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 23 May 2023 17:44:10 +0900 Subject: [PATCH 2/2] refactor: rename vars --- packages/vite/src/node/config.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 65be05ed539956..3f4f06ee8368e6 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -998,7 +998,7 @@ async function bundleConfigFile( const resolveByViteResolver = ( id: string, importer: string, - require: boolean, + isRequire: boolean, ) => { return tryNodeResolve( id, @@ -1017,7 +1017,7 @@ async function bundleConfigFile( extensions: DEFAULT_EXTENSIONS, preserveSymlinks: false, packageCache, - isRequire: require, + isRequire, }, false, )?.id @@ -1058,15 +1058,15 @@ async function bundleConfigFile( idFsPath = resolveByViteResolver(id, importer, !isImport) } catch (e) { if (!isImport) { - let canResolveWithRequire = false + let canResolveWithImport = false try { - canResolveWithRequire = !!resolveByViteResolver( + canResolveWithImport = !!resolveByViteResolver( id, importer, false, ) } catch {} - if (canResolveWithRequire) { + if (canResolveWithImport) { throw new Error( `Failed to resolve ${JSON.stringify( id,