依赖同一个公共本地模块打包多个 Typescript 项目
Packaging multiple Typescript projects depending on the same common local module
我正在研究一组 VSTS 扩展。每个扩展都是它自己的小 Node 项目,有自己的 package.json
和自己的 node_modules
文件夹。文件夹结构如下:
- MyExtension
- package.json // containing all dev-dependencies
- tslint.json
- Tasks
- tsconfig.json
- Common
- common.ts // containing functioanlity shared across tasks
- package.json // containing all runtime dependencies for all projects
- My1stTask
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
- ...
- ...
- My6thTask
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
VSTS 构建任务的工作方式是它们应该是完全独立的。到目前为止,我已经通过将 Common
项目的内容复制到每个任务中,然后 运行 tsc
将它们全部转换为 JavaScript 来解决此问题。
这还不错,但需要不断复制 Common 的内容才能进行任何测试。
我尝试使用本地文件引用,在每个任务的 package.json 到 file:../common
中添加了一个依赖项,这在开发时有效,但这不会导致公共模块成为生成扩展后的任务。
我的背景不是 Node 开发,而是 C#。我到处搜索,但没有找到适用于 vsts-extensions 的解决方案。
npm pack
似乎不起作用,因为扩展希望所有文件都在那里。
package.json/bundleDependencies
看起来很有希望,但没有捆绑本地文件引用。
///<reference path="../common/common.ts"/>
非常适合编辑,但在构建扩展后仍然无法 运行。
- 带前缀的项目引用不起作用,构建任务需要 commonjs 模块解析器。系统和 AMD 无法加载模块。 Prepend 仅适用于后者。
有没有一种方法可以使这项工作 "seamlessly" 无需使用 bower 或 g运行t 并且只需让每个 MyXthTask 在其 node_modules
文件夹?
如果您愿意为每个任务生成单个文件作为输出(并使用兼容的模块加载器)而不是生成单独的模块,则可以使用 project references with the prepend
option。
如果您需要多文件输出,请参阅 以获得 TypeScript 建议和可能的解决方法。
我尝试了@matt-mccutchen 的方法,但不幸的是,由于这些任务需要 commonjs
:
,我无法将其用于 VSTS 构建任务
"compilerOptions": {
"module": "commonjs",
"target": "es6",
但我确实找到了适合我的解决方案。
在 Tasks
文件夹中,我添加了一个 tsconfig.json
,它定义了我的默认设置并包含来自公共库的文件:
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"sourceMap": true,
"strict": false,
"strictNullChecks": false,
"removeComments": true
},
"files": [
"./Common/uuidv5.d.ts",
"./Common/Common.ts"
]
}
然后在每个任务中,我创建了一个 tsconfig.json
,它将输出文件夹设置为该项目的当前文件夹,并且继承自 Tasks
文件夹中的 tsconfig.json
:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "./",
"sourceRoot": "./"
},
"files": [
"InstallExtension.ts"
]
}
这导致:
- MyExtension
- package.json // containing all dev-dependencies
- tslint.json
- Tasks
- tsconfig.json // Including Common by default
- Common
- common.ts // containing functionality shared across tasks
- package.json // containing all runtime dependencies for Common
- tsconfig.json // containing build configuration for just the common files, inherits from ..\Task\tsconfig.json
- My1stTask
- package.json // containing all prod-dependencies for the task
- task.ts // containing task implementation
- tsconfig.json // containing build configuration for the task, inherits from ..\Task\tsconfig.json
- ...
- ...
- My6thTask
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
- tsconfig.json // containing build configuration for the task, inherits from ..\Task\tsconfig.json
编译任务时如下
- My6thTask
- Common
- Common.js // Compiled common
- My6thTask
- task.js // Compiled task
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
- task.json // defining the task UI
- tsconfig.json // containing build configuration for the task
我唯一要添加到 task.ts
的是以下内容:
///<reference path="../Common/Common.ts"/>
import * as common from "../Common/Common";
并更改 task.json 中的执行处理程序以指向新位置:
"execution": {
"Node": {
"target": "InstallExtension/InstallExtension.js", // was: InstallExtension.js
"argumentFormat": ""
}
}
一切似乎都很好 :D。结合使用 glob-exec
我已经能够在构建 clean 时将构建时间减少到不到一分钟:
"initdev:npm": "npm install & glob-exec --parallel --foreach \"Tasks/*/tsconfig.json\" -- \"cd {{file.dir}} && npm install\"",
"compile:tasks": "glob-exec \"Tasks/*/tsconfig.json\" -- \"tsc -b {{files.join(' ')}}\"",
"lint:tasks": "glob-exec --parallel --foreach \"Tasks/*/tsconfig.json\" -- \"tslint -p {{file}}\"",
项目引用在我的情况下效果不佳,所以我使用 webpack 和 ts-loader 来构建我的项目。
将所有 ts 代码放在单个 root 下,使用单个 tsconfig,这样它就会像这样。
ts
-core
-plugin1
-plugin2
从 3.10 开始,webpack 允许 multiple output configurations。所以我们可以像这样使用单个配置文件。
const path = require("path");
const commonTsRule = {
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
};
const commonConfig = {
devtool: "inline-source-map",
mode: "development",
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
};
module.exports = [
{
...commonConfig,
entry: `${path.resolve(__dirname, "ts")}/plugin1/index.ts`,
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build/plugin1/js"),
},
module: {
rules: [
{
...commonTsRule,
// here you can customize rule if required
},
],
},
},
{
...commonConfig,
entry: `${path.resolve(__dirname, "ts")}/plugin2/index.ts`,
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build/plugin2/js"),
},
module: {
rules: [
{
...commonTsRule
// here you can customize rule if required
},
],
},
},
];
因此,作为最终结果,您将从每个项目自己的入口点构建到自己的输出目标。
我正在研究一组 VSTS 扩展。每个扩展都是它自己的小 Node 项目,有自己的 package.json
和自己的 node_modules
文件夹。文件夹结构如下:
- MyExtension
- package.json // containing all dev-dependencies
- tslint.json
- Tasks
- tsconfig.json
- Common
- common.ts // containing functioanlity shared across tasks
- package.json // containing all runtime dependencies for all projects
- My1stTask
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
- ...
- ...
- My6thTask
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
VSTS 构建任务的工作方式是它们应该是完全独立的。到目前为止,我已经通过将 Common
项目的内容复制到每个任务中,然后 运行 tsc
将它们全部转换为 JavaScript 来解决此问题。
这还不错,但需要不断复制 Common 的内容才能进行任何测试。
我尝试使用本地文件引用,在每个任务的 package.json 到 file:../common
中添加了一个依赖项,这在开发时有效,但这不会导致公共模块成为生成扩展后的任务。
我的背景不是 Node 开发,而是 C#。我到处搜索,但没有找到适用于 vsts-extensions 的解决方案。
npm pack
似乎不起作用,因为扩展希望所有文件都在那里。package.json/bundleDependencies
看起来很有希望,但没有捆绑本地文件引用。///<reference path="../common/common.ts"/>
非常适合编辑,但在构建扩展后仍然无法 运行。- 带前缀的项目引用不起作用,构建任务需要 commonjs 模块解析器。系统和 AMD 无法加载模块。 Prepend 仅适用于后者。
有没有一种方法可以使这项工作 "seamlessly" 无需使用 bower 或 g运行t 并且只需让每个 MyXthTask 在其 node_modules
文件夹?
如果您愿意为每个任务生成单个文件作为输出(并使用兼容的模块加载器)而不是生成单独的模块,则可以使用 project references with the prepend
option。
如果您需要多文件输出,请参阅
我尝试了@matt-mccutchen 的方法,但不幸的是,由于这些任务需要 commonjs
:
"compilerOptions": {
"module": "commonjs",
"target": "es6",
但我确实找到了适合我的解决方案。
在 Tasks
文件夹中,我添加了一个 tsconfig.json
,它定义了我的默认设置并包含来自公共库的文件:
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"sourceMap": true,
"strict": false,
"strictNullChecks": false,
"removeComments": true
},
"files": [
"./Common/uuidv5.d.ts",
"./Common/Common.ts"
]
}
然后在每个任务中,我创建了一个 tsconfig.json
,它将输出文件夹设置为该项目的当前文件夹,并且继承自 Tasks
文件夹中的 tsconfig.json
:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "./",
"sourceRoot": "./"
},
"files": [
"InstallExtension.ts"
]
}
这导致:
- MyExtension
- package.json // containing all dev-dependencies
- tslint.json
- Tasks
- tsconfig.json // Including Common by default
- Common
- common.ts // containing functionality shared across tasks
- package.json // containing all runtime dependencies for Common
- tsconfig.json // containing build configuration for just the common files, inherits from ..\Task\tsconfig.json
- My1stTask
- package.json // containing all prod-dependencies for the task
- task.ts // containing task implementation
- tsconfig.json // containing build configuration for the task, inherits from ..\Task\tsconfig.json
- ...
- ...
- My6thTask
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
- tsconfig.json // containing build configuration for the task, inherits from ..\Task\tsconfig.json
编译任务时如下
- My6thTask
- Common
- Common.js // Compiled common
- My6thTask
- task.js // Compiled task
- package.json // containing all prod-dependencies
- task.ts // containing task implementation
- task.json // defining the task UI
- tsconfig.json // containing build configuration for the task
我唯一要添加到 task.ts
的是以下内容:
///<reference path="../Common/Common.ts"/>
import * as common from "../Common/Common";
并更改 task.json 中的执行处理程序以指向新位置:
"execution": {
"Node": {
"target": "InstallExtension/InstallExtension.js", // was: InstallExtension.js
"argumentFormat": ""
}
}
一切似乎都很好 :D。结合使用 glob-exec
我已经能够在构建 clean 时将构建时间减少到不到一分钟:
"initdev:npm": "npm install & glob-exec --parallel --foreach \"Tasks/*/tsconfig.json\" -- \"cd {{file.dir}} && npm install\"",
"compile:tasks": "glob-exec \"Tasks/*/tsconfig.json\" -- \"tsc -b {{files.join(' ')}}\"",
"lint:tasks": "glob-exec --parallel --foreach \"Tasks/*/tsconfig.json\" -- \"tslint -p {{file}}\"",
项目引用在我的情况下效果不佳,所以我使用 webpack 和 ts-loader 来构建我的项目。
将所有 ts 代码放在单个 root 下,使用单个 tsconfig,这样它就会像这样。
ts
-core
-plugin1
-plugin2
从 3.10 开始,webpack 允许 multiple output configurations。所以我们可以像这样使用单个配置文件。
const path = require("path");
const commonTsRule = {
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
};
const commonConfig = {
devtool: "inline-source-map",
mode: "development",
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
};
module.exports = [
{
...commonConfig,
entry: `${path.resolve(__dirname, "ts")}/plugin1/index.ts`,
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build/plugin1/js"),
},
module: {
rules: [
{
...commonTsRule,
// here you can customize rule if required
},
],
},
},
{
...commonConfig,
entry: `${path.resolve(__dirname, "ts")}/plugin2/index.ts`,
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build/plugin2/js"),
},
module: {
rules: [
{
...commonTsRule
// here you can customize rule if required
},
],
},
},
];
因此,作为最终结果,您将从每个项目自己的入口点构建到自己的输出目标。