根据相同的公共本地模块打包多个Typescript项目

时间:2018-08-20 21:09:57

标签: typescript npm azure-pipelines-build-task azure-devops-extensions

我正在研究一组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无法加载模块。前置仅适用于后者。

有没有一种方法可以使我的工作“无缝”,而不必费心或烦恼,而只需让每个MyXthTask在其node_modules文件夹中拥有本地公共模块的副本?

3 个答案:

答案 0 :(得分:1)

我尝试了@ 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,它将输出文件夹设置为该项目的当前文件夹,并继承自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}}\"",

答案 1 :(得分:0)

如果您满意为每个任务生成一个文件作为输出(并使用兼容的模块加载器)而不是生成单个模块,则可以将project referencesprepend option一起使用。 / p>

如果需要多文件输出,请参见this question,以获取有关TypeScript的建议和可能的解决方法。

答案 2 :(得分:0)

在我的情况下,项目引用无法正常工作,因此我将Webpack与ts-loader一起使用来构建项目。

将所有ts代码放在具有单个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
        },
      ],
    },
  },
];

因此,作为最终结果,每个项目都将从其自己的入口点构建到其自己的输出目标。