mirror of
https://github.com/nodejs/node.git
synced 2025-05-21 17:44:15 +00:00

This simplifies the top-level load when ES modules are enabled as we can entirely delegate the module resolver, which will hand over to CommonJS where appropriate. All not found errors are made consistent to throw during resolve and have the MODULE_NOT_FOUND code. Includes the test case from https://github.com/nodejs/node/pull/15736. Fixes: https://github.com/nodejs/node/issues/15732 PR-URL: https://github.com/nodejs/node/pull/16147 Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
130 lines
3.8 KiB
JavaScript
130 lines
3.8 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const internalCJSModule = require('internal/module');
|
|
const internalURLModule = require('internal/url');
|
|
const internalFS = require('internal/fs');
|
|
const NativeModule = require('native_module');
|
|
const { extname, _makeLong } = require('path');
|
|
const { URL } = require('url');
|
|
const { realpathSync } = require('fs');
|
|
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
|
const {
|
|
ModuleWrap,
|
|
createDynamicModule
|
|
} = require('internal/loader/ModuleWrap');
|
|
const errors = require('internal/errors');
|
|
|
|
const search = require('internal/loader/search');
|
|
const asyncReadFile = require('util').promisify(require('fs').readFile);
|
|
const debug = require('util').debuglog('esm');
|
|
|
|
const realpathCache = new Map();
|
|
|
|
const loaders = new Map();
|
|
exports.loaders = loaders;
|
|
|
|
// Strategy for loading a standard JavaScript module
|
|
loaders.set('esm', async (url) => {
|
|
const source = `${await asyncReadFile(new URL(url))}`;
|
|
debug(`Loading StandardModule ${url}`);
|
|
return {
|
|
module: new ModuleWrap(internalCJSModule.stripShebang(source), url),
|
|
reflect: undefined
|
|
};
|
|
});
|
|
|
|
// Strategy for loading a node-style CommonJS module
|
|
loaders.set('cjs', async (url) => {
|
|
return createDynamicModule(['default'], url, (reflect) => {
|
|
debug(`Loading CJSModule ${url}`);
|
|
const CJSModule = require('module');
|
|
const pathname = internalURLModule.getPathFromURL(new URL(url));
|
|
CJSModule._load(pathname);
|
|
});
|
|
});
|
|
|
|
// Strategy for loading a node builtin CommonJS module that isn't
|
|
// through normal resolution
|
|
loaders.set('builtin', async (url) => {
|
|
return createDynamicModule(['default'], url, (reflect) => {
|
|
debug(`Loading BuiltinModule ${url}`);
|
|
const exports = NativeModule.require(url.substr(5));
|
|
reflect.exports.default.set(exports);
|
|
});
|
|
});
|
|
|
|
loaders.set('addon', async (url) => {
|
|
const ctx = createDynamicModule(['default'], url, (reflect) => {
|
|
debug(`Loading NativeModule ${url}`);
|
|
const module = { exports: {} };
|
|
const pathname = internalURLModule.getPathFromURL(new URL(url));
|
|
process.dlopen(module, _makeLong(pathname));
|
|
reflect.exports.default.set(module.exports);
|
|
});
|
|
return ctx;
|
|
});
|
|
|
|
loaders.set('json', async (url) => {
|
|
return createDynamicModule(['default'], url, (reflect) => {
|
|
debug(`Loading JSONModule ${url}`);
|
|
const pathname = internalURLModule.getPathFromURL(new URL(url));
|
|
const content = fs.readFileSync(pathname, 'utf8');
|
|
try {
|
|
const exports = JSON.parse(internalCJSModule.stripBOM(content));
|
|
reflect.exports.default.set(exports);
|
|
} catch (err) {
|
|
err.message = pathname + ': ' + err.message;
|
|
throw err;
|
|
}
|
|
});
|
|
});
|
|
|
|
exports.resolve = (specifier, parentURL) => {
|
|
if (NativeModule.nonInternalExists(specifier)) {
|
|
return {
|
|
url: specifier,
|
|
format: 'builtin'
|
|
};
|
|
}
|
|
|
|
let url;
|
|
try {
|
|
url = search(specifier, parentURL);
|
|
} catch (e) {
|
|
if (e.message && e.message.startsWith('Cannot find module'))
|
|
e.code = 'MODULE_NOT_FOUND';
|
|
throw e;
|
|
}
|
|
|
|
if (url.protocol !== 'file:') {
|
|
throw new errors.Error('ERR_INVALID_PROTOCOL',
|
|
url.protocol, 'file:');
|
|
}
|
|
|
|
if (!preserveSymlinks) {
|
|
const real = realpathSync(internalURLModule.getPathFromURL(url), {
|
|
[internalFS.realpathCacheKey]: realpathCache
|
|
});
|
|
const old = url;
|
|
url = internalURLModule.getURLFromFilePath(real);
|
|
url.search = old.search;
|
|
url.hash = old.hash;
|
|
}
|
|
|
|
const ext = extname(url.pathname);
|
|
switch (ext) {
|
|
case '.mjs':
|
|
return { url: `${url}`, format: 'esm' };
|
|
case '.json':
|
|
return { url: `${url}`, format: 'json' };
|
|
case '.node':
|
|
return { url: `${url}`, format: 'addon' };
|
|
case '.js':
|
|
return { url: `${url}`, format: 'cjs' };
|
|
default:
|
|
throw new errors.Error('ERR_UNKNOWN_FILE_EXTENSION',
|
|
internalURLModule.getPathFromURL(url));
|
|
}
|
|
};
|