网站搜索

Monorepo - Yarn 工作区 Typescript Node.JS 项目 - 运行 nodemon 时找不到模块


我已经使用 yarn workspaces 为一个 TypeScript Node.JS 项目设置了一个 monorepo。构建项目没有问题,然而,在本地开发过程中我遇到了一些问题。

我需要在运行 yarn dev 之前手动运行 yarn build。否则我会收到以下错误:

错误:无法找到模块 '/Users/benedikt/code/monorepo-build/node_modules/@bhirmer/utils/dist/index.js'。请确认 package.json 中有有效的 "main" 条目

这是重现该问题的示例仓库。

或者,重要的文件。

项目结构

packages/
  utils
services/
  api

根 package.json

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

根 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 ",
  "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" }]
}

在 services/api 中使用 packages/utils 的示例

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

...

const projectID = getProjectID();

...

另一个需要注意的点是,一旦我在 services/api/tsconfig.json 中设置了 "rootDir": "src",我就会遇到以下错误:

TypeError: src/server/index.ts: 未发出(Emit skipped) 如果未被注释掉

答案#1

NPM 工作区仍然需要你在根目录(即包含工作区定义/位置的 package.json 所在的目录)运行 npm install,以便创建到本地包的相关符号链接。

当你那样做时,你应该得到:

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

每次你创建一个新的本地包文件夹并在其中放入 package.json 并希望从其他地方访问时,你都必须重新运行它。

答案#2

最近遇到了这个问题,这对我们来说的解决方法是:

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

为了让 ts-node 能看到其他 monorepo 包,它需要这个入口

相关文章