Упаковка нескольких проектов Typescript в зависимости от одного и того же локального модуля
Я работаю над набором расширений 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
, который работает во время разработки, но это не приводит к тому, что общий модуль становится частью задачи после генерации расширения.
Мой фон не в разработке узлов, а в C#. Я искал по всему и не нашел решения, которое хорошо работает с VSTS-расширениями.
npm pack
похоже, не работает, так как расширение ожидает, что все файлы будут там.package.json/bundleDependencies
выглядит многообещающе, но не связывает локальную ссылку на файл.///<reference path="../common/common.ts"/>
прекрасно работает для редактирования, но все еще не может работать после создания расширения.- ссылка на проект с prepend не работает, для задач сборки требуется модуль разрешения commonjs. Система и AMD не могут загружать модули. Prepend работает только с последним.
Есть ли способ, которым я могу сделать эту работу "без проблем", не взирая на недовольство или хрюканье, и просто заставляя каждую MyXthTask иметь копию локального общего модуля в своем node_modules
папка?
2 ответа
Я попробовал подход @matt-mccutchen, но, к сожалению, я не смог заставить его работать с задачами сборки VSTS из-за того, что эти задачи требуют 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
который устанавливает выходную папку в текущую папку для этого проекта и которая наследует от tsconfig.json
в Tasks
папка:
{
"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
Я смог сократить время сборки до менее минуты при чистом сборке:
"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}}\"",
Вы можете быть в состоянии использовать ссылки проекта с prepend
вариант, если вы удовлетворены тем, что генерируете один файл в качестве вывода для каждой задачи (и используете совместимый загрузчик модулей) вместо генерации отдельных модулей.
Если вам нужен многофайловый вывод, см. Этот вопрос для предложения TypeScript и возможного обходного пути.
Ссылки на проекты в моем случае не работают, поэтому я использовал webpack с ts-loader для создания своих проектов.
Поместите весь ts-код в один корень с одним tsconfig, чтобы он был таким.
ts
-core
-plugin1
-plugin2
Начиная с 3.10 webpack допускает несколько конфигураций вывода. Таким образом, мы могли бы использовать один такой файл конфигурации.
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
},
],
},
},
];
Таким образом, в конечном результате у вас будет каждый проект, построенный из собственной точки входа и в свое собственное место назначения.