Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use HTTP urls with Node ESM module loader?

I have the following import mongo from "mongodb"; I would like to avoid using npm and instead use unpkg.com like this import mongo from "https://unpkg.com/mongodb";. However, when I run I get...

...@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'
}

Because it uses the term default module loader I was wondering if there was an alternative ESM loader I could use.

like image 838
Jackie Avatar asked Oct 20 '25 14:10

Jackie


1 Answers

Node will eventually support ESM URL imports. This feature is currently available under a CLI flag --experimental-network-imports. It doesn't ship with public releases yet (as of Node 18.0.0), so you will need to build Node from source for this as of current. See https://nodejs.org/api/esm.html#https-and-http-imports

In the meanwhile, Node has experimental support for module loaders and even shows a HTTPS loader as an example. See 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);
}

Use like so:

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

like image 107
Tomáš Hübelbauer Avatar answered Oct 22 '25 07:10

Tomáš Hübelbauer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!