@@ -13,7 +13,11 @@ import { purgeStaleBuildCache } from '../../utils/purge-cache';
13
13
import { assertCompatibleAngularVersion } from '../../utils/version' ;
14
14
import { runEsBuildBuildAction } from './build-action' ;
15
15
import { executeBuild } from './execute-build' ;
16
- import { ApplicationBuilderInternalOptions , normalizeOptions } from './options' ;
16
+ import {
17
+ ApplicationBuilderExtensions ,
18
+ ApplicationBuilderInternalOptions ,
19
+ normalizeOptions ,
20
+ } from './options' ;
17
21
import { Schema as ApplicationBuilderOptions } from './schema' ;
18
22
19
23
export { ApplicationBuilderOptions } ;
@@ -25,28 +29,49 @@ export async function* buildApplicationInternal(
25
29
infrastructureSettings ?: {
26
30
write ?: boolean ;
27
31
} ,
28
- plugins ?: Plugin [ ] ,
29
- ) : AsyncIterable <
30
- BuilderOutput & {
31
- outputFiles ?: BuildOutputFile [ ] ;
32
- assetFiles ?: { source : string ; destination : string } [ ] ;
33
- }
34
- > {
32
+ extensions ?: ApplicationBuilderExtensions ,
33
+ ) : AsyncIterable < ApplicationBuilderOutput > {
34
+ const { workspaceRoot, logger, target } = context ;
35
+
35
36
// Check Angular version.
36
- assertCompatibleAngularVersion ( context . workspaceRoot ) ;
37
+ assertCompatibleAngularVersion ( workspaceRoot ) ;
37
38
38
39
// Purge old build disk cache.
39
40
await purgeStaleBuildCache ( context ) ;
40
41
41
42
// Determine project name from builder context target
42
- const projectName = context . target ?. project ;
43
+ const projectName = target ?. project ;
43
44
if ( ! projectName ) {
44
- context . logger . error ( `The 'application' builder requires a target to be specified.` ) ;
45
+ yield { success : false , error : `The 'application' builder requires a target to be specified.` } ;
45
46
46
47
return ;
47
48
}
48
49
49
- const normalizedOptions = await normalizeOptions ( context , projectName , options , plugins ) ;
50
+ const normalizedOptions = await normalizeOptions ( context , projectName , options , extensions ) ;
51
+ const writeToFileSystem = infrastructureSettings ?. write ?? true ;
52
+ const writeServerBundles =
53
+ writeToFileSystem && ! ! ( normalizedOptions . ssrOptions && normalizedOptions . serverEntryPoint ) ;
54
+
55
+ if ( writeServerBundles ) {
56
+ const { browser, server } = normalizedOptions . outputOptions ;
57
+ if ( browser === '' ) {
58
+ yield {
59
+ success : false ,
60
+ error : `'outputPath.browser' cannot be configured to an empty string when SSR is enabled.` ,
61
+ } ;
62
+
63
+ return ;
64
+ }
65
+
66
+ if ( browser === server ) {
67
+ yield {
68
+ success : false ,
69
+ error : `'outputPath.browser' and 'outputPath.server' cannot be configured to the same value.` ,
70
+ } ;
71
+
72
+ return ;
73
+ }
74
+ }
50
75
51
76
// Setup an abort controller with a builder teardown if no signal is present
52
77
let signal = context . signal ;
@@ -59,14 +84,11 @@ export async function* buildApplicationInternal(
59
84
yield * runEsBuildBuildAction (
60
85
async ( rebuildState ) => {
61
86
const startTime = process . hrtime . bigint ( ) ;
62
-
63
87
const result = await executeBuild ( normalizedOptions , context , rebuildState ) ;
64
88
65
89
const buildTime = Number ( process . hrtime . bigint ( ) - startTime ) / 10 ** 9 ;
66
90
const status = result . errors . length > 0 ? 'failed' : 'complete' ;
67
- context . logger . info (
68
- `Application bundle generation ${ status } . [${ buildTime . toFixed ( 3 ) } seconds]` ,
69
- ) ;
91
+ logger . info ( `Application bundle generation ${ status } . [${ buildTime . toFixed ( 3 ) } seconds]` ) ;
70
92
71
93
return result ;
72
94
} ,
@@ -76,24 +98,28 @@ export async function* buildApplicationInternal(
76
98
poll : normalizedOptions . poll ,
77
99
deleteOutputPath : normalizedOptions . deleteOutputPath ,
78
100
cacheOptions : normalizedOptions . cacheOptions ,
79
- outputPath : normalizedOptions . outputPath ,
101
+ outputOptions : normalizedOptions . outputOptions ,
80
102
verbose : normalizedOptions . verbose ,
81
103
projectRoot : normalizedOptions . projectRoot ,
82
104
workspaceRoot : normalizedOptions . workspaceRoot ,
83
105
progress : normalizedOptions . progress ,
84
- writeToFileSystem : infrastructureSettings ?. write ,
106
+ writeToFileSystem,
85
107
// For app-shell and SSG server files are not required by users.
86
108
// Omit these when SSR is not enabled.
87
- writeToFileSystemFilter :
88
- normalizedOptions . ssrOptions && normalizedOptions . serverEntryPoint
89
- ? undefined
90
- : ( file ) => file . type !== BuildOutputFileType . Server ,
91
- logger : context . logger ,
109
+ writeToFileSystemFilter : writeServerBundles
110
+ ? undefined
111
+ : ( file ) => file . type !== BuildOutputFileType . Server ,
112
+ logger,
92
113
signal,
93
114
} ,
94
115
) ;
95
116
}
96
117
118
+ export interface ApplicationBuilderOutput extends BuilderOutput {
119
+ outputFiles ?: BuildOutputFile [ ] ;
120
+ assetFiles ?: { source : string ; destination : string } [ ] ;
121
+ }
122
+
97
123
/**
98
124
* Builds an application using the `application` builder with the provided
99
125
* options.
@@ -112,13 +138,41 @@ export function buildApplication(
112
138
options : ApplicationBuilderOptions ,
113
139
context : BuilderContext ,
114
140
plugins ?: Plugin [ ] ,
115
- ) : AsyncIterable <
116
- BuilderOutput & {
117
- outputFiles ?: BuildOutputFile [ ] ;
118
- assetFiles ?: { source : string ; destination : string } [ ] ;
141
+ ) : AsyncIterable < ApplicationBuilderOutput > ;
142
+
143
+ /**
144
+ * Builds an application using the `application` builder with the provided
145
+ * options.
146
+ *
147
+ * Usage of the `extensions` parameter is NOT supported and may cause unexpected
148
+ * build output or build failures.
149
+ *
150
+ * @experimental Direct usage of this function is considered experimental.
151
+ *
152
+ * @param options The options defined by the builder's schema to use.
153
+ * @param context An Architect builder context instance.
154
+ * @param extensions An object contain extension points for the build.
155
+ * @returns The build output results of the build.
156
+ */
157
+ export function buildApplication (
158
+ options : ApplicationBuilderOptions ,
159
+ context : BuilderContext ,
160
+ extensions ?: ApplicationBuilderExtensions ,
161
+ ) : AsyncIterable < ApplicationBuilderOutput > ;
162
+
163
+ export function buildApplication (
164
+ options : ApplicationBuilderOptions ,
165
+ context : BuilderContext ,
166
+ pluginsOrExtensions ?: Plugin [ ] | ApplicationBuilderExtensions ,
167
+ ) : AsyncIterable < ApplicationBuilderOutput > {
168
+ let extensions ;
169
+ if ( pluginsOrExtensions && Array . isArray ( pluginsOrExtensions ) ) {
170
+ extensions = {
171
+ codePlugins : pluginsOrExtensions ,
172
+ } ;
119
173
}
120
- > {
121
- return buildApplicationInternal ( options , context , undefined , plugins ) ;
174
+
175
+ return buildApplicationInternal ( options , context , undefined , extensions ) ;
122
176
}
123
177
124
178
export default createBuilder ( buildApplication ) ;
0 commit comments