【问题标题】:Depending on completion of multiple parallel gulp tasks取决于多个并行 gulp 任务的完成情况
【发布时间】:2019-09-05 10:15:44
【问题描述】:

我有一个复杂的 NodeJS 应用程序,由几个 yarn 工作区包组成。以下 gulpconfig.ts 文件为整个包集定义了一个 gulp 构建任务:

import { series, parallel, TaskFunction, src, dest } from 'gulp';
import gulpTslint from 'gulp-tslint';
import { createProject } from 'gulp-typescript';
import tslint, { Linter } from 'tslint';
import { resolve } from 'path';
import { DestOptions } from 'vinyl-fs';
import { exec } from 'child_process';
import { promisify } from 'util';

const execPromise = promisify(exec);

interface GulpTasks {
  [key: string]: TaskFunction;
}

type TaskFunctionCallback = (error?: any) => void;

class Project {
  public projectFiles: NodeJS.ReadWriteStream;
  public constructor(
    public readonly projectDirectory: string,
    public readonly sourcemaps: boolean = false,
  ) {
    this.projectFiles = src('./src/**/*.ts', { cwd: projectDirectory, sourcemaps });
  }

  public lint(): this {
    this.projectFiles = this.projectFiles.pipe(
      gulpTslint({
        tslint,
        configuration: resolve(__dirname, 'tslint.json'),
        program: Linter.createProgram(
          resolve(this.projectDirectory, 'tsconfig.json'),
          this.projectDirectory,
        ),
      }),
    );

    return this;
  }

  public build(): this {
    const opts: DestOptions = {};
    if (this.sourcemaps) {
      opts.sourcemaps = true;
    }
    this.projectFiles = this.projectFiles
      .pipe(createProject(resolve(this.projectDirectory, 'tsconfig.build.json'))())
      .pipe(dest(resolve(this.projectDirectory, 'dist'), opts));

    return this;
  }
}

const buildDatabase = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'server/database')).build().projectFiles;

const buildSharedCommon = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'shared/common')).lint().build().projectFiles;
const buildSharedFrontoffice = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'shared/frontoffice')).lint().build().projectFiles;
const buildSharedBackoffice = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'shared/backoffice')).lint().build().projectFiles;

const buildClientCommon = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'client/common')).lint().build().projectFiles;
const buildClientFrontoffice = async (cb: TaskFunctionCallback): Promise<unknown> =>
  execPromise('yarn run build', { cwd: 'client/frontoffice' });
const buildClientBackoffice = async (cb: TaskFunctionCallback): Promise<unknown> =>
  execPromise('yarn run build', { cwd: 'client/backoffice' });

const buildServerCommon = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'server/common')).lint().build().projectFiles;
const buildServerFrontoffice = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'server/frontoffice')).lint().build().projectFiles;
const buildServerBackoffice = (cb: TaskFunctionCallback): NodeJS.ReadWriteStream =>
  new Project(resolve(__dirname, 'server/backoffice')).lint().build().projectFiles;

const tasks: GulpTasks = {
  build: parallel(
    buildDatabase,
    series(
      buildSharedCommon,
      parallel(buildSharedBackoffice, buildSharedFrontoffice),
      parallel(
        series(buildClientCommon, parallel(buildClientFrontoffice, buildClientBackoffice)),
        series(buildServerCommon, parallel(buildServerFrontoffice, buildServerBackoffice)),
      ),
    ),
  ),
};

export = tasks;

由于我的应用程序的结构,buildServerCommon 依赖于 buildDatabase。但是 buildDatabase 不依赖任何东西,并且需要很长时间,这就是为什么我与其他部分并行启动它的原因。

不过,通过上述设置,buildDatabase 可能(并且确实)在 buildServerCommon 启动之后完成。

我怎样才能使 buildServerCommon 仅在 buildDatabase 和 buildSharedCommon 之后启动,但仍让其他一切尽早启动?

基本上,在我的依赖树中:

  • 我有“客户端”、“服务器”和“共享”包文件夹。
  • “{client,server,shared}/common”是同一软件包文件夹中的“frontoffice”和“backoffice”软件包所必需的。
  • “shared/{common,frontoffice,backoffice}”是各个包的“客户端”和“服务器”都需要的。
  • “server/database”比较特殊,只存在于“server”中,是“server/common”需要的。

我尝试使用

const tasks: GulpTasks = {
  build: series(
    parallel(buildSharedCommon, buildDatabase),
    parallel(buildServerCommon, buildSharedFrontoffice, buildSharedBackoffice),
    parallel(
      series(buildClientCommon, parallel(buildClientFrontoffice, buildClientBackoffice)),
      parallel(buildServerFrontoffice, buildServerBackoffice),
    ),
  ),
};

但这并不是最优的,因为 buildSharedFrontoffice 和 buildSharedBackoffice 在 buildDatabase 完成之前不会被编译,并且从那里客户端也被不必要地延迟了。

【问题讨论】:

    标签: node.js typescript gulp


    【解决方案1】:

    我认为最理想的解决方案是等待所有共享包构建完成,然后为客户端和服务器分叉 2 个并行分支。

    const tasks: GulpTasks = {
        build: series(
            series(buildSharedCommon, parallel(buildSharedFrontoffice, buildSharedBackoffice)),
            parallel(
                series(buildClientCommon, parallel(buildClientFrontoffice, buildClientBackoffice)),
                series(buildDatabase, buildServerCommon, parallel(buildServerFrontoffice, buildServerBackoffice))
            )
        )
      };
    

    最快/理想的执行路径是并行旋转 3 个任务,然后等待 3 个任务中的 2 个完成,用于两个不同的延续(客户端和服务器)。这在 Gulp 中不能开箱即用,并且需要您的代码来处理同步。

    【讨论】:

    • 您的序列与我的初始代码(在最顶部)中的序列大部分相似,除了它将“buildDatabase”移动到服务器序列中,我想这很有效,所以谢谢。虽然最后,我通过在 TypeScript 中使用项目引用并让 gulp 使用命令行执行 tsc 解决了我的问题(因为 gulp-typescript 不正确支持项目引用)。
    【解决方案2】:

    如果您使用早期版本的 Gulp,请注意 serial() 的参数顺序与使用 task() 的早期版本不同。特别是serial() 的参数按照它们列出的顺序一个接一个地执行。

    因此,如果您需要buildDatabase 完成之前 buildServerCommon,它们需要以预期的顺序出现在同一个serial 函数调用中。我认为您需要更多类似的东西:

    const tasks: GulpTasks = {
    build: parallel(
        series( buildDatabase, buildServerCommon /* ... others? */ ),
        buildSharedCommon,
        buildSharedFrontoffice,
        // ... others?
        )
    }; 
    

    这当然假设 buildSharedCommon 和 buildSharedFrontoffice 对 serial() 块中的消息没有依赖关系。

    我是这样看的,在 gulp 3 中,gulp 任务从所有定义的 task 声明中找出正确的构建顺序,而在 gulp 4 中,您必须明确使用新的 @987654330 @ 和 parallel 构造。从这个意义上说,gulp 变得更加程序化而不是声明性。

    【讨论】:

    • buildServerCommon 要求 buildSharedCommon 已完成。但是, buildSharedCommon 不需要 buildDatabase 完成 - 它们可以并行启动.... 根据您建议的设置,buildServerCommon 可能会在 buildSharedCommon 准备好之前启动。当然,它可能不会,因为 buildDatabase 需要更长的时间,但我不想依赖它,因为编译时间可能会随着项目的发展而改变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多