| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent da61e23 commit 254efd9
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -238,6 +238,17 @@ function fetchModule(parsed, { parentURL }) { | |||
| 238 | 238 | return fetchWithRedirects(parsed); | |
| 239 | 239 | } | |
| 240 | 240 | ||
| 241 | + /** | ||
| 242 | + * Checks if the given canonical URL exists in the fetch cache | ||
| 243 | + * | ||
| 244 | + * @param {string} key | ||
| 245 | + * @returns {boolean} | ||
| 246 | + */ | ||
| 247 | + function inFetchCache(key) { | ||
| 248 | + return cacheForGET.has(key); | ||
| 249 | + } | ||
| 250 | + | ||
| 241 | 251 | module.exports = { | |
| 242 | - fetchModule: fetchModule, | ||
| 252 | + fetchModule, | ||
| 253 | + inFetchCache, | ||
| 243 | 254 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -57,6 +57,7 @@ const { translators } = require( | |||
| 57 | 57 | const { getOptionValue } = require('internal/options'); | |
| 58 | 58 | const { | |
| 59 | 59 | fetchModule, | |
| 60 | + inFetchCache, | ||
| 60 | 61 | } = require('internal/modules/esm/fetch_module'); | |
| 61 | 62 | ||
| 62 | 63 | ||
@@ -338,23 +339,35 @@ class ESMLoader { | |||
| 338 | 339 | * would have a cache key of https://example.com/foo and baseURL | |
| 339 | 340 | * of https://example.com/bar | |
| 340 | 341 | * | |
| 341 | - * MUST BE SYNCHRONOUS for import.meta initialization | ||
| 342 | - * MUST BE CALLED AFTER receiving the url body due to I/O | ||
| 343 | - * @param {string} url | ||
| 344 | - * @returns {string} | ||
| 342 | + * ! MUST BE SYNCHRONOUS for import.meta initialization | ||
| 343 | + * ! MUST BE CALLED AFTER receiving the url body due to I/O | ||
| 344 | + * @param {URL['href']} url | ||
| 345 | + * @returns {string|Promise<URL['href']>} | ||
| 345 | 346 | */ | |
| 346 | 347 | getBaseURL(url) { | |
| 347 | - if ( | ||
| 348 | + if (getOptionValue('--experimental-network-imports') && ( | ||
| 348 | 349 | StringPrototypeStartsWith(url, 'http:') || | |
| 349 | 350 | StringPrototypeStartsWith(url, 'https:') | |
| 350 | - ) { | ||
| 351 | - // The request & response have already settled, so they are in | ||
| 352 | - // fetchModule's cache, in which case, fetchModule returns | ||
| 351 | + )) { | ||
| 352 | + // When using network-imports, the request & response have already settled | ||
| 353 | + // so they are in fetchModule's cache, in which case, fetchModule returns | ||
| 353 | 354 | // immediately and synchronously | |
| 354 | - url = fetchModule(new URL(url), { parentURL: url }).resolvedHREF; | ||
| 355 | - // This should only occur if the module hasn't been fetched yet | ||
| 356 | - if (typeof url !== 'string') { // [2] | ||
| 357 | - throw new ERR_INTERNAL_ASSERTION(`Base url for module ${url} not loaded.`); | ||
| 355 | + // Unless a custom loader bypassed the fetch cache, in which case we just | ||
| 356 | + // use the original url | ||
| 357 | + if (inFetchCache(url)) { | ||
| 358 | + const module = fetchModule(new URL(url), { parentURL: url }); | ||
| 359 | + if (typeof module?.resolvedHREF === 'string') { | ||
| 360 | + return module.resolvedHREF; | ||
| 361 | + } | ||
| 362 | + // Internal error | ||
| 363 | + throw new ERR_INTERNAL_ASSERTION( | ||
| 364 | + `Base url for module ${url} not loaded.` | ||
| 365 | + ); | ||
| 366 | + } else { | ||
| 367 | + // A custom loader was used instead of network-imports. | ||
| 368 | + // Adding support for a response URL resolve return in custom loaders is | ||
| 369 | + // pending. | ||
| 370 | + return url; | ||
| 358 | 371 | } | |
| 359 | 372 | } | |
| 360 | 373 | return url; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -76,7 +76,11 @@ class ModuleJob { | |||
| 76 | 76 | // these `link` callbacks depending on each other. | |
| 77 | 77 | const dependencyJobs = []; | |
| 78 | 78 | const promises = this.module.link(async (specifier, assertions) => { | |
| 79 | - const baseURL = this.loader.getBaseURL(url); | ||
| 79 | + const base = await this.loader.getBaseURL(url); | ||
| 80 | + const baseURL = typeof base === 'string' ? | ||
| 81 | + base : | ||
| 82 | + base.resolvedHREF; | ||
| 83 | + | ||
| 80 | 84 | const jobPromise = this.loader.getModuleJob(specifier, baseURL, assertions); | |
| 81 | 85 | ArrayPrototypePush(dependencyJobs, jobPromise); | |
| 82 | 86 | const job = await jobPromise; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,72 @@ | |||
| 1 | + import { mustCall } from '../common/index.mjs'; | ||
| 2 | + import fixtures from '../common/fixtures.js'; | ||
| 3 | + import { strictEqual } from 'node:assert'; | ||
| 4 | + import { spawn } from 'node:child_process'; | ||
| 5 | + import http from 'node:http'; | ||
| 6 | + import path from 'node:path'; | ||
| 7 | + import { promisify } from 'node:util'; | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + const files = { | ||
| 11 | + 'main.mjs': 'export * from "./lib.mjs";', | ||
| 12 | + 'lib.mjs': 'export { sum } from "./sum.mjs";', | ||
| 13 | + 'sum.mjs': 'export function sum(a, b) { return a + b }', | ||
| 14 | + }; | ||
| 15 | + | ||
| 16 | + const requestListener = ({ url }, rsp) => { | ||
| 17 | + const filename = path.basename(url); | ||
| 18 | + const content = files[filename]; | ||
| 19 | + | ||
| 20 | + if (content) { | ||
| 21 | + return rsp | ||
| 22 | + .writeHead(200, { 'Content-Type': 'application/javascript' }) | ||
| 23 | + .end(content); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + return rsp | ||
| 27 | + .writeHead(404) | ||
| 28 | + .end(); | ||
| 29 | + }; | ||
| 30 | + | ||
| 31 | + const server = http.createServer(requestListener); | ||
| 32 | + | ||
| 33 | + await promisify(server.listen.bind(server))({ | ||
| 34 | + host: '127.0.0.1', | ||
| 35 | + port: 0, | ||
| 36 | + }); | ||
| 37 | + | ||
| 38 | + const { | ||
| 39 | + address: host, | ||
| 40 | + port, | ||
| 41 | + } = server.address(); | ||
| 42 | + | ||
| 43 | + { // Verify nested HTTP imports work | ||
| 44 | + const child = spawn( // ! `spawn` MUST be used (vs `spawnSync`) to avoid blocking the event loop | ||
| 45 | + process.execPath, | ||
| 46 | + [ | ||
| 47 | + '--no-warnings', | ||
| 48 | + '--loader', | ||
| 49 | + fixtures.fileURL('es-module-loaders', 'http-loader.mjs'), | ||
| 50 | + '--input-type=module', | ||
| 51 | + '--eval', | ||
| 52 | + `import * as main from 'http://${host}:${port}/main.mjs'; console.log(main)`, | ||
| 53 | + ] | ||
| 54 | + ); | ||
| 55 | + | ||
| 56 | + let stderr = ''; | ||
| 57 | + let stdout = ''; | ||
| 58 | + | ||
| 59 | + child.stderr.setEncoding('utf8'); | ||
| 60 | + child.stderr.on('data', (data) => stderr += data); | ||
| 61 | + child.stdout.setEncoding('utf8'); | ||
| 62 | + child.stdout.on('data', (data) => stdout += data); | ||
| 63 | + | ||
| 64 | + child.on('close', mustCall((code, signal) => { | ||
| 65 | + strictEqual(stderr, ''); | ||
| 66 | + strictEqual(stdout, '[Module: null prototype] { sum: [Function: sum] }\n'); | ||
| 67 | + strictEqual(code, 0); | ||
| 68 | + strictEqual(signal, null); | ||
| 69 | + | ||
| 70 | + server.close(); | ||
| 71 | + })); | ||
| 72 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + import { get } from 'http'; | ||
| 2 | + | ||
| 3 | + export function resolve(specifier, context, nextResolve) { | ||
| 4 | + const { parentURL = null } = context; | ||
| 5 | + | ||
| 6 | + if (specifier.startsWith('http://')) { | ||
| 7 | + return { | ||
| 8 | + shortCircuit: true, | ||
| 9 | + url: specifier, | ||
| 10 | + }; | ||
| 11 | + } else if (parentURL?.startsWith('http://')) { | ||
| 12 | + return { | ||
| 13 | + shortCircuit: true, | ||
| 14 | + url: new URL(specifier, parentURL).href, | ||
| 15 | + }; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + return nextResolve(specifier, context); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + export function load(url, context, nextLoad) { | ||
| 22 | + if (url.startsWith('http://')) { | ||
| 23 | + return new Promise((resolve, reject) => { | ||
| 24 | + get(url, (rsp) => { | ||
| 25 | + let data = ''; | ||
| 26 | + rsp.on('data', (chunk) => data += chunk); | ||
| 27 | + rsp.on('end', () => { | ||
| 28 | + resolve({ | ||
| 29 | + format: 'module', | ||
| 30 | + shortCircuit: true, | ||
| 31 | + source: data, | ||
| 32 | + }); | ||
| 33 | + }); | ||
| 34 | + }) | ||
| 35 | + .on('error', reject); | ||
| 36 | + }); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + return nextLoad(url, context); | ||
| 40 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments