Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
module: do not warn for typeless package.json when there isn't one
It was intended that warnings should only be emitted for an
existing package.json without a type. This fixes a confusing
warning telling users to update /package.json when there are
no package.json on the lookup path at all, like this:

[MODULE_TYPELESS_PACKAGE_JSON] Warning: ... parsed as an ES module
because module syntax was detected; to avoid the performance penalty
of syntax detection, add "type": "module" to /package.json

Drive-by: update the warning message to be clear about
reparsing and make it clear what's actionable.
  • Loading branch information
joyeecheung committed Jul 25, 2024
commit cf52a8bc6fddaec2bda9f3170017a3376c3afb3a
13 changes: 7 additions & 6 deletions lib/internal/modules/esm/get_format.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ let typelessPackageJsonFilesWarnedAbout;
function warnTypelessPackageJsonFile(pjsonPath, url) {
typelessPackageJsonFilesWarnedAbout ??= new SafeSet();
if (!typelessPackageJsonFilesWarnedAbout.has(pjsonPath)) {
const warning = `${url} parsed as an ES module because module syntax was detected;` +
` to avoid the performance penalty of syntax detection, add "type": "module" to ${pjsonPath}`;
const warning = `Module type of ${url} is not specified and it doesn't parse as CommonJS.\n` +
'Reparsing as ES module because module syntax was detected. This incurs a performance overhead.\n' +
`To eliminate this warning, add "type": "module" to ${pjsonPath}.`;
process.emitWarning(warning, {
code: 'MODULE_TYPELESS_PACKAGE_JSON',
});
Expand All @@ -118,7 +119,7 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
const ext = extname(url);

if (ext === '.js') {
const { type: packageType, pjsonPath } = getPackageScopeConfig(url);
const { type: packageType, pjsonPath, exists: foundPackageJson } = getPackageScopeConfig(url);
if (packageType !== 'none') {
return packageType;
}
Expand All @@ -139,7 +140,7 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
// For ambiguous files (no type field, .js extension) we return
// undefined from `resolve` and re-run the check in `load`.
const format = detectModuleFormat(source, url);
if (format === 'module') {
if (format === 'module' && foundPackageJson) {
// This module has a .js extension, a package.json with no `type` field, and ESM syntax.
// Warn about the missing `type` field so that the user can avoid the performance penalty of detection.
warnTypelessPackageJsonFile(pjsonPath, url);
Expand All @@ -149,7 +150,7 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
}
}
if (ext === '.ts' && getOptionValue('--experimental-strip-types')) {
const { type: packageType, pjsonPath } = getPackageScopeConfig(url);
const { type: packageType, pjsonPath, exists: foundPackageJson } = getPackageScopeConfig(url);
if (packageType !== 'none') {
return `${packageType}-typescript`;
}
Expand All @@ -170,7 +171,7 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
const parsedSource = tsParse(source);
const detectedFormat = detectModuleFormat(parsedSource, url);
const format = detectedFormat ? `${detectedFormat}-typescript` : 'commonjs-typescript';
if (format === 'module-typescript') {
if (format === 'module-typescript' && foundPackageJson) {
// This module has a .js extension, a package.json with no `type` field, and ESM syntax.
// Warn about the missing `type` field so that the user can avoid the performance penalty of detection.
warnTypelessPackageJsonFile(pjsonPath, url);
Expand Down
12 changes: 12 additions & 0 deletions test/es-module/test-esm-detect-ambiguous.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,18 @@ describe('Module syntax detection', { concurrency: !process.env.TEST_PARALLEL },
});
}

it('does not warn when there are no package.json', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
fixtures.path('es-modules/loose.js'),
]);

strictEqual(stderr, '');
strictEqual(stdout, 'executed\n');
strictEqual(code, 0);
strictEqual(signal, null);
});


it('warns only once for a package.json that affects multiple files', async () => {
const { stdout, stderr, code, signal } = await spawnPromisified(process.execPath, [
fixtures.path('es-modules/package-without-type/detected-as-esm.js'),
Expand Down