mirror of https://github.com/nodejs/node.git
module: expose `resolveLoadAndCache` API
This commit is contained in:
parent
6f12f1e500
commit
327af5a19c
|
@ -352,6 +352,34 @@ changes:
|
|||
Register a module that exports [hooks][] that customize Node.js module
|
||||
resolution and loading behavior. See [Customization hooks][].
|
||||
|
||||
### `module.resolveLoadAndCache(specifier[, parentURL[, importAttributes[, conditions]]])`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
* `specifier` {string|URL} Customization hooks to be registered; this should be
|
||||
the same string that would be passed to `import()`, except that if it is
|
||||
relative, it is resolved relative to `parentURL`.
|
||||
* `parentURL` {string|URL} If you want to resolve `specifier` relative to a base
|
||||
URL, such as `import.meta.url`, you can pass that URL here. **Default:**
|
||||
`'data:'`.
|
||||
* `importAttributes` {object}
|
||||
* `conditions` {Array}
|
||||
* Returns: {Promise} fulfills with an object with the following properties:
|
||||
* `url` {string} The absolute URL for that module
|
||||
* `format` {string} The format this module will be parsed as.
|
||||
* `source` {null|TypedArray}
|
||||
|
||||
This API tells you how a specific URL will be loaded by the ECMAScript loader if
|
||||
it was imported from the `parentURL` in the current process. If the module was
|
||||
already imported before `resolveLoadAndCache` is called, the cached version is
|
||||
returned; if not, it will populate the cache so future calls to
|
||||
`resolveLoadAndCache` or `import` do re-do the work.
|
||||
|
||||
|
||||
## `module.stripTypeScriptTypes(code[, options])`
|
||||
|
||||
<!-- YAML
|
||||
|
|
|
@ -26,7 +26,7 @@ const { pathToFileURL, fileURLToPath } = require('internal/url');
|
|||
const assert = require('internal/assert');
|
||||
|
||||
const { getOptionValue } = require('internal/options');
|
||||
const { setOwnProperty, getLazy } = require('internal/util');
|
||||
const { setOwnProperty, getLazy, kEmptyObject } = require('internal/util');
|
||||
const { inspect } = require('internal/util/inspect');
|
||||
|
||||
const lazyTmpdir = getLazy(() => require('os').tmpdir());
|
||||
|
@ -392,6 +392,24 @@ ObjectFreeze(compileCacheStatus);
|
|||
const constants = { __proto__: null, compileCacheStatus };
|
||||
ObjectFreeze(constants);
|
||||
|
||||
async function resolveLoadAndCache(specifier, base = 'data:', importAttributes = kEmptyObject, conditions) {
|
||||
const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader();
|
||||
// TODO: this should hit the cache (and populate it if it finds nothing)
|
||||
const { url, format: resolveFormat } = await cascadedLoader.resolve(`${specifier}`, `${base}`, importAttributes);
|
||||
const { format, source } = await cascadedLoader.load(url, {
|
||||
__proto__: null,
|
||||
importAttributes,
|
||||
format: resolveFormat,
|
||||
conditions,
|
||||
});
|
||||
return {
|
||||
__proto__: null,
|
||||
format,
|
||||
source,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the compile cache directory if on-disk compile cache is enabled.
|
||||
* @returns {string|undefined} Path to the module compile cache directory if it is enabled,
|
||||
|
@ -414,6 +432,7 @@ module.exports = {
|
|||
loadBuiltinModule,
|
||||
makeRequireFunction,
|
||||
normalizeReferrerURL,
|
||||
resolveLoadAndCache,
|
||||
stringify,
|
||||
stripBOM,
|
||||
toRealPath,
|
||||
|
|
|
@ -9,20 +9,22 @@ const {
|
|||
enableCompileCache,
|
||||
flushCompileCache,
|
||||
getCompileCacheDir,
|
||||
resolveLoadAndCache,
|
||||
} = require('internal/modules/helpers');
|
||||
const {
|
||||
findPackageJSON,
|
||||
} = require('internal/modules/package_json_reader');
|
||||
const { stripTypeScriptTypes } = require('internal/modules/typescript');
|
||||
|
||||
Module.findSourceMap = findSourceMap;
|
||||
Module.register = register;
|
||||
Module.SourceMap = SourceMap;
|
||||
Module.constants = constants;
|
||||
Module.enableCompileCache = enableCompileCache;
|
||||
Module.findPackageJSON = findPackageJSON;
|
||||
Module.findSourceMap = findSourceMap;
|
||||
Module.flushCompileCache = flushCompileCache;
|
||||
Module.getCompileCacheDir = getCompileCacheDir;
|
||||
Module.register = register;
|
||||
Module.resolveLoadAndCache = resolveLoadAndCache;
|
||||
Module.SourceMap = SourceMap;
|
||||
Module.stripTypeScriptTypes = stripTypeScriptTypes;
|
||||
|
||||
module.exports = Module;
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
'use strict';
|
||||
|
||||
const { spawnPromisified } = require('../common');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const assert = require('node:assert');
|
||||
const { resolveLoadAndCache } = require('node:module');
|
||||
const { describe, it } = require('node:test');
|
||||
|
||||
|
||||
describe('resolveLoadAndCache', () => { // Throws when no arguments are provided
|
||||
it('should return null source for CJS module and built-in modules', async () => {
|
||||
assert.deepStrictEqual(await resolveLoadAndCache(fixtures.fileURL('empty.js')), {
|
||||
__proto__: null,
|
||||
url: `${fixtures.fileURL('empty.js')}`,
|
||||
format: 'commonjs',
|
||||
source: null,
|
||||
});
|
||||
assert.deepStrictEqual(await resolveLoadAndCache('node:fs'), {
|
||||
__proto__: null,
|
||||
url: 'node:fs',
|
||||
format: 'builtin',
|
||||
source: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return full source for ESM module', async () => {
|
||||
assert.deepStrictEqual(await resolveLoadAndCache(fixtures.fileURL('es-modules/print-3.mjs')), {
|
||||
__proto__: null,
|
||||
url: `${fixtures.fileURL('es-modules/print-3.mjs')}`,
|
||||
format: 'module',
|
||||
source: Buffer.from('console.log(3);\n'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept relative path when a base URL is provided', async () => {
|
||||
assert.deepStrictEqual(await resolveLoadAndCache('./print-3.mjs', fixtures.fileURL('es-modules/loop.mjs')), {
|
||||
__proto__: null,
|
||||
url: `${fixtures.fileURL('es-modules/print-3.mjs')}`,
|
||||
format: 'module',
|
||||
source: Buffer.from('console.log(3);\n'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw when parentLocation is invalid', async () => {
|
||||
for (const invalid of [null, {}, [], () => {}, true, false, 1, 0]) {
|
||||
await assert.rejects(
|
||||
() => resolveLoadAndCache('', invalid),
|
||||
{ code: 'ERR_INVALID_URL' },
|
||||
);
|
||||
}
|
||||
|
||||
await assert.rejects(resolveLoadAndCache('', Symbol()), {
|
||||
name: 'TypeError',
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept a file URL (string), like from `import.meta.resolve()`', async () => {
|
||||
const url = `${fixtures.fileURL('es-modules/print-3.mjs')}`;
|
||||
assert.deepStrictEqual(await resolveLoadAndCache(url), {
|
||||
__proto__: null,
|
||||
url,
|
||||
format: 'module',
|
||||
source: Buffer.from('console.log(3);\n'),
|
||||
});
|
||||
assert.deepStrictEqual(await resolveLoadAndCache('./print-3.mjs', fixtures.fileURL('es-modules/loop.mjs').href), {
|
||||
__proto__: null,
|
||||
url,
|
||||
format: 'module',
|
||||
source: Buffer.from('console.log(3);\n'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should require import attribute to load JSON files', async () => {
|
||||
const url = 'data:application/json,{}';
|
||||
await assert.rejects(resolveLoadAndCache(url), { code: 'ERR_IMPORT_ATTRIBUTE_MISSING' });
|
||||
assert.deepStrictEqual(await resolveLoadAndCache(url, undefined, { type: 'json' }), {
|
||||
__proto__: null,
|
||||
format: 'json',
|
||||
url,
|
||||
source: Buffer.from('{}'),
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should use the existing cache', async () => {
|
||||
const url = fixtures.fileURL('es-modules/print-3.mjs');
|
||||
assert.deepStrictEqual(await spawnPromisified(process.execPath, [
|
||||
'--no-warnings',
|
||||
'--loader',
|
||||
fixtures.fileURL('es-module-loaders/loader-resolve-passthru.mjs'),
|
||||
'--loader',
|
||||
fixtures.fileURL('es-module-loaders/loader-load-passthru.mjs'),
|
||||
'-p',
|
||||
`import(${JSON.stringify(url)}).then(() => module.resolveLoadAndCache(${JSON.stringify(url)}, url.pathToFileURL(__filename)))`,
|
||||
]), {
|
||||
stderr: '',
|
||||
stdout: `Promise <>`,
|
||||
code: 0,
|
||||
signal: null,
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should populate the cache', async () => {});
|
||||
});
|
Loading…
Reference in New Issue