'package.json'不在'rootDir'



我正在尝试在我的 TypeScript 应用程序中导入package.json

import packageJson from '../package.json';

我的tsconfig.json包含以下内容:

{
"compilerOptions": {
"rootDir": "./src/"
"outDir": "./dist/",
"baseUrl": ".",
"resolveJsonModule": true
}
}

问题是当我编译这个时,我得到

error TS6059: File '/path/to/package.json' is not under 'rootDir' '/path/to/app/src/'. 'rootDir' is expected to contain all source files.

我不确定我是否理解这个问题,因为./src//.dist都有相同的父..,所以 TypeScript 可以不理会import '../package.json'它可以rootDiroutDir工作。

无论如何,我尝试了以下方法,结果不令人满意:

  • 删除rootDir- 编译有效,但dist将包含我不想要的dist/src
  • 删除outDir- 然后src.js文件污染(如果sourceMap是真的,.js.map)
  • 添加@ts-ignore- 编译将停止导入../package.json的文件

此限制的解决方法是什么,将生成的文件保留在dist中,并允许从rootDir的父目录导入?

这是可能的,事实证明,并不难

解决方案不明显的原因是 Typescript 依赖于rootDir来决定输出的目录结构(参见 Typescript 老板的这条评论),并且只能导入输出或包依赖项中包含的代码。

  • 如果将rootDir设置为项目的根目录,则package.json将发出到outDir根目录,并且可以导入。但是,您编译的src文件将写入outDir/src
  • 如果将rootDir设置为src,则其中的文件将编译为outDir的根目录。 但是现在编译器没有地方发出package.json,所以它发出"一个错误,因为项目似乎配置错误"(老板的话)。

解决方案:使用单独的 Typescript 子项目

每个 Typescript项目都是自包含的,由自己的tsconfig定义,具有自己的rootDir。这与封装原理一致。

您可以有多个项目(例如,一个主库和一组库),每个项目都有自己的rootDir并具有自己的 tsconfig。 它们之间的依赖关系是使用 Typescript 项目引用在依赖项的tsconfig中声明的。

我承认,"项目"这个词很糟糕,因为直觉上它指的是整个 shebang,但"模块"和"包"已经被采用。将它们视为子项目,这将更有意义。

