[英]Run angular custom builders in sequence
I have an Angular 13 project with some custom made builders.我有一个 Angular 13 项目和一些定制的构建器。 One of these generates a file with a $templateCache module.
其中之一会生成一个带有 $templateCache 模块的文件。 This can take a few seconds to complete.
这可能需要几秒钟才能完成。
The issue is that the main Angular builder starts before the $templateCache builder has completed.问题是主 Angular 构建器在 $templateCache 构建器完成之前启动。 This causes the module file to not be included in the build and the application crashes on page load or the build fails with an error saying the module cannot be resolved.
这会导致模块文件不包含在构建中,并且应用程序在页面加载时崩溃,或者构建失败并显示无法解析模块的错误。
How can I ensure the $templateCache builder has completed before starting the main build?在开始主构建之前,如何确保 $templateCache 构建器已完成?
This is my builder that I am using to run the other custom ones and the Angular builder:这是我用来运行其他自定义构建器和 Angular 构建器的构建器:
import { CustomScheduleBuilderSchema } from './schema';
import { BuilderContext, BuilderOutput, BuilderRun, createBuilder, ScheduleOptions } from '@angular-devkit/architect';
import { Observable, of, from } from 'rxjs';
import { catchError, finalize, first, mergeMap } from 'rxjs/operators';
import { json, JsonObject } from '@angular-devkit/core';
function scheduleNgBuildTarget(
options: JsonObject & CustomScheduleBuilderSchema,
context: BuilderContext,
): Promise<BuilderRun> {
return context.scheduleTarget({
target: options.target,
project: context.target?.project ?? ''
});
}
function scheduleConcatenateLanguagesBuilder(
context: BuilderContext
): Promise<BuilderRun> {
return context.scheduleTarget({
target: 'concat-lang',
project: context.target?.project ?? ''
},
{
watchModeEnabled: true
});
}
function scheduleTemplatesBuilder(
context: BuilderContext
): Promise<BuilderRun> {
return context.scheduleTarget({
target: 'templates',
project: context.target?.project ?? ''
},
{
watchModeEnabled: true
});
}
function scheduleVersionBuilder(
context: BuilderContext
): Promise<BuilderRun> {
return context.scheduleTarget({
target: 'version',
project: context.target?.project ?? ''
});
}
export function runCustomScheduleBuilder (
options: JsonObject & CustomScheduleBuilderSchema,
context: BuilderContext
): Observable<BuilderOutput> {
const scheduleLogger = context.logger.createChild('CustomSchedule');
scheduleLogger.info('Starting build');
return of({ success: true }).pipe(
first(),
mergeMap(_ => from(scheduleConcatenateLanguagesBuilder(context))),
mergeMap(_ => from(scheduleTemplatesBuilder(context))),
mergeMap(_ => from(scheduleVersionBuilder(context))),
mergeMap(_ => from(scheduleNgBuildTarget(options, context))), // This should run after the other builders have completed.
mergeMap(target =>
target.output.pipe(
finalize(() => {
scheduleLogger.info('Shutting down build');
}),
),
),
catchError(e => {
scheduleLogger.error(JSON.stringify(e));
return of({ success: false });
}),
);
}
export default createBuilder<json.JsonObject & CustomScheduleBuilderSchema>(runCustomScheduleBuilder);
This is the builder that generates the file with the $templateCache module:这是使用 $templateCache 模块生成文件的构建器:
import { TemplatesBuilderSchema } from './schema';
import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import { json, normalize } from '@angular-devkit/core';
import { Observable, of, noop, from, fromEvent } from 'rxjs';
import { catchError, map, finalize, take, tap, mergeMap, first } from 'rxjs/operators';
import { join } from 'path';
import html2jsProcessor from 'angular-template-cache';
import defaults from 'angular-template-cache/lib/defaults';
import { watch } from 'chokidar';
async function populateTemplateCache(
options: any,
templatesLogger: any
) {
await html2jsProcessor(options);
templatesLogger.info(`Completed templates file: ${options.output}`)
}
export function runTemplatesBuilder(
{ outputPath, watchModeEnabled }: TemplatesBuilderSchema,
{ workspaceRoot, logger }: BuilderContext
): Observable<BuilderOutput> {
const templatesLogger = logger.createChild('Templates');
templatesLogger.info('Creating templates file to populate $templateCache');
const options = {
...defaults,
strict: false,
filesGlob: 'src/app/**/*.html',
moduleName: 'myApp.templates',
output: join(workspaceRoot, normalize(outputPath)),
};
// Setup file watcher
const watcher = watch('src/app/**/*.html', { ignoreInitial: true });
watcher.on('add', () => {
populateTemplateCache(options, templatesLogger);
})
.on('change', () => {
populateTemplateCache(options, templatesLogger);
})
.on('unlink', () => {
populateTemplateCache(options, templatesLogger);
});
return fromEvent(watcher, 'ready').pipe(
tap(() => {
templatesLogger.info('templates watcher ready...');
}),
first(),
mergeMap(_ => from(populateTemplateCache(options, templatesLogger))),
map(() => ({ success: true })),
finalize(() => {
templatesLogger.info('Shutting down templates file watcher');
watcher.close();
}),
catchError(e => {
templatesLogger.error(`Failed to create templates file: ${options.output}, Error: ${JSON.stringify(e)}`);
return of({ success: false });
}),
watchModeEnabled ? tap(noop) : take(1),
);
}
export default createBuilder<json.JsonObject & TemplatesBuilderSchema>(runTemplatesBuilder);
It seems the scheduleTarget
function returns a resolved Promise without waiting for the builder target to complete.似乎
scheduleTarget
function 返回已解决的 Promise 而无需等待构建器目标完成。
By creating a child instance of a logger and passing it to the builder I can listen for log messages and wait to return the resolved promise until the expected 'Completed templates' message is detected.通过创建记录器的子实例并将其传递给构建器,我可以侦听日志消息并等待返回已解析的 promise,直到检测到预期的“已完成模板”消息。
async function scheduleTemplatesBuilder(
context: BuilderContext
): Promise<BuilderRun> {
const templatesLogger = context.logger.createChild('templates');
const builderRun = context.scheduleTarget({
target: 'templates',
project: context.target?.project ?? ''
},
{
watchModeEnabled: true
},
{
logger: templatesLogger
});
await templatesLogger.pipe(
takeWhile(logEntry => !logEntry.message.includes('Completed templates')),
).toPromise();
return builderRun;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.