30

我正在尝试使用纱线建立一个 monorepo。我对如何使用项目引用设置打字稿以使事情正确解决感到困惑。

例如,如果我有一个像这样的文件夹结构

/cmd
/client

我想cmd依靠client我可以拥有:

cmd/tsconfig.json

{
  "compilerOptions": {
    "types": ["reflect-metadata", "jest"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": "node",
    "declaration": true,
    "importHelpers": true,
    "composite": true,
    "target": "esnext"
    "sourceRoot": "src",
    "outDir": "dist"
  },
  "references": [
    {
      "path": "../client"
    }
  ],
  "include": [
    "src/**/*"
  ]
}

package.json

{
  "name": "cmd",
  "version": "1.0.0",
  "dependencies": {
    "client": "^1.0.0",
  }
}

在此模型中,两者都使用tsconfig 中设置的cmd和字段进行编译。这意味着他们所有编译的 javascript 都进入了andclientoutDirsourceRootdist/cmd/distclient/dist

如果现在我尝试引用一个类 from clientinto cmdlike

import Foo from 'client/src/foo'

IDE 非常乐意解决这个问题,因为它似乎是通过 typescriptreferences属性映射的。

但是,编译后的 javascript 归结为

const foo_1 = require("client/src/foo");

但是,实际构建的 javascript 是 in client/dist/src/foo,因此在运行时这永远不会起作用。

另一方面,如果我不使用 sourceRoots 和 outDirs 并且在同一个文件夹中将 javascript 与打字稿文件内联,那么一切都可以正常工作(但会使 repo 变脏并且需要自定义 gitignores 来排除东西)

任何人都可以阐明如何正确设置带有纱线工作区的 typescript 3.x monorepo 以使事情正常工作吗?

4

2 回答 2

73

我创建了一个 Github存储库,以便更轻松地遵循以下代码描述:


代码说明

TypeScriptProject References可以编译由多个较小的 TypeScript 项目组成的 TypeScript 项目,每个项目都有一个tsconfig.json文件。(来源:项目参考文档


打字稿设置

我们有一个tsconfig.json只管理其子项目的根文件。该references属性指定每个包含有效tsconfig.json文件的目录。如果我们现在使用--build选项 ( tsc --build tsconfig.json) 构建项目,那么我们指定了应该编译的项目,但我们没有指定项目应该编译的构建顺序

{
  "references": [
    { "path": "./client" },
    { "path": "./cmd" }
  ],
  "files": [],
  "include": [],
  "exclude": ["**/node_modules"]
}

要正确指定构建顺序,我们需要references在文件中添加一个属性cmd/tsconfig.jsonclient/这告诉编译器在我们编译之前它首先需要编译cmd/

cmd/tsconfig.json

{
  "extends": "../tsconfig.packages.json",
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "dist"
  },
  "references": [
    {
      "path": "../client"
    }
  ]
}

建造顺序

client/
  ^
  |
  |
 cmd/

节点设置

最佳实践是每个子项目都有自己的package.json文件,其中包含main属性和name集合。在我们的示例中,两个包 (cmd/client/) 都有一个main指向index.jsTypeScriptoutDir目录中文件的属性 (cmd/dist/index.jsclient/dist/index.js)。

项目结构:

tsconfig.json
cmd/
    tsconfig.json
    package.json
    src/
        index.ts
    dist/  #artifacts
        index.js
client/
    tsconfig.json
    package.json
    src/
        index.ts
    dist/  #artifacts
        index.js

client/packages.json

{
  "name": "client",
  "version": "1.0.0",
  "main": "dist/index",
  ...
}

重要是我们将client/as 依赖添加到 中,这样当我们在 TypeScript 代码中导入它时cmd/packages.json,模块解析算法可以找到:client/dist/index.jsimport Foo from 'client';

cmd/packages.json

{
  "name": "cmd",
  "version": "1.0.0",
  "main": "dist/index",
  "dependencies": {
    "client": "1.0.0" // important
  }
}

cmd/src/index.ts

import Foo from 'client';

console.log(Foo())

纱线设置

纱线设置很简单。Yarn 将所有包添加到下面node_modules而不是:

  • cmd/node_modules
  • client/node_modules

要启用纱线工作区,请将workspaces属性和private: true属性添加到<root>/package.json文件中。

<root>/package.json

{
  "private": true,
  "workspaces": [
    "cmd",
    "client"
  ],
  "name": "yarn_workplace",
  "version": "1.0.0"
  ...
}

和包在目录cmd/下:client/symlinked<root>/node_modules/

纱线节点模块


笔记

  • 要启用代码导航,必须首先构建项目
  • 每个包都是独立存在的。该cmd/包使用定义文件client/dist/index.d.ts来获取类型信息,而不是直接使用 TypeScript 文件。
于 2019-10-04T14:19:26.183 回答
-1

我已经使用此存储库中的 Yarn Workspaces 和 Typescript 在我的项目中使用了一些配置设置了一个 monorepo 。

我不知道这个设置是否能解决你的问题,但你不需要在 Typescript 配置中指定你的包。当您使用 Yarn Workspaces 时,它会链接您在 rootnode_modules的工作空间包属性中定义的所有包package.json

"workspaces": {
    "packages": [
        "packages/**/*"
    ],
    "nohoist": []
}

之后yarn install,根node_modulesclientcmd作为链接文件夹。

在此处输入图像描述

使用此配置,您可以简单地在 Workspace 内的任何包中导入任何包。例如:

// cmd/src/index.ts

import { name } from 'client';

const otherName = 'cmd' + name;

console.log(otherName);
于 2019-10-01T12:46:35.350 回答