esm: deprecate legacy main lookup for modules
PR-URL: https://github.com/nodejs/node/pull/36918 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
parent
fd02dace6f
commit
255d6337cd
@ -2726,10 +2726,28 @@ settings set when the Node.js binary was compiled. However, the property has
|
|||||||
been mutable by user code making it impossible to rely on. The ability to
|
been mutable by user code making it impossible to rely on. The ability to
|
||||||
change the value has been deprecated and will be disabled in the future.
|
change the value has been deprecated and will be disabled in the future.
|
||||||
|
|
||||||
|
### DEP0XXX: Main index lookup and extension searching
|
||||||
|
<!-- YAML
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/36918
|
||||||
|
description: Documentation-only deprecation
|
||||||
|
with `--pending-deprecation` support.
|
||||||
|
-->
|
||||||
|
|
||||||
|
Type: Documentation-only (supports [`--pending-deprecation`][])
|
||||||
|
|
||||||
|
Previously, `index.js` and extension searching lookups would apply to
|
||||||
|
`import 'pkg'` main entry point resolution, even when resolving ES modules.
|
||||||
|
|
||||||
|
With this deprecation, all ES module main entry point resolutions require
|
||||||
|
an explicit [`"exports"` or `"main"` entry][] with the exact file extension.
|
||||||
|
|
||||||
[Legacy URL API]: url.md#url_legacy_url_api
|
[Legacy URL API]: url.md#url_legacy_url_api
|
||||||
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
|
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
|
||||||
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
|
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
|
||||||
[WHATWG URL API]: url.md#url_the_whatwg_url_api
|
[WHATWG URL API]: url.md#url_the_whatwg_url_api
|
||||||
|
[`"exports"` or `"main"` entry]: packages.md#packages_main_entry_point_export
|
||||||
[`--pending-deprecation`]: cli.md#cli_pending_deprecation
|
[`--pending-deprecation`]: cli.md#cli_pending_deprecation
|
||||||
[`--throw-deprecation`]: cli.md#cli_throw_deprecation
|
[`--throw-deprecation`]: cli.md#cli_throw_deprecation
|
||||||
[`--unhandled-rejections`]: cli.md#cli_unhandled_rejections_mode
|
[`--unhandled-rejections`]: cli.md#cli_unhandled_rejections_mode
|
||||||
@ -2852,7 +2870,7 @@ change the value has been deprecated and will be disabled in the future.
|
|||||||
[from_string_encoding]: buffer.md#buffer_static_method_buffer_from_string_encoding
|
[from_string_encoding]: buffer.md#buffer_static_method_buffer_from_string_encoding
|
||||||
[legacy `urlObject`]: url.md#url_legacy_urlobject
|
[legacy `urlObject`]: url.md#url_legacy_urlobject
|
||||||
[static methods of `crypto.Certificate()`]: crypto.md#crypto_class_certificate
|
[static methods of `crypto.Certificate()`]: crypto.md#crypto_class_certificate
|
||||||
[subpath exports]: #packages_subpath_exports
|
[subpath exports]: packages.md#packages_subpath_exports
|
||||||
[subpath folder mappings]: #packages_subpath_folder_mappings
|
[subpath folder mappings]: packages.md#packages_subpath_folder_mappings
|
||||||
[subpath imports]: #packages_subpath_imports
|
[subpath imports]: packages.md#packages_subpath_imports
|
||||||
[subpath patterns]: #packages_subpath_patterns
|
[subpath patterns]: packages.md#packages_subpath_patterns
|
||||||
|
@ -90,6 +90,36 @@ function emitFolderMapDeprecation(match, pjsonUrl, isExports, base) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
|
||||||
|
if (!pendingDeprecation)
|
||||||
|
return;
|
||||||
|
const { format } = defaultGetFormat(url);
|
||||||
|
if (format !== 'module')
|
||||||
|
return;
|
||||||
|
const path = fileURLToPath(url);
|
||||||
|
const pkgPath = fileURLToPath(new URL('.', packageJSONUrl));
|
||||||
|
const basePath = fileURLToPath(base);
|
||||||
|
if (main)
|
||||||
|
process.emitWarning(
|
||||||
|
`Package ${pkgPath} has a "main" field set to ${JSONStringify(main)}, ` +
|
||||||
|
`excluding the full filename and extension to the resolved file at "${
|
||||||
|
StringPrototypeSlice(path, pkgPath.length)}", imported from ${
|
||||||
|
basePath}.\n Automatic extension resolution of the "main" field is` +
|
||||||
|
'deprecated for ES modules.',
|
||||||
|
'DeprecationWarning',
|
||||||
|
'DEP0150'
|
||||||
|
);
|
||||||
|
else
|
||||||
|
process.emitWarning(
|
||||||
|
`No "main" or "exports" field defined in the package.json for ${pkgPath
|
||||||
|
} resolving the main entry point "${
|
||||||
|
StringPrototypeSlice(path, pkgPath.length)}", imported from ${basePath
|
||||||
|
}.\nDefault "index" lookups for the main are deprecated for ES modules.`,
|
||||||
|
'DeprecationWarning',
|
||||||
|
'DEP0150'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function getConditionsSet(conditions) {
|
function getConditionsSet(conditions) {
|
||||||
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
|
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
|
||||||
if (!ArrayIsArray(conditions)) {
|
if (!ArrayIsArray(conditions)) {
|
||||||
@ -209,41 +239,33 @@ function legacyMainResolve(packageJSONUrl, packageConfig, base) {
|
|||||||
if (fileExists(guess = new URL(`./${packageConfig.main}`,
|
if (fileExists(guess = new URL(`./${packageConfig.main}`,
|
||||||
packageJSONUrl))) {
|
packageJSONUrl))) {
|
||||||
return guess;
|
return guess;
|
||||||
}
|
} else if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
|
||||||
if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
|
packageJSONUrl)));
|
||||||
packageJSONUrl))) {
|
else if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
|
||||||
return guess;
|
packageJSONUrl)));
|
||||||
}
|
else if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
|
||||||
if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
|
packageJSONUrl)));
|
||||||
packageJSONUrl))) {
|
else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
|
||||||
return guess;
|
packageJSONUrl)));
|
||||||
}
|
else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
|
||||||
if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
|
packageJSONUrl)));
|
||||||
packageJSONUrl))) {
|
else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
|
||||||
return guess;
|
packageJSONUrl)));
|
||||||
}
|
else guess = undefined;
|
||||||
if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
|
if (guess) {
|
||||||
packageJSONUrl))) {
|
emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
|
||||||
return guess;
|
packageConfig.main);
|
||||||
}
|
|
||||||
if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
|
|
||||||
packageJSONUrl))) {
|
|
||||||
return guess;
|
|
||||||
}
|
|
||||||
if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
|
|
||||||
packageJSONUrl))) {
|
|
||||||
return guess;
|
return guess;
|
||||||
}
|
}
|
||||||
// Fallthrough.
|
// Fallthrough.
|
||||||
}
|
}
|
||||||
if (fileExists(guess = new URL('./index.js', packageJSONUrl))) {
|
if (fileExists(guess = new URL('./index.js', packageJSONUrl)));
|
||||||
return guess;
|
|
||||||
}
|
|
||||||
// So fs.
|
// So fs.
|
||||||
if (fileExists(guess = new URL('./index.json', packageJSONUrl))) {
|
else if (fileExists(guess = new URL('./index.json', packageJSONUrl)));
|
||||||
return guess;
|
else if (fileExists(guess = new URL('./index.node', packageJSONUrl)));
|
||||||
}
|
else guess = undefined;
|
||||||
if (fileExists(guess = new URL('./index.node', packageJSONUrl))) {
|
if (guess) {
|
||||||
|
emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
|
||||||
return guess;
|
return guess;
|
||||||
}
|
}
|
||||||
// Not found.
|
// Not found.
|
||||||
@ -891,3 +913,6 @@ module.exports = {
|
|||||||
packageExportsResolve,
|
packageExportsResolve,
|
||||||
packageImportsResolve
|
packageImportsResolve
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// cycle
|
||||||
|
const { defaultGetFormat } = require('internal/modules/esm/get_format');
|
||||||
|
@ -6,7 +6,9 @@ let curWarning = 0;
|
|||||||
const expectedWarnings = [
|
const expectedWarnings = [
|
||||||
'"./sub/"',
|
'"./sub/"',
|
||||||
'"./fallbackdir/"',
|
'"./fallbackdir/"',
|
||||||
'"./subpath/"'
|
'"./subpath/"',
|
||||||
|
'no_exports',
|
||||||
|
'default_index'
|
||||||
];
|
];
|
||||||
|
|
||||||
process.addListener('warning', mustCall((warning) => {
|
process.addListener('warning', mustCall((warning) => {
|
||||||
|
@ -35,7 +35,7 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js';
|
|||||||
['pkgexports-sugar', { default: 'main' }],
|
['pkgexports-sugar', { default: 'main' }],
|
||||||
// Path patterns
|
// Path patterns
|
||||||
['pkgexports/subpath/sub-dir1', { default: 'main' }],
|
['pkgexports/subpath/sub-dir1', { default: 'main' }],
|
||||||
['pkgexports/features/dir1', { default: 'main' }]
|
['pkgexports/features/dir1', { default: 'main' }],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (isRequire) {
|
if (isRequire) {
|
||||||
@ -44,6 +44,11 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js';
|
|||||||
validSpecifiers.set('pkgexports/subpath/dir1/', { default: 'main' });
|
validSpecifiers.set('pkgexports/subpath/dir1/', { default: 'main' });
|
||||||
validSpecifiers.set('pkgexports/subpath/dir2', { default: 'index' });
|
validSpecifiers.set('pkgexports/subpath/dir2', { default: 'index' });
|
||||||
validSpecifiers.set('pkgexports/subpath/dir2/', { default: 'index' });
|
validSpecifiers.set('pkgexports/subpath/dir2/', { default: 'index' });
|
||||||
|
} else {
|
||||||
|
// No exports or main field
|
||||||
|
validSpecifiers.set('no_exports', { default: 'index' });
|
||||||
|
// Main field without extension
|
||||||
|
validSpecifiers.set('default_index', { default: 'main' });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [validSpecifier, expected] of validSpecifiers) {
|
for (const [validSpecifier, expected] of validSpecifiers) {
|
||||||
|
1
test/fixtures/node_modules/default_index/index.js
generated
vendored
Normal file
1
test/fixtures/node_modules/default_index/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default 'main'
|
4
test/fixtures/node_modules/default_index/package.json
generated
vendored
Normal file
4
test/fixtures/node_modules/default_index/package.json
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"main": "index",
|
||||||
|
"type": "module"
|
||||||
|
}
|
1
test/fixtures/node_modules/no_exports/index.js
generated
vendored
Normal file
1
test/fixtures/node_modules/no_exports/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default 'index'
|
3
test/fixtures/node_modules/no_exports/package.json
generated
vendored
Normal file
3
test/fixtures/node_modules/no_exports/package.json
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user