为了解决您的特定问题,我们将src目录和包含package.json的根目录视为单独的项目。每个人都有自己的tsconfig

  1. src目录提供自己的项目。

    ./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`
    ]
    }
    
  2. 为根目录提供自己的项目。

    ./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, you avoid the default TS behavior, which
    "package.json"   // will include everything, resulting in `src` being included in both projects (bad)
    ]
    }
    
  3. tsc --build src,瞧!

    这将生成src项目。因为它声明了对根项目的引用,所以它也会生成该根项目,但前提是它已过期。因为根 tsconfig 与outDir具有相同的目录,tsc 不会简单地package.json它配置编译的一个文件。

这非常适合单存储库

  • 您可以通过将模块/库/子项目放在它们自己的子目录中并赋予它们自己的 tsconfig 来隔离它们。

  • 您可以使用项目引用显式管理依赖项,以及模块化构建:

    从链接的文档:

    • 您可以大大缩短构建时间

      期待已久的功能是 TypeScript 项目的智能增量构建。在 3.0 中,您可以将--build标志与tsc一起使用。这实际上是tsc的新入口点,其行为更像是生成业务流程协调程序,而不是简单的编译器。

      运行tsc --build(简称tsc -b)将执行以下操作:

      • 查找所有引用的项目
      • 检测它们是否为最新
      • 以正确的顺序构建过时的项目

      不用担心对在命令行上传递的文件进行排序 - 如果需要,tsc会重新排序它们,以便始终首先构建依赖项。

    • 在组件之间强制实施逻辑分离

    • 以新的和更好的方式组织您的代码。

这也很容易:

  1. 共享选项和构建所有选项的根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" }
    ]
    }
    
  2. 阻止从 其他子项目,因为它没有项目引用

    src/common/tsconfig.json

    {
    "extends": "../tsconfig.json", //inherit from root tsconfig
    // but override these:
    "compilerOptions": {
    "rootDir": ".",
    "outDir": "../../build/common",
    "resolveJsonModule": true,
    "composite": true
    }
    }
    
  3. 由于声明的引用而可以导入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" }
    ]
    }
    

我们可以将resolveJsonModule设置为 false 并在typings.d.ts中声明一个用于*.json的模块,这将需要 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内容

{
"name": "my-app",
"version": "0.0.1",
...
}

lib/package.json内容

{
"name": "my-lib",
"version": "1.0.1",
...
}

现在如果我们使用tsc编译项目,我们将得到以下dist目录结构:

app
└─ dist
├─ index.d.ts
└─ index.js

如果我们使用node ./dist运行它,我们将从applibpackage.json信息中获得输出:

$ node ./dist
App name "my-app" with version 0.0.1
Lib name "my-lib" with version 1.0.1

您可以在此处找到项目存储库:https://github.com/clytras/typescript-monorepo

对于使用 ES 模块而不是 CommonJS 的软件包,有一个整洁的三步解决方案,包括 Node 16+ LTS 和 TypeScript 4.7+。

package.json中的"imports"字段定义了只能从实际包中导入的内部伪包。定义内部导入说明符,例如package.json中的#package.json

{
"type": "module",
"exports": "./dist/index.js",
"imports": {
"#package.json": "./package.json"
}
}

tsconfig.json中为 ES 模块和 JSON 导入启用 TypeScript 支持:

{
"compilerOptions": {
"module": "nodenext",
// "moduleResolution" defaults to "nodenext", just made explicit here
"moduleResolution": "nodenext",
"resolveJsonModule": true,
}
}

最后,从 TypeScript 模块导入#package.json

import packageJson from '#package.json' assert { type: 'json' };
console.log(packageJson);

目前不可能。Typescript 编译器尝试保留您的目录结构。

例如,您的项目如下所示:

src/
shared/
index.ts
index.ts
package.json
tsconfig.json

您的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/**/*"
]
}

如您所见,该文件不包含rootDir属性,但是当您调用tsc命令来编译项目时,输出将如下所示:

build/
shared/
index.js
index.js

输出不包含src文件夹,因为在我的代码中,我只是在文件夹中导入和使用src,例如:

src/index.ts

import someName from './shared';

然后,build/index.js将如下所示:

...
const shared_1 = __importDefault(require("./shared"));
...

如您所见 -require("./shared"),这意味着它可以在文件夹结构build正常工作。

导入"外部"模块时出现"问题">

import packageJson from '../package.json';

那么,"后退"行动会发生什么 - '../'?如果你希望你的输出结构是:

build/
package.json
index.js

然后,他们如何与const packageJson = __importDefault(require("../package.json"));一起工作.然后 Typescript 编译器尝试保持项目结构:

build/
package.json
src/
index.js

对于 monorepo 项目,我认为您需要为每个库创建声明文件,结束然后在 tsconfig 文件中使用references设置。前任:

  1. ./lib01文件夹中,库导入./lib02其代码中。Tsconfig 文件将如下所示:
{
"compilerOptions": {
"declarationDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"],
"references": [ // here
{
"path": "../lib02"
}
]
}
  1. lib02 的tsconfig.json
{
"compilerOptions": {
"declarationDir": "dist",
"rootDir": "src",
"composite": true // importance.
}
}

这取决于您阅读"package.json"的方式和时间。您可以在运行时使用 NodeJS "fs" 模块将其读取为文件,或者只需键入 const package = require("package.json")。

在第两种情况下,Typescript 将在编译时在根目录中搜索它(请参阅 Typescript 模块解析文档)。

您还可以使用"rootDirs"属性而不是"rootDir"来指定根文件夹数组。

import调用之上使用// @ts-ignore并设置"rootDir": "./src"它工作时。在这种情况下,启用resolveJsonModule仍然有效,但仅适用于./src下的文件。请参阅:https://github.com/MatrixAI/TypeScript-Demo-Lib/pull/33 了解如何将其应用于我们的模板存储库。这样就可以像往常一样从./src内部导入 json 文件,但是当您导入../package.json时,您必须使用// @ts-ignore来确保 TSC 忽略它。这是一个一次性的特例,所以这是有效的。

这一切起作用的原因是因为 设置 https://www.typescriptlang.org/tsconfig#rootDir 将强制 TSC 不推断项目根目录为 SRC。因此将强制执行预期的dist结构,同时在导入rootDir外时引发警告/错误。但您可以忽略这些警告。

我通过使用符号链接来解决这个问题: 在窗口中:

cd src
mklink package.json ..package.json

或在 Linux 中:

cd src
ln -s package.json ../package.json

相关内容

  • 没有找到相关文章

最新更新