Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ESM import a .node addon

I am trying to import a .node binary addon in an ESM & Node Typescript based context. However, when I try to do this I get the following error "error TS2307: Cannot find module './addon.node' or its corresponding type declarations."

I've looked online for several solutions, these are my versions: NodeJS: v16.14.1 ts-node: v10.7.0 Typescript: 4.6.3

This is my current approach for importing:

import addon from "./addon.node";

Just to note, because of my configuration I am limited to only using import. Thanks in advance for any support.

like image 502
pou bee Avatar asked Aug 03 '26 08:08

pou bee


1 Answers

Node.js import doesn’t support .node files. To import such files in an ESM context, you need to use createRequire:

import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

const addon = require('./addon.node');

You could also import the .node file in a CommonJS file that an ESM file then imports.

// addon.cjs
module.exports = require('./addon.node');

// main.js
import addon from './addon.cjs';

Finally, you could create an ESM loader that adds support for .node files to import, by wrapping the createRequire method into a loader (untested):

import { cwd } from 'node:process';
import { pathToFileURL } from 'node:url';

const baseURL = pathToFileURL(`${cwd()}/`).href;

export async function resolve(specifier, context, nextResolve) {
  if (specifier.endsWith('.node')) {
    const { parentURL = baseURL } = context;

    // Node.js normally errors on unknown file extensions, so return a URL for
    // specifiers ending in `.node`.
    return {
      shortCircuit: true,
      url: new URL(specifier, parentURL).href,
    };
  }

  // Let Node.js handle all other specifiers.
  return nextResolve(specifier);
}

export async function load(url, context, nextLoad) {
  if (url.endsWith('.node')) {
    const source = `
      import { createRequire } from 'node:module';
      import { fileURLToPath } from 'node:url';
      const require = createRequire(import.meta.url);
      const path = fileURLToPath(${url});
      export default require(path);`;

    return {
      format: 'module',
      shortCircuit: true,
      source,
    };
  }

  // Let Node.js handle all other URLs.
  return nextLoad(url);
}
like image 186
Geoffrey Booth Avatar answered Aug 07 '26 02:08

Geoffrey Booth



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!