Normalmente en Node se puede usar NODE_PATH=./src"
para que en lugar de:
import { foo } from '../../../bar'
Solo puedes hacer:
import { foo } from 'src/bar'
Sin embargo, eso solo funciona si usa el paquete esm
(es decir, node -r esm
): NODE_PATH
no funciona con módulos ES nativos (es decir, agregar "type": "module"
a package.json
) ... ¿y qué? es el reemplazo moderno?
Probé todo lo siguiente, y ninguno de ellos parece funcionar (aunque es posible que no los esté usando correctamente y agradecería cualquier aclaración):
node_modules/src
a project-root/src
) - que importa el archivo como un paquete CommonJS, no como uno ES, lo que significa que las importaciones con nombre no funcionan"workspaces": ["src"],
en package.json
) - mismo problema: sin importaciones con nombre"imports": {"#src": "./src"}
): ignora el --experimental-specifier-resolution=node
(por lo que solo funciona SI quiero pasar y agregar manualmente .js
a cada importación en mi proyecto)loader.js
y usar node --loader loader.js
): no pude averiguar cómo hacer que esto funcione, ya que casi no hay documentación sobre cargadores personalizados Idealmente, preferiría no tener que implementar todo Babel/Webpack/Typescript/etc. en mi proyecto, solo para reemplazar NODE_PATH=./src
, pero parece que agregar alguna herramienta de este tipo es la única forma ahora.
Parece que la única opción viable... si desea importaciones relativas a la raíz Y no desea especificar la extensión .js
... es usar un cargador personalizado.
Como referencia, el que hice para lograr esto fue:
import path from 'path'; import fs from 'fs'; export function resolve(originalSpecifier, context, defaultResolver) { let specifier = originalSpecifier; try { // All my root-relative imports start with "src/"; if you // have other folders you'll need to account for them here if (specifier.startsWith('src')) { specifier = specifier.replace(/^src/, path.resolve('.') + '/src'); // If the import is for a directory, get its index.js file const itExists = fs.existsSync(specifier); let isDirectory = false; try { isDirectory = fs.lstatSync(specifier).isDirectory(); } catch (err) {} specifier = itExists && isDirectory ? `${specifier}/index` : specifier; // Add the ".js" extension if not specified specifier += specifier.endsWith('.js') ? '' : '.js'; return { format: 'module', url: new URL(specifier, context.parentURL).href, }; } } catch (err) { console.error(err); } // If we're not handling our special cases, just use the // default handler return defaultResolver(specifier, context); }
Luego puede usar ese cargador con la opción --loader
, por ejemplo.
node --loader loader.js index.js
Sin embargo, vale la pena señalar que el cargador aún está en desarrollo y podría cambiar (haciendo que el cargador anterior no sea válido) en el futuro. Probablemente en algún momento de 2030, dado lo lenta que es la organización de Node con su desarrollo;)