如何在 Node ESM 模块加载器中使用 HTTP url?

问题描述

我有以下 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'
}

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

解决方法

Node 不支持通过 HTTP/HTTPS URL 加载 ES 模块,但它确实对模块加载器有实验性支持,甚至以 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,defaultResolve);
}

export function getFormat(url,defaultGetFormat) {
  // This loader assumes all network-provided JavaScript is ES module code.
  if (url.startsWith('https://')) {
    return {
      format: 'module'
    };
  }

  // Let Node.js handle all other URLs.
  return defaultGetFormat(url,defaultGetFormat);
}

export function getSource(url,defaultGetSource) {
  // 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({ source: data }));
      }).on('error',(err) => reject(err));
    });
  }

  // Let Node.js handle all other URLs.
  return defaultGetSource(url,defaultGetSource);
}

像这样使用:

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...