package.jsonnodemonmonorepotsconfigyarn-workspaces

nodemon config with yarn workspaces monorepo


I'm having some trouble with nodemon in a yarn monorepo structure. I can't use nodemon src/index.ts in my api package, because it requires functions, enums, and the prisma instance from the orm package, whose package.json points to a dist/index.js file using the main field of its package.json.

I have the following repo structure:

packages/
  api
  cli
  orm

The error message I'm getting is the following:

repo-name/node_modules/ts-node/src/index.ts:859
    return new TSError(diagnosticText, diagnosticCodes, diagnostics);
           ^
TSError: ⨯ Unable to compile TypeScript:
src/controllers/_common/auth.controller.ts:13:3 - error TS2305: Module '"@project/orm"' has no exported member 'logActivity'.

13   logActivity,
     ~~~~~~~~~~~
src/controllers/_common/auth.controller.ts:14:3 - error TS2305: Module '"@project/orm"' has no exported member 'comparePasswords'.

14   comparePasswords,
     ~~~~~~~~~~~~~~~~
src/controllers/_common/auth.controller.ts:15:3 - error TS2305: Module '"@project/orm"' has no exported member 'SysActionsEnum'.

15   SysActionsEnum,
     ~~~~~~~~~~~~~~
src/controllers/_common/auth.controller.ts:16:3 - error TS2305: Module '"@project/orm"' has no exported member 'SysResourcesEnum'.

16   SysResourcesEnum,
     ~~~~~~~~~~~~~~~~


    at createTSError (/repo-name/node_modules/ts-node/src/index.ts:859:12)
    at reportTSError (/repo-name/node_modules/ts-node/src/index.ts:863:19)
    at getOutput (/repo-name/node_modules/ts-node/src/index.ts:1077:36)
    at Object.compile (/repo-name/node_modules/ts-node/src/index.ts:1433:41)
    at Module.m._compile (/repo-name/node_modules/ts-node/src/index.ts:1617:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Object.require.extensions.<computed> [as .ts] (/repo-name/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Function.Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19) {
  diagnosticCodes: [ 2305, 2305, 2305, 2305 ]


When I change the main field of the orm package.json to src/index.ts it works, because nodemon is able to handle .ts files. Is there any way I can configure nodemon so it automatically uses the ts files in the required package instead of the compiled JavaScript?

Additional info:

packages/api/package.json:

{
  "name": "@project/api",
  "version": "0.6.0",
  "description": "Project API",
  "license": "MIT",
  "main": "src/app.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node dist/app.js",
    "build": "tsc --project tsconfig.json",
    "dev": "nodemon src/app.ts",
    "prod": "set NODE_ENV=production&node dist/app.js"
  },
  "dependencies": {
    ...
  },
  "devDependencies":
    "ts-node": "^10.9.1",
    "typescript": "^5.0.4"
    ...
  }
}

packages/api/tsconfig.json:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "rootDir": "./src",
    "moduleResolution": "NodeNext",
    "baseUrl": "./src",
    "resolveJsonModule": true,
    "allowJs": true,
    "outDir": "./dist",
    "removeComments": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": false,
    "skipLibCheck": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}

packages/orm/package.json:

{
  "name": "@project/orm",
  "version": "0.1.0",
  "description": "project ORM",
  "license": "MIT",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc --project tsconfig.json",
    "dev": "nodemon src/index.ts",
    "studio": "dotenv -e ../../.env prisma studio",
    "db:pull": "dotenv -e ../../.env prisma db pull",
    "db:push": "dotenv -e ../../.env prisma db push",
    "db:seed": "dotenv -e ../../.env prisma db seed",
    "db:execute": "dotenv -e ../../.env prisma db execute",
    "migrate:dev": "dotenv -e ../../.env prisma migrate dev",
    "migrate:diff": "dotenv -e ../../.env prisma migrate diff",
    "migrate:reset": "dotenv -e ../../.env prisma migrate reset",
    "migrate:reset:force": "dotenv -e ../../.env prisma migrate reset -- --force",
    "migrate:deploy": "dotenv -e ../../.env prisma migrate deploy",
    "migrate:status": "dotenv -e ../../.env prisma migrate status",
    "generate": "dotenv -e ../../.env prisma generate"
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    ...
    "ts-node": "^10.9.1",
    "typescript": "^5.0.4"
  },
  "prisma": {
    "schema": "src/prisma/schema.prisma",
    "seed": "ts-node src/prisma/seed.ts"
  }
}

packages/orm/tsconfig.json:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "rootDir": "./src",
    "moduleResolution": "NodeNext",
    "baseUrl": "./src",
    "resolveJsonModule": true,
    "allowJs": false,
    "outDir": "./dist",
    "removeComments": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": false,"skipLibCheck": true
  },
  "include": ["src/*.ts", "src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}


Solution

  • Found the solution:

    1. I installed tsconfig-paths and ts-node as dev dependencies in all of my workspaces.
    2. I created a tsconfig.json in the root directory with the following config:
    {
      "compilerOptions": {
        "target": "ES6",
        "module": "CommonJS",
        "moduleResolution": "Node",
        "esModuleInterop": true,
        "removeComments": true,
        "strict": false,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "baseUrl": ".",
        "paths": {
          "@project/cli": ["./packages/cli/src/project.ts"],
          "@project/orm": ["./packages/orm/src/index.ts"]
        }
      }
    }
    
    1. Inside the all 3 packages I have created a tsconfig.json which extends this base config. I tried naming it tsconfig-base.json but then the custom paths wouldn't work. Here are the contents of the api and orm package:

    packages/api/tsconfig.json:

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

    packages/orm/tsconfig.json:

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

    They're both very similar and don't do much except set up the dirs.

    1. I added a new dev script which has to be executed from the root package.json file:
    "dev": "nodemon --exec ts-node --require tsconfig-paths/register packages/api/src/app.ts",
    

    And that's it! Now the dev script of the root package.json runs and uses the ts files of the orm package. It also restarts the process if I make changes to ts files of the orm package.