diff --git a/commonjs-extension-resolution-loader/loader.js b/commonjs-extension-resolution-loader/loader.js index 1ba18cd..cdf0fc8 100644 --- a/commonjs-extension-resolution-loader/loader.js +++ b/commonjs-extension-resolution-loader/loader.js @@ -1,27 +1,34 @@ -import { existsSync } from 'fs'; -import { createRequire } from 'module'; +import { builtinModules } from 'node:module'; import { dirname } from 'path'; -import { URL, fileURLToPath, pathToFileURL } from 'url'; +import { cwd } from 'process'; +import { fileURLToPath, pathToFileURL } from 'url'; +import { promisify } from 'util'; -const require = createRequire(import.meta.url); -const baseURL = pathToFileURL(process.cwd() + '/').href; +import resolveCallback from 'resolve/async.js'; -export function resolve(specifier, context, defaultResolve) { +const resolveAsync = promisify(resolveCallback); + +const baseURL = pathToFileURL(cwd() + '/').href; + + +export async function resolve(specifier, context, next) { const { parentURL = baseURL } = context; - // `require.resolve` works with paths, not URLs, so convert to and from + if (specifier.startsWith('node:') || builtinModules.includes(specifier)) { + return next(specifier, context); + } + + // `resolveAsync` works with paths, not URLs if (specifier.startsWith('file://')) { specifier = fileURLToPath(specifier); } - const basePath = dirname(fileURLToPath(parentURL)); - const resolvedPath = require.resolve(specifier, {paths: [basePath]}); + const parentPath = fileURLToPath(parentURL); - if (existsSync(resolvedPath)) { - return { - url: pathToFileURL(resolvedPath).href - }; - } + const resolution = await resolveAsync(specifier, { + basedir: dirname(parentPath), + extensions: ['.js', '.json', '.node'], + }); + const url = pathToFileURL(resolution).href; - // Let Node.js handle all other specifiers, such as package names - return defaultResolve(specifier, context, defaultResolve); + return next(url, context); } diff --git a/commonjs-extension-resolution-loader/package-lock.json b/commonjs-extension-resolution-loader/package-lock.json new file mode 100644 index 0000000..2e22ac1 --- /dev/null +++ b/commonjs-extension-resolution-loader/package-lock.json @@ -0,0 +1,118 @@ +{ + "name": "commonjs-extension-resolution-loader", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "commonjs-extension-resolution-loader", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "resolve": "^1.22.1" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + } + }, + "dependencies": { + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "requires": { + "has": "^1.0.3" + } + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + } + } +} diff --git a/commonjs-extension-resolution-loader/package.json b/commonjs-extension-resolution-loader/package.json index 9cbd4ca..d1b47ad 100644 --- a/commonjs-extension-resolution-loader/package.json +++ b/commonjs-extension-resolution-loader/package.json @@ -8,6 +8,9 @@ "start": "npm test", "test": "node test.js" }, - "author": "Geoffrey Booth ", - "license": "MIT" + "author": "Geoffrey Booth ", + "license": "MIT", + "dependencies": { + "resolve": "^1.22.1" + } } diff --git a/commonjs-extension-resolution-loader/test.js b/commonjs-extension-resolution-loader/test.js index a0802f5..6a17e47 100644 --- a/commonjs-extension-resolution-loader/test.js +++ b/commonjs-extension-resolution-loader/test.js @@ -1,25 +1,25 @@ -import { ok } from 'assert'; +import { match } from 'assert'; import { spawn } from 'child_process'; import { execPath } from 'process'; // Run this test yourself with debugging mode via: -// node --inspect-brk --experimental-loader ./loader.js ./fixtures/index.js +// node --inspect-brk --loader ./loader.js ./fixtures/index.js const child = spawn(execPath, [ - '--experimental-loader', + '--loader', './loader.js', './fixtures/index.js' ]); let stdout = ''; child.stdout.setEncoding('utf8'); -child.stdout.on('data', (data) => { +child.stdout.on('data', data => { stdout += data; }); -child.on('close', (code, signal) => { - stdout = stdout.toString(); - ok(stdout.includes('hello from file.js')); - ok(stdout.includes('hello from folder/index.js')); +child.on('close', (_code, _signal) => { + stdout = stdout.toString(); + match(stdout, /hello from file\.js/); + match(stdout, /hello from folder\/index\.js/); });