情况:您有一个typescript项目,它被配置为还输出JSON文件。您拥有正确的tsconfig.json
设置和正确的依赖关系。你也读过这个相关的问答;并确保您的typescript文件导入json文件。然而,当您运行tsc
时,您会注意到json文件丢失了。
然后将项目复制到一个单独的位置,使用完全相同的文件布局、完全相同的二进制文件,并运行tsc
。现在,生成json
文件。WTFNODE?
这是一个最小的repo,使用节点v16.13.2和纱线v1.22.7
参考项目
假设您已准备好安装nodejs
和yarn
。如果使用Nix
,则可以通过nix-shell -p yarn nodejs
实现。然后:
pwd
# /tmp/foolib
yarn init -y # blank project
yarn add typescript # this is all we need for the repro
export PATH=$(yarn bin):$PATH # make sure we see `tsc` in the path
其余文件:
src/index.ts
import Thing from './moveme.json'
console.log("Hello")
src/moveme.json
{ "foo": "bar" }
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2015",
"declarationMap": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"outDir": "./dist",
"skipLibCheck": true,
"declaration": true,
"jsx": "react"
},
"include": [
"src/**/*"
]
}
如果运行rm -rf dist;export PATH=$(yarn bin):$PATH; tsc; find dist
,应该会看到以下输出:
dist
dist/index.d.ts
dist/index.d.ts.map
dist/moveme.json
dist/index.js
另一个项目
假设您正在将项目作为库导入其他地方。让我们用这种方式创建一个假的:
mkdir /tmp/fooproject
cd /tmp/fooproject
yarn init -y # this creates package.json, yarn.lock, node_modules
cp -R /tmp/foolib ./node_modules/ # create a local copy
cd node_modules/foolib
tsc
现在,find dist
的输出
dist
dist/index.d.ts
dist/index.d.ts.map
dist/index.js
为什么没有moveme.json
tl;dr
当您从真实路径(解析符号链接后)包含node_modules
目录的位置运行tsc
时,json文件将不会被复制。
快速修复
根据tsc
的工作方式,在node_modules
中的某个目录之外运行tsc
可能被认为是一种糟糕的做法。但是,如果在某个时候你决定这样做,最快的方法是在不同的位置编译它,node_modules
不在路径层次结构中(你甚至可以重命名node_modules
并将其重新命名)。
解释
当您调用tsc
时,它会启动一组异步Worker
,解析源文件并计算代码依赖树。代码中引用的模块(如上例中导入的JSON文件)在这里被发现,然后由这里的工作逻辑解析。
因此,在我们的示例中,processImportedModules()
将发现index.ts
导入一个名为moveme.json
的模块。是否将此文件作为输出文件包括在内的决定取决于以下行:
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
因为它没有得到输出,我们知道tsc
认为moveme.json
是一个";外部库导入";。该确定由tryResolve()
函数进行,特别是该行
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
最后告诉我们;模块";其路径中某处包含CCD_;"外部库导入";,并且不会被复制到输出文件夹中。
在跟踪源之后,这种行为在逻辑上是有意义的,但非常令人惊讶,因为看似孤立的项目的输出实际上取决于一直到文件系统根的结构。在没有这些知识的情况下,tsc
的行为是不一致的;给定:
inputs0 --{tsc}--> outputs1
来自/tmp/foolib
inputs0 --{tsc}--> outputs2
来自/tmp/fooproject/node_modules/foolib
此处,outputs1 != outputs2
有了这些知识,tsc
的行为是依赖于工作目录的。