@@ -3,7 +3,12 @@ import { type Input, toConfig, toDependency, toEntry, toProductionEntry } from '
3
3
import { join } from '../../util/path.js' ;
4
4
import { hasDependency } from '../../util/plugin.js' ;
5
5
import * as karma from '../karma/helpers.js' ;
6
- import type { AngularCLIWorkspaceConfiguration , KarmaTarget , WebpackBrowserSchemaForBuildFacade } from './types.js' ;
6
+ import type {
7
+ AngularCLIWorkspaceConfiguration ,
8
+ KarmaTarget ,
9
+ Project ,
10
+ WebpackBrowserSchemaForBuildFacade ,
11
+ } from './types.js' ;
7
12
8
13
// https://angular.io/guide/workspace-config
9
14
@@ -24,48 +29,40 @@ const resolveConfig: ResolveConfig<AngularCLIWorkspaceConfiguration> = async (co
24
29
25
30
for ( const project of Object . values ( config . projects ) ) {
26
31
if ( ! project . architect ) return [ ] ;
27
- for ( const target of Object . values ( project . architect ) ) {
32
+ for ( const [ targetName , target ] of Object . entries ( project . architect ) ) {
28
33
const { options : opts , configurations : configs } = target ;
29
34
const [ packageName ] = typeof target . builder === 'string' ? target . builder . split ( ':' ) : [ ] ;
30
35
if ( typeof packageName === 'string' ) inputs . add ( toDependency ( packageName ) ) ;
31
36
if ( opts ) {
32
- if ( 'main' in opts && typeof opts . main === 'string' ) {
33
- inputs . add ( toProductionEntry ( join ( cwd , opts . main ) ) ) ;
34
- }
35
- if ( 'browser' in opts && typeof opts . browser === 'string' ) {
36
- inputs . add ( toProductionEntry ( join ( cwd , opts . browser ) ) ) ;
37
- }
38
- if ( 'ssr' in opts && opts . ssr && typeof opts . ssr === 'object' ) {
39
- if ( 'entry' in opts . ssr && typeof opts . ssr . entry === 'string' ) {
40
- inputs . add ( toProductionEntry ( join ( cwd , opts . ssr . entry ) ) ) ;
41
- }
42
- }
43
37
if ( 'tsConfig' in opts && typeof opts . tsConfig === 'string' ) {
44
38
inputs . add ( toConfig ( 'typescript' , opts . tsConfig , configFilePath ) ) ;
45
39
}
46
- if ( 'server' in opts && opts . server && typeof opts . server === 'string' ) {
47
- inputs . add ( toProductionEntry ( join ( cwd , opts . server ) ) ) ;
48
- }
49
- if ( 'fileReplacements' in opts && opts . fileReplacements && Array . isArray ( opts . fileReplacements ) ) {
50
- for ( const fileReplacedBy of filesReplacedBy ( opts . fileReplacements ) ) {
51
- inputs . add ( toEntry ( fileReplacedBy ) ) ;
52
- }
53
- }
54
- if ( 'scripts' in opts && opts . scripts && Array . isArray ( opts . scripts ) ) {
55
- for ( const scriptStringOrObject of opts . scripts as AngularScriptsBuildOption ) {
56
- const script = typeof scriptStringOrObject === 'string' ? scriptStringOrObject : scriptStringOrObject . input ;
57
- inputs . add ( toProductionEntry ( script ) ) ;
40
+ }
41
+ const defaultEntriesByOption : EntriesByOption = opts ? entriesByOption ( opts ) : new Map ( ) ;
42
+ const entriesByOptionByConfig : Map < string , EntriesByOption > = new Map (
43
+ configs ? Object . entries ( configs ) . map ( ( [ name , opts ] ) => [ name , entriesByOption ( opts ) ] ) : [ ]
44
+ ) ;
45
+ const productionEntriesByOption : EntriesByOption =
46
+ entriesByOptionByConfig . get ( PRODUCTION_CONFIG_NAME ) ?? new Map ( ) ;
47
+ const normalizePath = ( path : string ) => join ( cwd , path ) ;
48
+ for ( const [ configName , entriesByOption ] of entriesByOptionByConfig . entries ( ) ) {
49
+ for ( const entries of entriesByOption . values ( ) ) {
50
+ for ( const entry of entries ) {
51
+ inputs . add (
52
+ targetName === BUILD_TARGET_NAME && configName === PRODUCTION_CONFIG_NAME
53
+ ? toProductionEntry ( normalizePath ( entry ) )
54
+ : toEntry ( normalizePath ( entry ) )
55
+ ) ;
58
56
}
59
57
}
60
58
}
61
- if ( configs ) {
62
- for ( const [ configName , config ] of Object . entries ( configs ) ) {
63
- const isProductionConfig = configName === 'production' ;
64
- if ( 'fileReplacements' in config && config . fileReplacements && Array . isArray ( config . fileReplacements ) ) {
65
- for ( const fileReplacedBy of filesReplacedBy ( config . fileReplacements ) ) {
66
- inputs . add ( isProductionConfig ? toProductionEntry ( fileReplacedBy ) : toEntry ( fileReplacedBy ) ) ;
67
- }
68
- }
59
+ for ( const [ option , entries ] of defaultEntriesByOption . entries ( ) ) {
60
+ for ( const entry of entries ) {
61
+ inputs . add (
62
+ targetName === BUILD_TARGET_NAME && ! productionEntriesByOption . get ( option ) ?. length
63
+ ? toProductionEntry ( normalizePath ( entry ) )
64
+ : toEntry ( normalizePath ( entry ) )
65
+ ) ;
69
66
}
70
67
}
71
68
if ( target . builder === '@angular-devkit/build-angular:karma' && opts ) {
@@ -102,16 +99,48 @@ const resolveConfig: ResolveConfig<AngularCLIWorkspaceConfiguration> = async (co
102
99
return Array . from ( inputs ) ;
103
100
} ;
104
101
105
- type AngularScriptsBuildOption = Exclude < WebpackBrowserSchemaForBuildFacade [ 'scripts' ] , undefined > ;
106
-
107
- const filesReplacedBy = (
108
- //👇 Using Webpack-based browser schema to support old `replaceWith` file replacements
109
- fileReplacements : Exclude < WebpackBrowserSchemaForBuildFacade [ 'fileReplacements' ] , undefined >
110
- ) : readonly string [ ] =>
111
- fileReplacements . map ( fileReplacement =>
112
- 'with' in fileReplacement ? fileReplacement . with : fileReplacement . replaceWith
102
+ const entriesByOption = ( opts : TargetOptions ) : EntriesByOption =>
103
+ new Map (
104
+ Object . entries ( {
105
+ main : 'main' in opts && opts . main && typeof opts . main === 'string' ? [ opts . main ] : [ ] ,
106
+ scripts :
107
+ 'scripts' in opts && opts . scripts && Array . isArray ( opts . scripts )
108
+ ? ( opts . scripts as ScriptsBuildOption ) . map ( scriptStringOrObject =>
109
+ typeof scriptStringOrObject === 'string' ? scriptStringOrObject : scriptStringOrObject . input
110
+ )
111
+ : [ ] ,
112
+ fileReplacements :
113
+ 'fileReplacements' in opts && opts . fileReplacements && Array . isArray ( opts . fileReplacements )
114
+ ? ( opts . fileReplacements as FileReplacementsBuildOption ) . map ( fileReplacement =>
115
+ 'with' in fileReplacement ? fileReplacement . with : fileReplacement . replaceWith
116
+ )
117
+ : [ ] ,
118
+ browser : 'browser' in opts && opts . browser && typeof opts . browser === 'string' ? [ opts . browser ] : [ ] ,
119
+ server : 'server' in opts && opts . server && typeof opts . server === 'string' ? [ opts . server ] : [ ] ,
120
+ ssrEntry :
121
+ 'ssr' in opts &&
122
+ opts . ssr &&
123
+ typeof opts . ssr === 'object' &&
124
+ 'entry' in opts . ssr &&
125
+ typeof opts . ssr . entry === 'string'
126
+ ? [ opts . ssr . entry ]
127
+ : [ ] ,
128
+ } )
113
129
) ;
114
130
131
+ type TargetOptions = Exclude < Target [ 'options' ] , undefined > ;
132
+ type Target = Architect [ string ] ;
133
+ type Architect = Exclude < Project [ 'architect' ] , undefined > ;
134
+
135
+ type EntriesByOption = Map < string , readonly string [ ] > ;
136
+
137
+ //👇 Using Webpack-based browser schema to support old `replaceWith` file replacements
138
+ type FileReplacementsBuildOption = Exclude < WebpackBrowserSchemaForBuildFacade [ 'fileReplacements' ] , undefined > ;
139
+ type ScriptsBuildOption = Exclude < WebpackBrowserSchemaForBuildFacade [ 'scripts' ] , undefined > ;
140
+
141
+ const PRODUCTION_CONFIG_NAME = 'production' ;
142
+ const BUILD_TARGET_NAME = 'build' ;
143
+
115
144
export default {
116
145
title,
117
146
enablers,
0 commit comments