如何使用 `tsc` 和 `npm install` 解决 Chicken/Egg 的情况?

How to resolve Chicken/Egg situation with `tsc` and `npm install`?

所以我有标准的文件夹结构

dist/
src/

其中 src 有我的 .ts 文件,dist 有我的 .js 文件。 (我的 tsconfig.json 文件中有 "outDir":"dist""includes" 设置为 'src')。

注意 'dist' 在我的 gitignore 文件中,所以它不在版本控制中,所以当它转到 Travis 或 CircleCIdist 文件夹中没有任何内容,直到我 运行 tsc.

这是 问题 - 如果我先 运行 npm install - 它会失败,因为我的 package.json 中有这个:

"bin":{
  "foo" :"dist/cli.js"   // dist/cli.js does not exist yet
}

但是如果我先 运行 tsc - tsc 将缺少编译所需的依赖项,如果我 运行 npm install.

我能想到的 解决这个问题的方法是先安装所有必需的 tsc 依赖项,然后 运行 tsc,然后 运行 npm install --production.

然而,这并不是最方便的做法。

有没有人运行解决这个问题并找到好的解决方案?

我不记得有过这个问题,但至少在一个案例中我做了一些事情可以解决这个问题。

我在根文件夹中放置了一个 index.js,运行 是 dist 中的实际依赖项。然后 npm 查找的 bin 是一个存在的文件,它不应该惊慌失措。

当然,在 tsc 为 运行 之前,它不会起作用。但它应该可以解决您的先有鸡还是先有蛋的问题。

看起来 preinstall 脚本正是您所需要的

将您的 package.json 文件添加为

{
  "scripts": {
    "preinstall" : "tsc ..." // < build stuff
  }
}

引用https://docs.npmjs.com/misc/scripts

我会签入一个文件./lib/cli文件内容是

#!/usr/bin/env node
require('../dist/cli.js')

并且 运行 npm 通常后跟 tsc。

绝对不是你的答案,但我通常更愿意提交 javascript。

缺点:大量额外 git history/bloat。

我的观点:

  • 最终您正在制作一个 javascript 项目。因此,应该测试 javascript 运行时,如果该项目也应该从打字稿中使用,请测试生成的 .d.ts;
  • 生成代码的 TSC 版本不应成为测试和消费者的另一个移动部分。您将针对许多 TSC 版本测试生成的输出,而不是您的源代码。
  • 通过包含 .js 和 .d.ts 来减少 "moving parts" 边界,您获得的(= 可预测性)远多于您失去的(git 历史膨胀)。

@wkrueger 的回答很接近。

这里的目标是只允许一个俗气的步骤工作,而不实际让它做任何有用的事情。这个俗气的步骤是在安装步骤中通过 bin 使文件引用可执行,这对于本地模块只对非转译的 JavaScript 有意义,至于转译的代码文件还不存在.幸运的是,这个俗气的步骤实际上并不关心文件是否可用,它只需要它存在就可以 chmod 它不会失败。

我解决这个问题的方法是简单地签入一个空的 dist/index.js 文件:

touch dist/index.js

然后将 dist 添加回 .gitignore,因为您不想签入文件的真实版本。

在 NPM 6 中,我会在 package.json 中使用 preinstall 脚本,但这在 NPM 7 中已损坏,我碰巧正在使用它,我对转换为钩子不太感兴趣只是为了解决这个问题。如果您使用的是 NPM 6 或更早版本,preinstall 脚本将如下所示:

  ...
  "scripts": {
    "preinstall": "mkdir -p dist/ && touch dist/index.js"
  }
  ...