diff options
author | Bradley Farias <bradley.meck@gmail.com> | 2022-03-15 03:59:32 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-15 03:59:32 +0300 |
commit | a01302b8dfaa9aa6290cd6bee552c4ce30dca34c (patch) | |
tree | 1f4e9a42a536e2670a1494176869f2f34743f0e4 /lib | |
parent | 6f8c983f904ad6508f03e074524f40b2975c8cf6 (diff) |
esm: make extension-less errors in type:module actionable
PR-URL: https://github.com/nodejs/node/pull/42301
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/internal/errors.js | 10 | ||||
-rw-r--r-- | lib/internal/modules/esm/get_format.js | 22 | ||||
-rw-r--r-- | lib/internal/modules/esm/resolve.js | 8 |
3 files changed, 29 insertions, 11 deletions
diff --git a/lib/internal/errors.js b/lib/internal/errors.js index c0834aab9c0..dce159b94cc 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1594,9 +1594,13 @@ E('ERR_UNHANDLED_ERROR', E('ERR_UNKNOWN_BUILTIN_MODULE', 'No such built-in module: %s', Error); E('ERR_UNKNOWN_CREDENTIAL', '%s identifier does not exist: %s', Error); E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError); -E('ERR_UNKNOWN_FILE_EXTENSION', - 'Unknown file extension "%s" for %s', - TypeError); +E('ERR_UNKNOWN_FILE_EXTENSION', (ext, path, suggestion) => { + let msg = `Unknown file extension "${ext}" for ${path}`; + if (suggestion) { + msg += `. ${suggestion}`; + } + return msg; +}, TypeError); E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s for URL %s', RangeError); E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError); diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js index 91f3c9edeb1..950a769227c 100644 --- a/lib/internal/modules/esm/get_format.js +++ b/lib/internal/modules/esm/get_format.js @@ -6,8 +6,9 @@ const { ObjectPrototypeHasOwnProperty, PromisePrototypeThen, PromiseResolve, + StringPrototypeSlice, } = primordials; -const { extname } = require('path'); +const { basename, extname, relative } = require('path'); const { getOptionValue } = require('internal/options'); const { fetchModule } = require('internal/modules/esm/fetch_module'); const { @@ -20,7 +21,7 @@ const experimentalNetworkImports = getOptionValue('--experimental-network-imports'); const experimentalSpecifierResolution = getOptionValue('--experimental-specifier-resolution'); -const { getPackageType } = require('internal/modules/esm/resolve'); +const { getPackageType, getPackageScopeConfig } = require('internal/modules/esm/resolve'); const { URL, fileURLToPath } = require('internal/url'); const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes; @@ -52,7 +53,8 @@ function getDataProtocolModuleFormat(parsed) { * @returns {string} */ function getFileProtocolModuleFormat(url, context, ignoreErrors) { - const ext = extname(url.pathname); + const filepath = fileURLToPath(url); + const ext = extname(filepath); if (ext === '.js') { return getPackageType(url) === 'module' ? 'module' : 'commonjs'; } @@ -63,7 +65,19 @@ function getFileProtocolModuleFormat(url, context, ignoreErrors) { if (experimentalSpecifierResolution !== 'node') { // Explicit undefined return indicates load hook should rerun format check if (ignoreErrors) return undefined; - throw new ERR_UNKNOWN_FILE_EXTENSION(ext, fileURLToPath(url)); + let suggestion = ''; + if (getPackageType(url) === 'module' && ext === '') { + const config = getPackageScopeConfig(url); + const fileBasename = basename(filepath); + const relativePath = StringPrototypeSlice(relative(config.pjsonPath, filepath), 1); + suggestion = 'Loading extensionless files is not supported inside of ' + + '"type":"module" package.json contexts. The package.json file ' + + `${config.pjsonPath} caused this "type":"module" context. Try ` + + `changing ${filepath} to have a file extension. Note the "bin" ` + + 'field of package.json can point to a file with an extension, for example ' + + `{"type":"module","bin":{"${fileBasename}":"${relativePath}.js"}}`; + } + throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath, suggestion); } return getLegacyExtensionFormat(ext) ?? null; diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index 5e00b53a65f..59d3bc1723e 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -80,10 +80,10 @@ const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS); * @typedef {'module' | 'commonjs'} PackageType * @typedef {{ * pjsonPath: string, - * exports?: ExportConfig; - * name?: string; - * main?: string; - * type?: PackageType; + * exports?: ExportConfig, + * name?: string, + * main?: string, + * type?: PackageType, * }} PackageConfig */ |