12

So I'm using the package esm and module-alias, but it seems like esm does not register module-alias's paths.

Here's how I'm loading my server file:

nodemon -r esm ./src/index.js 8081

Here's the top of my index.js file:

import "module-alias/register"
import "@/setup"

import "@/setup" does not work whereas require("@/setup") does.

A. L
  • 11,695
  • 23
  • 85
  • 163

4 Answers4

14

The problem is that esm tries to handle all import statements when parsing the file, before any other module gets loaded.

When processing import statements, it uses node's builtin require rather than the modified require created by module-alias

To fix this, you need to first load module-alias and then esm. This way, module-alias will get the chance to modify the require function before esm gets to do anything.

You can achive this by passing multiple -r parameters to node, but make sure module-alias comes first:

node -r module-alias/register -r esm index.js 8081

or with nodemon:

nodemon -r module-alias/register -r esm ./src/index.js 8081

You also need to remove the import "module-alias/register" from your code, since now it's loaded from the command line.

mihai
  • 37,072
  • 9
  • 60
  • 86
  • i need to add `node_modules`, like this `nodemon -r node_modules/module-alias/register` – Alex Montoya Mar 19 '19 at 06:44
  • 3
    I inverted the order and seems to be working now, mine is this: `node -r esm -r module-alias/register index.js`, The normal require wasn't working – Marcelo Apr 25 '19 at 17:53
  • confim, working order for me: `-r esm -r module-alias/register index.js` – taburetkin Jun 08 '19 at 11:28
  • For me that worked Added "@std/esm": "cjs" to package.json nodemon -r @std/esm -r module-alias/register ./app/server.mjs – Anderson Danilo Nov 11 '19 at 13:02
  • What if I want to add my aliases manually, let's say with something like: `import * as path from 'path'; import * as moduleAlias from 'module-alias'; moduleAlias.addAlias('@', path.join(process.cwd(), 'dist', 'server'));` ? – EuberDeveloper Mar 06 '22 at 13:54
0

For me worked the following code:

package.json

  "scripts": {
    "dev": "pkill -f lib/serverIndex.js; NODE_ENV=development node lib/serverIndex.js",

lib/serverIndex.js

require = require('esm')(module/*, options*/);
require('module-alias/register');
module.exports = require("./server.js");
Mihail Davydenkov
  • 1,861
  • 2
  • 19
  • 33
0

This problem has been plaguing me for years because I want to write good quality code that is shared between node & browser. I finally found a system that works:

  • Place 'nesm.js' in the root of your project
  • [optional] Place the 'nesm' shell script in your path, make it executable
  • Run scripts with: 'nesm file_to_run.js' or 'node path/to/nesm.js -- file_to_run.js'

'nesm.js'

/*
 * esm and module-alias do not play nicely together.
 * this precise arrangement is the only way I found to make it work.
 * you can run this from anywhere in your project hierarchy.
 * you can use args, and use in npm scripts.
 * encourage the node.js devs to make this work natively.  ux matters.
 * ---- CAVEATS
 * will not work with "type":"module"
 * ---- SETUP
 * place 'nesm.js' in the root of your project
 * [optional] place the 'nesm' shell script in your path, make it executable
 * ---- USAGE
 * > nesm file_to_run.js
 * to run without the nesm shell script:
 * > node path/to/nesm.js -- file_to_run.js
 * to run with nodemon:
 * > nodemon -- path/to/nesm.js -- file_to_run.js
*/
require = require('esm')(module);   // eslint-disable-line no-global-assign
require('module-alias/register');   // must come after esm for some reason

let runNext;
for(const arg of process.argv) {
    if(runNext) {
        let filename = arg;
        if(filename[0]!='.' && filename[0]!='/') filename = './'+filename;
        require(filename);
        break;
    }
    runNext = (arg=='--');
}

'nesm' shell script

#!/bin/bash
if [ -z $1 ]; then
    echo "Node esm runner.  Usage: nesm file_to_run.js"
    exit 1
fi
baseDir=$( pwd )
while [ ! -f "$baseDir/nesm.js" ]; do
    if [ ${#baseDir} -le 1 ]; then
        echo "nesm.js not found in folder ancestry"
        exit 1
    fi
    baseDir="$(dirname "$baseDir")"
done
file1=$(realpath $1);
node $baseDir/nesm.js -- $file1
Dirigible
  • 1,749
  • 16
  • 11
0

There is another solution, initially found in this comment to solve the problem without even using module-alias.

I also made a repo to simplify this, check it here esm-module-alias

EuberDeveloper
  • 874
  • 1
  • 14
  • 38