取决于完成多个并行 gulp 任务
Depending on completion of multiple parallel gulp tasks
我有一个复杂的 NodeJS 应用程序,由多个纱线工作区包组成。以下 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" 包文件夹。
- “{client,server,shared}/common”是同一包文件夹中的 "frontoffice" 和 "backoffice" 包所必需的。
相应包的 "client" 和 "server" 都需要 - "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 完成之前不会被编译,并且从那里客户端也被不必要地延迟。
如果您使用 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,您必须明确使用新的 series
和 parallel
结构。从这个意义上说,gulp 变得比声明更具程序性。
我认为最佳解决方案是等待构建所有共享包,然后为客户端和服务器分叉 2 个并行分支。
const tasks: GulpTasks = {
build: series(
series(buildSharedCommon, parallel(buildSharedFrontoffice, buildSharedBackoffice)),
parallel(
series(buildClientCommon, parallel(buildClientFrontoffice, buildClientBackoffice)),
series(buildDatabase, buildServerCommon, parallel(buildServerFrontoffice, buildServerBackoffice))
)
)
};
Fastest/ideal 执行路径是并行旋转 3 个任务,然后等待 3 个任务中的 2 个完成,用于两个不同的延续(客户端和服务器)。 Gulp 开箱即用,需要您的代码来处理同步。
我有一个复杂的 NodeJS 应用程序,由多个纱线工作区包组成。以下 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" 包文件夹。
- “{client,server,shared}/common”是同一包文件夹中的 "frontoffice" 和 "backoffice" 包所必需的。 相应包的 "client" 和 "server" 都需要
- "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 完成之前不会被编译,并且从那里客户端也被不必要地延迟。
如果您使用 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,您必须明确使用新的 series
和 parallel
结构。从这个意义上说,gulp 变得比声明更具程序性。
我认为最佳解决方案是等待构建所有共享包,然后为客户端和服务器分叉 2 个并行分支。
const tasks: GulpTasks = {
build: series(
series(buildSharedCommon, parallel(buildSharedFrontoffice, buildSharedBackoffice)),
parallel(
series(buildClientCommon, parallel(buildClientFrontoffice, buildClientBackoffice)),
series(buildDatabase, buildServerCommon, parallel(buildServerFrontoffice, buildServerBackoffice))
)
)
};
Fastest/ideal 执行路径是并行旋转 3 个任务,然后等待 3 个任务中的 2 个完成,用于两个不同的延续(客户端和服务器)。 Gulp 开箱即用,需要您的代码来处理同步。