bhr
bhr

Reputation: 2337

Monorepo – Yarn workspaces Typescript Node.JS project – cannot find module when running nodemon

I've set up a monorepo using yarn workspaces for a typescript Node.JS project. Building the project works fine, however, I'm running into issues during local development.

I need to manually run yarn build before running yarn dev. Otherwise I'm receiving the following error:

Error: Cannot find module '/Users/benedikt/code/monorepo-build/node_modules/@bhirmer/utils/dist/index.js'. Please verify that the package.json has a valid "main" entry

Here's the sample repo that reproduces the issue.

Alternatively, the important files.

Project Structure

packages/
  utils
services/
  api

Root package.json

{
  "name": "@bhirmer/monorepo",
  "description": "Workspace",
  "private": true,
  "workspaces": [
    "packages/*",
    "services/*"
  ],
  "scripts": {},
  "devDependencies": {
    "eslint": "~7.14.0",
    "typescript": "^4.0.5"
  }
}

Root tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2015",
    "lib": ["ES2019", "dom"],
    "types": ["node"],
    "esModuleInterop": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "noEmitOnError": true,
    "allowUmdGlobalAccess": true,
    "allowJs": false,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": false,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noImplicitThis": true,
    "strictNullChecks": true,
    "noImplicitReturns": true,
    "preserveConstEnums": true,
    "suppressImplicitAnyIndexErrors": true,
    "composite": true,
    "baseUrl": "../..",
    "paths": {
      "@bhirmer/*": ["packages/*/src"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Utils package.json

{
  "name": "@bhirmer/utils",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
    "files": [
        "dist"
    ],
  "scripts": {
    "build": "yarn run clean && yarn run compile",
    "clean": "rimraf ./dist && rimraf ./tsconfig.buildinfo",
    "compile": "tsc --build",
    "test": "yarn run build"
  },
  "dependencies": {
    "@types/node": "^14.14.12"
  },
  "devDependencies": {},
  "sideEffects": false
}

Utils tsconfig.json

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "baseUrl": "../../",
    "rootDir": "./src",
    "outDir": "./dist",
    "composite": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

API package.json

{
  "name": "@bhirmer/api",
  "description": "api",
  "author": "Benedikt Hirmer <[email protected]",
  "license": "UNLICENSED",
  "private": true,
  "version": "1.0.0",
  "main": "server/index",
  "scripts": {
    "dev": "PROJECT_ID=test-dev PORT=3010 nodemon src/server/index.ts",
    "clean": "rimraf ./dist",
    "compile": "NODE_ENV=production tsc --build",
    "build": "yarn run compile",
    "start": "PROJECT_ID=test-prod NODE_ENV=production node dist/server/index.js",
  },
  "dependencies": {
    "@bhirmer/utils": "^1.0.0",
    "@types/compression": "^1.7.0",
    "@types/express": "^4.17.11",
    "@types/node": "^14.14.12",
    "compression": "^1.7.4",
    "express": "^4.17.1",
    "typescript": "^4.2.4"
  },
  "devDependencies": {
    "nodemon": "^2.0.7",
    "ts-node": "^9.1.1"
  }
}

API tsconfig.json

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist",
    "baseUrl": "../../",
    // "rootDir": "src", // Getting `TypeError: src/server/index.ts: Emit skipped` if not commented out
    "composite": true
  },
  "include": ["src/**/*"],
  "types": ["typePatches"],
  "references": [{ "path": "../../packages/utils" }]
}

Sample usage of packages/utils in services/api

import { getProjectID } from '@bhirmer/utils';

...

const projectID = getProjectID();

...

Another point to note is that once I set "rootDir": "src" in services/api/tsconfig.json, then I'm hitting the following error:

TypeError: src/server/index.ts: Emit skipped if not commented out

Upvotes: 5

Views: 17689

Answers (2)

Xolv.io
Xolv.io

Reputation: 2533

Recently had this issue, this was the fix for us:

  "ts-node": {
    "require": ["tsconfig-paths/register"]
  },

For ts-node to see other monorepo packages it needed this entry

Upvotes: 0

Grzegorz Judas
Grzegorz Judas

Reputation: 469

NPM workspaces still need you to run npm install inside the root directory (where the package.json with workspaces definition/location is), in order to make relevant symlinks to local packages.

When you do that, you should end up with:

node_modules/
    @bhirmer/
        utils/ <-- symlink to /packages/utils/
        api/ <-- symlink to /services/api/
packages/
    utils/
        ...
services/
    api/
        ...
package.json <-- root package.json with "workspaces"

You'll have to re-run it every time you make a new local package folder with package.json inside, that you want to access from elsewhere.

Upvotes: 1

Related Questions