Search code examples
node.jstypescript

Error [ERR_MODULE_NOT_FOUND]: Cannot find module when using bundler resolution


I switch to bunder resolution with my project, the project build process works fine, when run this application, shows error:

 node:internal/errors:496
│     ErrorCaptureStackTrace(err);
│     ^
│
│ Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/node/app/dist/websocket/config/setup' imported from /home/node/app/dist/app.js
│     at new NodeError (node:internal/errors:405:5)
│     at finalizeResolution (node:internal/modules/esm/resolve:327:11)
│     at moduleResolve (node:internal/modules/esm/resolve:980:10)
│     at defaultResolve (node:internal/modules/esm/resolve:1206:11)
│     at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:404:12)
│     at ModuleLoader.resolve (node:internal/modules/esm/loader:373:25)
│     at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:250:38)
│     at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:39)
│     at link (node:internal/modules/esm/module_job:75:36) {
│   url: 'file:///home/node/app/dist/websocket/config/setup',
│   code: 'ERR_MODULE_NOT_FOUND'
│ }
│
│ Node.js v18.20.6

this is the typescript config:

{
    "compilerOptions": {
      "target": "ES2020",
      "module": "esnext",
      "moduleResolution": "bundler",
      "outDir": "./dist",
      "rootDir": "./src",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "declaration": true,
    },
    "include": ["src/**/*"],
    "files": ["src/app.ts"]
  }

the bundler resolution did not need to add the file extension. why show this error? This is the package.json:

{
  "name": "texhub-broadcast",
  "version": "1.0.19",
  "description": "",
  "main": "./dist/app.js",
  "module": "./dist/app.js",
  "types": "./dist/app.d.ts",
  "type":"module",
  "exports": {
    "./dist/websocket/conn/socket_io_client_provider": "./dist/websocket/conn/socket_io_client_provider.js",
    ".": {
      "import": "./dist/app.js"
    }
  },
  "files": [
    "dist/*"
  ],
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint --fix",
    "dev": "vite-node src/app.ts",
    "build": "npx tsc",
    "dist": "npx tsc"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^16.4.7",
    "express": "^4.21.2",
    "flatted": "^3.3.2",
    "globals": "^15.14.0",
    "lib0": "^0.2.99",
    "lodash": "^4.17.21",
    "log4js": "^6.9.1",
    "meilisearch": "^0.35.1",
    "prom-client": "^14.2.0",
    "socket.io": "^4.8.1",
    "socket.io-client": "^4.8.1",
    "ws": "^8.18.0",
    "y-leveldb": "^0.1.2",
    "y-protocols": "^1.0.6",
    "y-websocket": "^1.5.0",
    "yjs": "^13.6.23"
  },
  "devDependencies": {
    "@types/express": "^5.0.0",
    "@types/lodash": "^4.17.15",
    "@types/node": "^22.12.0",
    "@types/ws": "^8.5.14",
    "@typescript-eslint/eslint-plugin": "^8.22.0",
    "@typescript-eslint/parser": "^8.22.0",
    "eslint": "^9.19.0",
    "typescript": "^5.7.3",
    "vite": "^6.0.11",
    "vite-node": "^3.0.4",
    "vitest": "^3.0.4"
  }
}

this is the import style:

import { setupWSConnection } from "./websocket/config/setup";

this is the dist file structure:

├── dist
│   ├── websocket
|        |__ config
|              |_ setup.js
│   └── app.js
├── package-lock.json
├── package.json
├── src
│   ├── websoccket
|         |_ config
|               |_ setup.ts  
│   └── app.ts
└── tsconfig.json

Solution

  • You are using "moduleResolution": "bundler" in your tsconfig.json, which means TypeScript does not require file extensions when importing modules.

    However, Node.js does require the correct file extension when running the compiled JavaScript files in an ES module ("type": "module" in package.json).

    Your import statement:

    import { setupWSConnection } from "./websocket/config/setup";
    

    gets compiled to:

    import { setupWSConnection } from "./websocket/config/setup";
    

    But in dist/ folder, the file is named setup.js, and Node.js expects:

    import { setupWSConnection } from "./websocket/config/setup.js";
    

    Since the extension is missing, Node.js throws the error:

    Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/node/app/dist/websocket/config/setup'
    

    Solutions:

    1. Add the .js extension in imports (wherever import statements are used):
    import { setupWSConnection } from "./websocket/config/setup.js";
    
    1. Use "moduleResolution": "node" instead of "bundler"

    Modify your tsconfig.json file

    "moduleResolution": "node"
    

    This forces TypeScript to behave like Node.js and require explicit .js extensions in the output.