module: fix legacy node specifier resolution to resolve "main" field

PR-URL: https://github.com/nodejs/node/pull/38979
Backport-PR-URL: https://github.com/nodejs/node/pull/39497
Fixes: https://github.com/nodejs/node/issues/32103
Fixes: https://github.com/nodejs/node/issues/38739
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
This commit is contained in:
Antoine du Hamel 2021-06-09 12:51:41 +02:00 committed by Richard Lau
parent ddc8dde150
commit 3e4bc1b0d3
No known key found for this signature in database
GPG Key ID: C43CEC45C17AB93C
4 changed files with 27 additions and 6 deletions

View File

@ -30,7 +30,7 @@ const {
Stats,
} = require('fs');
const { getOptionValue } = require('internal/options');
const { sep, relative } = require('path');
const { sep, relative, resolve } = require('path');
const preserveSymlinks = getOptionValue('--preserve-symlinks');
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
const typeFlag = getOptionValue('--input-type');
@ -160,16 +160,18 @@ function getPackageScopeConfig(resolved) {
return packageConfig;
}
/*
/**
* Legacy CommonJS main resolution:
* 1. let M = pkg_url + (json main field)
* 2. TRY(M, M.js, M.json, M.node)
* 3. TRY(M/index.js, M/index.json, M/index.node)
* 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
* 5. NOT_FOUND
* @param {string | URL} url
* @returns {boolean}
*/
function fileExists(url) {
return tryStatSync(fileURLToPath(url)).isFile();
return tryStatSync(url).isFile();
}
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
@ -236,7 +238,19 @@ function resolveExtensions(search) {
return undefined;
}
function resolveIndex(search) {
function resolveDirectoryEntry(search) {
const dirPath = fileURLToPath(search);
const pkgJsonPath = resolve(dirPath, 'package.json');
if (fileExists(pkgJsonPath)) {
const pkgJson = packageJsonReader.read(pkgJsonPath);
if (pkgJson.containsKeys) {
const { main } = JSONParse(pkgJson.string);
if (main != null) {
const mainUrl = pathToFileURL(resolve(dirPath, main));
return resolveExtensionsWithTryExactName(mainUrl);
}
}
}
return resolveExtensions(new URL('index', search));
}
@ -252,10 +266,10 @@ function finalizeResolution(resolved, base) {
let file = resolveExtensionsWithTryExactName(resolved);
if (file !== undefined) return file;
if (!StringPrototypeEndsWith(path, '/')) {
file = resolveIndex(new URL(`${resolved}/`));
file = resolveDirectoryEntry(new URL(`${resolved}/`));
if (file !== undefined) return file;
} else {
return resolveIndex(resolved) || resolved;
return resolveDirectoryEntry(resolved) || resolved;
}
throw new ERR_MODULE_NOT_FOUND(
resolved.pathname, fileURLToPath(base), 'module');

View File

@ -6,12 +6,15 @@ import assert from 'assert';
import commonjs from '../fixtures/es-module-specifiers/package-type-commonjs';
// esm index.js
import module from '../fixtures/es-module-specifiers/package-type-module';
// Directory entry with main.js
import main from '../fixtures/es-module-specifiers/dir-with-main';
// Notice the trailing slash
import success, { explicit, implicit, implicitModule }
from '../fixtures/es-module-specifiers/';
assert.strictEqual(commonjs, 'commonjs');
assert.strictEqual(module, 'module');
assert.strictEqual(main, 'main');
assert.strictEqual(success, 'success');
assert.strictEqual(explicit, 'esm');
assert.strictEqual(implicit, 'cjs');

View File

@ -0,0 +1 @@
module.exports = 'main';

View File

@ -0,0 +1,3 @@
{
"main": "./main.js"
}