3

Importing a module in my nodejs app is always flagging an error

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\xampp\htdocs\2021\farmi\api\src\controllers\user.controller' imported from C:\xampp\htdocs\2021\farmi\api\src\routes\user.route.js
    at finalizeResolution (internal/modules/esm/resolve.js:276:11)
    at moduleResolve (internal/modules/esm/resolve.js:699:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
    at Loader.resolve (internal/modules/esm/loader.js:88:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:241:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:56:40)
    at link (internal/modules/esm/module_job.js:55:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}
[nodemon] app crashed - waiting for file changes before starting...

This is because I didn't include the .js extension in import userController from '../controllers/user.controller';

How can I resolve this please.

Cradoe
  • 106
  • 1
  • 8
  • 2
    Add the .js extension to your import. – Phix Aug 25 '21 at 18:28
  • **Extended answers here** https://stackoverflow.com/questions/61291633/expressjs-is-return-error-err-module-not-found-if-i-import-the-file-without-j?rq=3 – ben Aug 09 '23 at 14:38

2 Answers2

3

../controllers/user.controller is a relative specifier. They refer to a path relative to the location of the importing file. The file extension is always necessary for these. See the documentation

Rukshan Jayasekara
  • 1,945
  • 1
  • 6
  • 26
2

Suppose the following files

a.js

export const value = 1;

b.js

import {value} from "./a"
console.log(value);

package.json

{
    "type":"module",
}

If you try running node b.js it will fail with ERR_MODULE_NOT_FOUND.

Apart from the selected answer here are two more -

Solution 1 - rollup

You can install the npm package rollup

% npm i -D rollup

to bundle your output

% npx rollup -i b.js -o ab.js
b.js → ab.js...
created ab.js in 26ms

Rollup accepts the import "./a" syntax, and bundles everything into a single file for execution.

% node ab.js
1

Solution 2 - package internal import aliasing with package.json

Change the import declaration in b.js to

import {value} from "#a" // the "./" is replaced by "#"
console.log(value);

and provide a mapping for #a in package.json

{
    "type":"module",
    "imports": {
        "#a": "./a.js"
    }
}

Node will read the mapping from package.json so the import works -

% node b.js
1

Discussion with respect to Typescript

Solution 1 (rollup) leaves your original code untouched but the (selected answer)[https://stackoverflow.com/a/68928179/4376643] and Solution 2 do not.

That's important when the .js code is output from Typescript, once with "module":"CommonJS" and once with "module":"es6" or greater. Typescript does not automatically add the extensions for es6 import statements, so the es6 output would not be runnable. Therefore rollup is a convenient way to make it runnable (and it has the advantage of doing tree-shaking as well.)

Craig Hicks
  • 2,199
  • 20
  • 35