|
| 1 | +/** |
| 2 | + * @license |
| 3 | + * Copyright Google LLC All Rights Reserved. |
| 4 | + * |
| 5 | + * Use of this source code is governed by an MIT-style license that can be |
| 6 | + * found in the LICENSE file at https://angular.dev/license |
| 7 | + */ |
| 8 | + |
| 9 | +import type { BuilderContext, BuilderOutput } from '@angular-devkit/architect'; |
| 10 | +import type { NgPackagrOptions } from 'ng-packagr'; |
| 11 | +import { join, resolve } from 'node:path'; |
| 12 | +import { assertIsError } from '../../utils/error'; |
| 13 | +import { normalizeCacheOptions } from '../../utils/normalize-cache'; |
| 14 | +import { purgeStaleBuildCache } from '../../utils/purge-cache'; |
| 15 | +import type { Schema as NgPackagrBuilderOptions } from './schema'; |
| 16 | + |
| 17 | +/** |
| 18 | + * A Builder that executes the `ng-packagr` tool to build an Angular library. |
| 19 | + * |
| 20 | + * @param options The builder options as defined by the JSON schema. |
| 21 | + * @param context A BuilderContext instance. |
| 22 | + * @returns A BuilderOutput object. |
| 23 | + * |
| 24 | + * @experimental Direct usage of this function is considered experimental. |
| 25 | + */ |
| 26 | +export async function* execute( |
| 27 | + options: NgPackagrBuilderOptions, |
| 28 | + context: BuilderContext, |
| 29 | +): AsyncIterableIterator<BuilderOutput> { |
| 30 | + // Purge old build disk cache. |
| 31 | + await purgeStaleBuildCache(context); |
| 32 | + |
| 33 | + const root = context.workspaceRoot; |
| 34 | + let packager; |
| 35 | + try { |
| 36 | + packager = (await import('ng-packagr')).ngPackagr(); |
| 37 | + } catch (error) { |
| 38 | + assertIsError(error); |
| 39 | + if (error.code === 'MODULE_NOT_FOUND') { |
| 40 | + return { |
| 41 | + success: false, |
| 42 | + error: |
| 43 | + 'The "ng-packagr" package was not found. To correct this error, ensure this package is installed in the project.', |
| 44 | + }; |
| 45 | + } |
| 46 | + |
| 47 | + throw error; |
| 48 | + } |
| 49 | + |
| 50 | + packager.forProject(resolve(root, options.project)); |
| 51 | + |
| 52 | + if (options.tsConfig) { |
| 53 | + packager.withTsConfig(resolve(root, options.tsConfig)); |
| 54 | + } |
| 55 | + |
| 56 | + const projectName = context.target?.project; |
| 57 | + if (!projectName) { |
| 58 | + throw new Error('The builder requires a target.'); |
| 59 | + } |
| 60 | + |
| 61 | + const metadata = await context.getProjectMetadata(projectName); |
| 62 | + const { enabled: cacheEnabled, path: cacheDirectory } = normalizeCacheOptions( |
| 63 | + metadata, |
| 64 | + context.workspaceRoot, |
| 65 | + ); |
| 66 | + |
| 67 | + const ngPackagrOptions: NgPackagrOptions = { |
| 68 | + cacheEnabled, |
| 69 | + poll: options.poll, |
| 70 | + cacheDirectory: join(cacheDirectory, 'ng-packagr'), |
| 71 | + }; |
| 72 | + |
| 73 | + try { |
| 74 | + if (options.watch) { |
| 75 | + await packager.watch(ngPackagrOptions).toPromise(); |
| 76 | + } else { |
| 77 | + await packager.build(ngPackagrOptions); |
| 78 | + } |
| 79 | + |
| 80 | + yield { success: true }; |
| 81 | + } catch (error) { |
| 82 | + assertIsError(error); |
| 83 | + |
| 84 | + yield { success: false, error: error.message }; |
| 85 | + } |
| 86 | +} |
0 commit comments