node.js - importar un addon .node con ESM
Estoy intentando importar un complemento binario .node en un contexto basado en ESM y Node con TypeScript. Sin embargo, cuando intento hacer esto, obtengo el siguiente error "error TS2307: No se puede encontrar el módulo './addon.node' o sus declaraciones de tipo correspondientes."
He buscado en línea varias soluciones, estas son mis versiones: NodeJS: v16.14.1 ts-node: v10.7.0 Typescript: 4.6.3
Este es mi enfoque actual para importar:
import addon from "./addon.node";
Solo para señalar, debido a mi configuración estoy limitado a usar únicamente import. Gracias de antemano por cualquier apoyo.
Respuesta #1
Node.js import no admite archivos .node. Para importar dichos archivos en un contexto ESM, necesitas usar createRequire:
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const addon = require('./addon.node');
También podrías importar el archivo .node en un archivo CommonJS que luego importe un archivo ESM.
// addon.cjs
module.exports = require('./addon.node');
// main.js
import addon from './addon.cjs';
Finalmente, podrías crear un cargador ESM que agregue soporte para archivos .node a import, envolviendo el método createRequire en un cargador (sin probar):
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);
}
