如何将 HTTP url 与 Node ESM 模块加载器一起使用?

Jac*_*kie 4 javascript node.js es6-modules

我有以下情况,import mongo from "mongodb";我想避免使用 npm 而是像这样使用 unpkg.com import mongo from "https://unpkg.com/mongodb";。然而,当我跑步时,我发现...

...@penguin:~/...$ node --harmony test.mjs node:internal/process/esm_loader:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only file and data URLs are supported by the default ESM loader. Received protocol 'https:'
    at new NodeError (node:internal/errors:328:5)
    at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:825:11)
    at Loader.resolve (node:internal/modules/esm/loader:86:40)
    at Loader.getModuleJob (node:internal/modules/esm/loader:230:28)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:56:40)
    at link (node:internal/modules/esm/module_job:55:36) {
  code: 'ERR_UNSUPPORTED_ESM_URL_SCHEME'
}
Run Code Online (Sandbox Code Playgroud)

因为它使用术语“默认模块加载器”,所以我想知道是否有可以使用的替代 ESM 加载器。

Tom*_*uer 8

Node 最终将支持 ESM URL 导入。此功能当前可在 CLI 标志下使用--experimental-network-imports。它尚未随公开版本一起发布(从 Node 18.0.0 开始),因此您需要从当前的源代码构建 Node。请参阅https://nodejs.org/api/esm.html#https-and-http-imports

同时,Node 对模块加载器提供了实验性支持,甚至展示了 HTTPS 加载器作为示例。请参阅https://nodejs.org/api/esm.html#esm_https_loader

// https-loader.mjs
import { get } from 'https';

export function resolve(specifier, context, defaultResolve) {
  const { parentURL = null } = context;

  // Normally Node.js would error on specifiers starting with 'https://', so
  // this hook intercepts them and converts them into absolute URLs to be
  // passed along to the later hooks below.
  if (specifier.startsWith('https://')) {
    return {
      url: specifier
    };
  } else if (parentURL && parentURL.startsWith('https://')) {
    return {
      url: new URL(specifier, parentURL).href
    };
  }

  // Let Node.js handle all other specifiers.
  return defaultResolve(specifier, context, defaultResolve);
}

export function load(url, context, defaultLoad) {
  // For JavaScript to be loaded over the network, we need to fetch and
  // return it.
  if (url.startsWith('https://')) {
    return new Promise((resolve, reject) => {
      get(url, (res) => {
        let data = '';
        res.on('data', (chunk) => data += chunk);
        res.on('end', () => resolve({
          // This example assumes all network-provided JavaScript is ES module
          // code.
          format: 'module',
          source: data,
        }));
      }).on('error', (err) => reject(err));
    });
  }

  // Let Node.js handle all other URLs.
  return defaultLoad(url, context, defaultLoad);
}
Run Code Online (Sandbox Code Playgroud)

像这样使用:

node --experimental-loader ./https-loader.mjs ./main.mjs