[英]'package.json' is not under 'rootDir'
I'm trying to import package.json
in my TypeScript application:我正在尝试在我的 TypeScript 应用程序中导入
package.json
:
import packageJson from '../package.json';
My tsconfig.json
contains the following:我的
tsconfig.json
包含以下内容:
{
"compilerOptions": {
"rootDir": "./src/"
"outDir": "./dist/",
"baseUrl": ".",
"resolveJsonModule": true
}
}
The problem is that when I compile this, I get问题是当我编译这个时,我得到
error TS6059: File '/path/to/package.json' is not under 'rootDir' '/path/to/app/src/'. 'rootDir' is expected to contain all source files.
I'm not sure I understand the issue, because both ./src/
and /.dist
have the same parent ..
, so TypeScript could just leave alone the import '../package.json'
and it would work from either rootDir
or outDir
.我不确定我是否理解这个问题,因为
./src/
和/.dist
都有相同的父级..
,所以 TypeScript 可以只保留import '../package.json'
并且它可以从任rootDir
工作或outDir
。
Anyway, I've tried the following, with unsatisfactory results:无论如何,我尝试了以下方法,但结果并不令人满意:
rootDir
- compilation works, but the dist
will contain dist/src
, which I don't wantrootDir
- 编译工作,但dist
将包含dist/src
,我不想要outDir
- then src
gets polluted with .js
files (and .js.map
if sourceMap
was true)outDir
- 然后src
被.js
文件污染(如果sourceMap
.js.map
@ts-ignore
- compilation stops the the file that imports ../package.json
@ts-ignore
- 编译停止导入../package.json
的文件What's the workaround for this limitation, to keep generated files in dist
, and allow importing from the parent directory of rootDir
?这个限制的解决方法是什么,将生成的文件保存在
dist
中,并允许从rootDir
的父目录导入?
This is possible , and it turns out, not hard .这是可能的,而且事实证明并不难。
The reason the solution is not obvious is because typescript relies on the rootDir
to decide the directory structure of the output (see this comment from Typescript's bossman ), and only code included in the output or in package dependencies can be imported.解决方案不明显的原因是因为 typescript 依赖
rootDir
来决定输出的目录结构(参见Typescript 的 bossman 的这个评论),并且只能导入包含在输出中或包依赖项中的代码。
rootDir
to the root of your project, package.json
gets emitted to the root of outDir
and can be imported.rootDir
设置为项目的根目录,则package.json
会发送到outDir
的根目录并可以导入。 But then your compiled src
files get written to outDir/src
.src
文件被写入outDir/src
。rootDir
to src
, files in there will compile to the root of outDir
.rootDir
设置为src
,其中的文件将编译到outDir
的根目录。 But now the compiler won't have a place to emit package.json
, so it issues "an error because the project appears to be misconfigured" (bossman's words).package.json
,所以它发出“一个错误,因为项目似乎配置错误”(老板的话)。A Typescript project is defined by a tsconfig file, is self-contained, and is effectively bounded by its rootDir
. Typescript 项目由tsconfig文件定义,是自包含的,并且有效地受其
rootDir
。 This is a very good thing, as it lines up with principles of encapsulation .这是一件非常好的事情,因为它符合封装的原则。
You can have multiple projects (eg a main and a set of libs) each in their own directory and with their own tsconfig.您可以有多个项目(例如,一个主项目和一组库),每个项目都在它们自己的目录中并使用它们自己的 tsconfig。 Dependencies between them are declared in the tsconfig file using Typescript Project References .
它们之间的依赖关系是在 tsconfig 文件中使用 Typescript Project References声明的。
I admit, the term "projects" is a poor one, as intuitively it refers to the whole shebang, but "modules" and "packages" are already taken in this context.
我承认,“项目”这个词很糟糕,因为直观上它指的是整个 shebang,但是“模块”和“包”已经在这种情况下出现了。 Think of them as "subprojects" and it will make more sense.
将它们视为“子项目”,它会更有意义。
We'll treat the src
directory and the root directory containing package.json
as separate projects.我们将
src
目录和包含package.json
的根目录视为单独的项目。 Each will have its own tsconfig
file.每个都有自己的
tsconfig
文件。
Give the src
dir its own project.给
src
目录它自己的项目。
./src/tsconfig.json
: ./src/tsconfig.json
:
{ "compilerOptions": { "rootDir": ".", "outDir": "../dist/", "resolveJsonModule": true }, "references": [ // this is how we declare a dependency from { "path": "../" } // this project to the one at the root dir` ] }
Give the root dir its own project.给根目录它自己的项目。
./tsconfig.json
: ./tsconfig.json
:
{ "compilerOptions": { "rootDir": ".", "outDir": ".", // if out path for a file is same as its src path, nothing will be emitted "resolveJsonModule": true, "composite": true // required on the dependency project for references to work }, "files": [ // by whitelisting the files to include, TS won't automatically "package.json" // include all source below root, which is the default. ] }
run tsc --build src
and voilà!运行
tsc --build src
和瞧!
This will build the src
project.这将构建
src
项目。 Because it declares a reference to the root project, it will build that one also, but only if it is out of date.因为它声明了对根项目的引用,所以它也会构建那个,但前提是它已经过时了。 Because the root tsconfig has the same dir as the
outDir
, tsc will simply do nothing to package.json
, the one file it is configured to compile.因为根 tsconfig 与
outDir
具有相同的目录,所以 tsc 将简单地对package.json
(它配置为编译的一个文件)执行任何操作。
You can isolate modules/libraries/sub-projects by putting them in their own subdirectory and giving them their own tsconfig.您可以通过将模块/库/子项目放在它们自己的子目录中并给它们自己的 tsconfig 来隔离它们。
You can manage dependencies explicitly using Project References , as well as modularize the build:您可以使用Project References显式管理依赖项,以及模块化构建:
From the linked doc:从链接的文档:
you can greatly improve build times您可以大大缩短构建时间
A long-awaited feature is smart incremental builds for TypeScript projects.
期待已久的功能是 TypeScript 项目的智能增量构建。 In 3.0 you can use the
--build
flag withtsc
.在 3.0 中,您可以将
--build
标志与tsc
一起使用。 This is effectively a new entry point fortsc
that behaves more like a build orchestrator than a simple compiler.这实际上是
tsc
的一个新入口点,它的行为更像是一个构建协调器,而不是一个简单的编译器。Running
tsc --build
(tsc -b
for short) will do the following:运行
tsc --build
(简称tsc -b
)将执行以下操作:
- Find all referenced projects
查找所有引用的项目
- Detect if they are up-to-date
检测它们是否是最新的
- Build out-of-date projects in the correct order
以正确的顺序构建过时的项目
Don't worry about ordering the files you pass on the commandline -
tsc
will re-order them if needed so that dependencies are always built first.不必担心对在命令行中传递的文件进行排序 - 如果需要,
tsc
会重新排序它们,以便始终首先构建依赖项。
enforce logical separation between components强制组件之间的逻辑分离
organize your code in new and better ways.以新的更好的方式组织您的代码。
It's also very easy:这也很容易:
A root tsconfig
for shared options and to build all subprojects with a simple tsc --build
command (with --force
to build them from scratch)用于共享选项的根
tsconfig
并使用简单的tsc --build
命令构建所有子项目(使用--force
从头开始构建它们)
src/tsconfig.json
{ "compilerOptions": { "outDir": ".", // prevents this tsconfig from compiling any files // we want subprojects to inherit these options: "target": "ES2019", "module": "es2020", "strict": true, ... }, // configure this project to build all of the following: "references": [ { "path": "./common" } { "path": "./projectA" } ] }
A "common" library that is prevented from importing from the other subprojects because it has no project references由于没有项目引用而无法从其他子项目导入的“通用”库
src/common/tsconfig.json
{ "extends": "../tsconfig.json", //inherit from root tsconfig // but override these: "compilerOptions": { "rootDir": ".", "outDir": "../../build/common", "resolveJsonModule": true, "composite": true } }
A subproject that can import common because of the declared reference.由于声明的引用,可以导入common的子项目。
src/projectA/tsconfig.json
{ "extends": "../tsconfig.json", //inherit from root tsconfig // but override these: "compilerOptions": { "rootDir": ".", "outDir": "../../build/libA", "resolveJsonModule": true, "composite": true }, "references": [ { "path": "../common" } ] }
We can set resolveJsonModule
to false and declare a module for *.json
inside typings.d.ts
which will require JSON files as modules and it will generate files without any directory structure inside the dist
directory.我们可以将
resolveJsonModule
设置为 false 并在 typings.d.ts 中为*.json
typings.d.ts
声明一个模块,这将需要 JSON 文件作为模块,它将在dist
目录中生成没有任何目录结构的文件。
monorepo\
├─ app\
│ ├─ src\
│ │ └─ index.ts
│ ├─ package.json
│ ├─ tsconfig.json
│ └─ typings.d.ts
└─ lib\
└─ package.json
app/typings.d.ts
declare module "*.json";
app/src/index.ts
// Import from app/package.json
import appPackageJson from '../package.json';
// Import from lib/package.json
import libPackageJson from '../../lib/package.json';
export function run(): void {
console.log(`App name "${appPackageJson.name}" with version ${appPackageJson.version}`);
console.log(`Lib name "${libPackageJson.name}" with version ${libPackageJson.version}`);
}
run();
app/package.json
contents app/package.json
内容{
"name": "my-app",
"version": "0.0.1",
...
}
lib/package.json
contents lib/package.json
内容{
"name": "my-lib",
"version": "1.0.1",
...
}
Now if we compile the project using tsc
, we'll get the following dist
directory structure:现在,如果我们使用
tsc
编译项目,我们将得到以下dist
目录结构:
app\
└─ dist\
├─ index.d.ts
└─ index.js
And if we run it using node ./dist
, we'll get the output from both app
and lib
package.json
information:如果我们使用
node ./dist
运行它,我们将从app
和lib
package.json
信息中获取输出:
$ node ./dist
App name "my-app" with version 0.0.1
Lib name "my-lib" with version 1.0.1
You can find the project repository here: https://github.com/clytras/typescript-monorepo您可以在此处找到项目存储库: https ://github.com/clytras/typescript-monorepo
It is not possible for now.目前是不可能的。 Typescript compiler try to keep your directory structure.
Typescript 编译器尝试保持你的目录结构。
For example, your project look like:例如,您的项目如下所示:
src/
shared/
index.ts
index.ts
package.json
tsconfig.json
Your tsconfig.json
contains:您的
tsconfig.json
包含:
{
"compilerOptions": {
"outDir": "./build",
"module": "commonjs",
"target": "es6",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": true,
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true
},
"include": [
"src/**/*"
]
}
As you see, the file does not include rootDir
property, but when you call tsc
command to compile the project, the output will look like:如您所见,该文件不包含
rootDir
属性,但是当您调用tsc
命令编译项目时,输出将如下所示:
build/
shared/
index.js
index.js
The output does not contain src
folder, because in my code, I just import and use inside src
folder, like:输出不包含
src
文件夹,因为在我的代码中,我只是在src
文件夹中导入和使用,例如:
src/index.ts
import someName from './shared';
then, build/index.js
will look like:然后,
build/index.js
将如下所示:
...
const shared_1 = __importDefault(require("./shared"));
...
as you see - require("./shared")
, this mean it working fine with build
folder structure.如您所见 -
require("./shared")
,这意味着它可以在build
文件夹结构中正常工作。
Your "issue" appeared when you import a "outside" module导入“外部”模块时出现“问题”
import packageJson from '../package.json';
So, what happen with "back" action - '../'?那么,“后退”动作 - '../' 会发生什么? If you hope your output structure will be:
如果你希望你的输出结构是:
build/
package.json
index.js
then, how do they work with const packageJson = __importDefault(require("../package.json"));
那么,它们如何与
const packageJson = __importDefault(require("../package.json"));
. . Then Typescript compiler try to keep project structure:
然后 Typescript 编译器尝试保持项目结构:
build/
package.json
src/
index.js
With a monorepo project, I think you need to create declaration files for each library, end then use references
setting in the tsconfig file.对于 monorepo 项目,我认为您需要为每个库创建声明文件,然后使用 tsconfig 文件中的
references
设置。 Ex:前任:
./lib01
folder, the lib import ./lib02
in their code../lib01
文件夹中,lib 在其代码中导入./lib02
。 Tsconfig file will be like: {
"compilerOptions": {
"declarationDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"],
"references": [ // here
{
"path": "../lib02"
}
]
}
tsconfig.json
tsconfig.json
{
"compilerOptions": {
"declarationDir": "dist",
"rootDir": "src",
"composite": true // importance.
}
}
It depends on how and when you're reading "package.json".这取决于您阅读“package.json”的方式和时间。 You can read it as file with NodeJS "fs" module at runtime, or just type const package = require("package.json").
您可以在运行时使用 NodeJS "fs" 模块将其作为文件读取,或者只需键入 const package = require("package.json")。
In 2nd case Typescript will search it in root dir at compile time (refer to Typescript module resolution documentation).在第二种情况下,Typescript 将在编译时在根目录中搜索它(请参阅Typescript 模块解析文档)。
You also can use "rootDirs" property instead of "rootDir" to specify array of root folders.您还可以使用“rootDirs”属性而不是“rootDir”来指定根文件夹数组。
When using // @ts-ignore
on top of the import
call and setting "rootDir": "./src"
it works.在
import
调用之上使用// @ts-ignore
并设置"rootDir": "./src"
时,它可以工作。 In this case enabling resolveJsonModule
will still work, but only for files under the ./src
.在这种情况下,启用
resolveJsonModule
仍然有效,但仅适用于./src
下的文件。 See: https://github.com/MatrixAI/TypeScript-Demo-Lib/pull/33 for how I applied it to our template repository.请参阅: https ://github.com/MatrixAI/TypeScript-Demo-Lib/pull/33,了解我如何将其应用于我们的模板存储库。 This way it is possible to import json files from within
./src
as normal, but when you import ../package.json
, you have to use // @ts-ignore
to ensure that TSC ignores it.这样就可以像往常一样从
./src
中导入 json 文件,但是当你导入../package.json
时,你必须使用// @ts-ignore
来确保 TSC 忽略它。 It's a one-off special case so this works.这是一次性的特殊情况,所以这是可行的。
The reason it all works is because setting https://www.typescriptlang.org/tsconfig#rootDir will force tsc not to infer the project root dir to be the src.一切正常的原因是因为设置https://www.typescriptlang.org/tsconfig#rootDir将强制 tsc 不将项目根目录推断为 src。 And thus will enforce the expected
dist
structure, while throwing warnings/errors on importing outside the rootDir
.因此将强制执行预期的
dist
结构,同时在rootDir
之外导入时抛出警告/错误。 But you can ignore these warnings.但是您可以忽略这些警告。
There is a tidy three-step solution with Node 16+ LTS and TypeScript 4.7+ for packages that use ES modules instead of CommonJS.对于使用ES 模块而不是 CommonJS 的包,Node 16+ LTS 和 TypeScript 4.7+ 有一个整洁的三步解决方案。
The "imports"
field in package.json defines internal pseudo-packages that can be imported only from within your actual package. package.json中的
"imports"
字段定义了只能从实际包中导入的内部伪包。 Define an internal import specifier, such as #package.json
in package.json :定义一个内部导入说明符,例如 package.json 中的
#package.json
package.json :
{
"type": "module",
"exports": "./dist/index.js",
"imports": {
"#package.json": "./package.json"
}
}
Enable TypeScript support for ES modules and JSON imports in tsconfig.json :在tsconfig.json中启用对 ES 模块和 JSON 导入的 TypeScript 支持:
{
"compilerOptions": {
"module": "nodenext",
// "moduleResolution" defaults to "nodenext", just made explicit here
"moduleResolution": "nodenext",
"resolveJsonModule": true,
}
}
Lastly, import #package.json
from your TypeScript module:最后,从 TypeScript 模块导入
#package.json
:
import packageJson from '#package.json' assert { type: 'json' };
console.log(packageJson);
I solve this problem by using symlink: in windows:我通过使用符号链接解决了这个问题:在 Windows 中:
cd src
mklink package.json ..\package.json
or in linux:或在linux中:
cd src
ln -s package.json ../package.json
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.