【问题标题】:How to use yarn workspaces with typescript and out folders?如何使用带有打字稿和输出文件夹的纱线工作区?
【发布时间】:2019-08-27 17:04:17
【问题描述】:

我正在尝试使用 yarn 建立一个 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",
  }
}

在此模型中,cmdclient 都在其 tsconfig 中使用 outDirsourceRoot 字段集进行编译。这意味着他们所有编译的 javascript 都会进入 cmd/distclient/distdist/ 子文件夹

如果现在我尝试将 client 中的类引用到 cmd

import Foo from 'client/src/foo'

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

然而,编译后的 javascript 归结为一个

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

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

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

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

【问题讨论】:

  • 旁注:我使用lerna 设置了一个monorepo,发现它非常有价值,它也应该适用于yarn。 (我将它与 npm 一起使用。)
  • 我记得处理过这样的事情。如果您想发布一个可以重现问题的存储库链接,我会看看。
  • 看看这个 repo。他们做得很好。仔细看github.com/apollographql/apollo-client

标签: node.js typescript yarnpkg yarn-workspaces


【解决方案1】:

我创建了一个 Github Repository 以便更容易遵循以下代码描述:


代码说明

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


TypeScript 设置

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

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

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

cmd/tsconfig.json:

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

构建顺序

client/
  ^
  |
  |
 cmd/

节点设置

最佳实践是每个子项目都有自己的package.json 文件,其中包含main 属性和name 集。在我们的示例中,两个包(cmd/client/)都有一个 main 属性,指向 TypeScript outDir 目录(cmd/dist/index.jsclient/dist/index.js)中的 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/ 作为依赖添加到 cmd/packages.json 以便模块解析算法可以找到 @ 987654359@ 当我们在我们的 TypeScript 代码中导入它时 import 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,请将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 文件。

【讨论】:

  • @devshorts 这对你有用吗?还是您在我的解决方案中遗漏了什么?
  • 很好的答案。自从我发布了这个问题以来,我早就以这种方式进行了设置。我最初的问题是不理解您必须拥有“dist”文件夹,如果您希望导入干净,则需要从索引模块中导出它们。
  • 非常好的文章!我没有找到根级 tsconfig 文件的用途。在其上调用 tsc 不会构建软件包,除非您想将其用作继承的基本配置,否则它似乎是多余的。由于每个包仍然需要它们自己的引用设置,我看不出根级引用的目的是什么。
  • 如果您在“client”项目的“src”中添加一个带有“index.ts”的“sub”文件夹,并尝试从另一个项目导入它,您会得到以下信息错误:“TS2307:找不到模块‘客户端/子’”。你知道怎么解决吗?
  • @Finickyflame 你是如何导入包的?导入项目是 JavaScript 还是 TypeScript 项目?
【解决方案2】:

我已经设置了一个monorepo,我在this repository 中使用Yarn Workspaces 和Typescript 在我的项目中一直使用一些配置。

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

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

yarn install 之后,根node_modules 具有clientcmd 作为链接文件夹。

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

// cmd/src/index.ts

import { name } from 'client';

const otherName = 'cmd' + name;

console.log(otherName);

【讨论】:

  • 如果您之前没有构建客户端,则构建将无法从 cmd 运行。错误 TS2307:找不到模块“客户端”。
  • 在尝试构建之前,您是否在根目录下运行了yarn
  • 是的,当然。删除所有“dist”目录并尝试自己。
  • 我明白了。使用我建议的配置,您不能删除 dist 文件夹,它是您代码的一部分。也许我完全误解了这个问题,如果 dist 不应该是存储库的一部分,我的解决方案将不起作用。
猜你喜欢
  • 2022-12-18
  • 1970-01-01
  • 2018-11-03
  • 2021-06-03
  • 2018-07-18
  • 2019-04-08
  • 2022-12-08
  • 2021-12-18
  • 2021-03-27
相关资源
最近更新 更多