@@ -10,7 +10,6 @@ import { EmittedFiles, WebpackLoggingCallback, runWebpack } from '@angular-devki
10
10
import { join , json , logging , normalize , tags , virtualFs } from '@angular-devkit/core' ;
11
11
import { NodeJsSyncHost } from '@angular-devkit/core/node' ;
12
12
import * as fs from 'fs' ;
13
- import * as os from 'os' ;
14
13
import * as path from 'path' ;
15
14
import { Observable , from , of } from 'rxjs' ;
16
15
import { concatMap , map , switchMap } from 'rxjs/operators' ;
@@ -49,12 +48,13 @@ import {
49
48
normalizeOptimization ,
50
49
normalizeSourceMaps ,
51
50
} from '../utils' ;
51
+ import { BundleActionExecutor } from '../utils/action-executor' ;
52
52
import { findCachePath } from '../utils/cache-path' ;
53
53
import { copyAssets } from '../utils/copy-assets' ;
54
54
import { cachingDisabled } from '../utils/environment-options' ;
55
- import { emittedFilesToInlineOptions } from '../utils/i18n-inlining' ;
56
- import { I18nOptions , createI18nOptions , mergeDeprecatedI18nOptions } from '../utils/i18n-options' ;
57
- import { createTranslationLoader } from '../utils/load-translations ' ;
55
+ import { i18nInlineEmittedFiles } from '../utils/i18n-inlining' ;
56
+ import { I18nOptions } from '../utils/i18n-options' ;
57
+ import { ensureOutputPaths } from '../utils/output-paths ' ;
58
58
import {
59
59
InlineOptions ,
60
60
ProcessBundleFile ,
@@ -63,11 +63,12 @@ import {
63
63
} from '../utils/process-bundle' ;
64
64
import { assertCompatibleAngularVersion } from '../utils/version' ;
65
65
import {
66
+ BrowserWebpackConfigOptions ,
66
67
generateBrowserWebpackConfigFromContext ,
68
+ generateI18nBrowserWebpackConfigFromContext ,
67
69
getIndexInputFile ,
68
70
getIndexOutputFile ,
69
71
} from '../utils/webpack-browser-config' ;
70
- import { BundleActionExecutor } from './action-executor' ;
71
72
import { Schema as BrowserBuilderSchema } from './schema' ;
72
73
73
74
const cacheDownlevelPath = cachingDisabled ? undefined : findCachePath ( 'angular-build-dl' ) ;
@@ -99,23 +100,53 @@ export function createBrowserLoggingCallback(
99
100
} ;
100
101
}
101
102
103
+ // todo: the below should be cleaned once dev-server support the new i18n
104
+ interface ConfigFromContextReturn {
105
+ config : webpack . Configuration ;
106
+ projectRoot : string ;
107
+ projectSourceRoot ?: string ;
108
+ }
109
+
110
+ export async function buildBrowserWebpackConfigFromContext (
111
+ options : BrowserBuilderSchema ,
112
+ context : BuilderContext ,
113
+ host : virtualFs . Host < fs . Stats > ,
114
+ i18n : boolean ,
115
+ ) : Promise < ConfigFromContextReturn & { i18n : I18nOptions } > ;
116
+ export async function buildBrowserWebpackConfigFromContext (
117
+ options : BrowserBuilderSchema ,
118
+ context : BuilderContext ,
119
+ host ?: virtualFs . Host < fs . Stats > ,
120
+ ) : Promise < ConfigFromContextReturn > ;
102
121
export async function buildBrowserWebpackConfigFromContext (
103
122
options : BrowserBuilderSchema ,
104
123
context : BuilderContext ,
105
124
host : virtualFs . Host < fs . Stats > = new NodeJsSyncHost ( ) ,
106
- ) : Promise < { config : webpack . Configuration ; projectRoot : string ; projectSourceRoot ?: string } > {
125
+ i18n = false ,
126
+ ) : Promise < ConfigFromContextReturn & { i18n ?: I18nOptions } > {
127
+ const webpackPartialGenerator = ( wco : BrowserWebpackConfigOptions ) => [
128
+ getCommonConfig ( wco ) ,
129
+ getBrowserConfig ( wco ) ,
130
+ getStylesConfig ( wco ) ,
131
+ getStatsConfig ( wco ) ,
132
+ getAnalyticsConfig ( wco , context ) ,
133
+ getCompilerConfig ( wco ) ,
134
+ wco . buildOptions . webWorkerTsConfig ? getWorkerConfig ( wco ) : { } ,
135
+ ] ;
136
+
137
+ if ( i18n ) {
138
+ return generateI18nBrowserWebpackConfigFromContext (
139
+ options ,
140
+ context ,
141
+ webpackPartialGenerator ,
142
+ host ,
143
+ ) ;
144
+ }
145
+
107
146
return generateBrowserWebpackConfigFromContext (
108
147
options ,
109
148
context ,
110
- wco => [
111
- getCommonConfig ( wco ) ,
112
- getBrowserConfig ( wco ) ,
113
- getStylesConfig ( wco ) ,
114
- getStatsConfig ( wco ) ,
115
- getAnalyticsConfig ( wco , context ) ,
116
- getCompilerConfig ( wco ) ,
117
- wco . buildOptions . webWorkerTsConfig ? getWorkerConfig ( wco ) : { } ,
118
- ] ,
149
+ webpackPartialGenerator ,
119
150
host ,
120
151
) ;
121
152
}
@@ -161,89 +192,24 @@ async function initialize(
161
192
projectSourceRoot ?: string ;
162
193
i18n : I18nOptions ;
163
194
} > {
164
- if ( ! context . target ) {
165
- throw new Error ( 'The builder requires a target.' ) ;
166
- }
167
-
168
- const tsConfig = readTsconfig ( options . tsConfig , context . workspaceRoot ) ;
169
- const usingIvy = tsConfig . options . enableIvy !== false ;
170
- const metadata = await context . getProjectMetadata ( context . target ) ;
171
- const projectRoot = path . join ( context . workspaceRoot , ( metadata . root as string ) || '' ) ;
172
- const i18n = createI18nOptions ( metadata , options . localize ) ;
173
-
174
- // Until 11.0, support deprecated i18n options when not using new localize option
175
- // i18nFormat is automatically calculated
176
- if ( options . localize === undefined && usingIvy ) {
177
- mergeDeprecatedI18nOptions ( i18n , options . i18nLocale , options . i18nFile ) ;
178
- } else if ( options . localize !== undefined && ! usingIvy ) {
179
- options . localize = undefined ;
180
-
181
- context . logger . warn ( `Option 'localize' is not supported with View Engine.` ) ;
182
- }
183
-
184
- if ( i18n . shouldInline ) {
185
- // Load locales
186
- const loader = await createTranslationLoader ( ) ;
187
-
188
- const usedFormats = new Set < string > ( ) ;
189
- for ( const [ locale , desc ] of Object . entries ( i18n . locales ) ) {
190
- if ( i18n . inlineLocales . has ( locale ) ) {
191
- const result = loader ( path . join ( projectRoot , desc . file ) ) ;
192
-
193
- usedFormats . add ( result . format ) ;
194
- if ( usedFormats . size > 1 && tsConfig . options . enableI18nLegacyMessageIdFormat !== false ) {
195
- // This limitation is only for legacy message id support (defaults to true as of 9.0)
196
- throw new Error (
197
- 'Localization currently only supports using one type of translation file format for the entire application.' ,
198
- ) ;
199
- }
200
-
201
- desc . format = result . format ;
202
- desc . translation = result . translation ;
203
- }
204
- }
205
-
206
- // Legacy message id's require the format of the translations
207
- if ( usedFormats . size > 0 ) {
208
- options . i18nFormat = [ ...usedFormats ] [ 0 ] ;
209
- }
210
- }
211
-
212
195
const originalOutputPath = options . outputPath ;
213
-
214
- // If inlining store the output in a temporary location to facilitate post-processing
215
- if ( i18n . shouldInline ) {
216
- options . outputPath = fs . mkdtempSync ( path . join ( fs . realpathSync ( os . tmpdir ( ) ) , 'angular-cli-' ) ) ;
217
- }
218
-
219
- const { config, projectSourceRoot } = await buildBrowserWebpackConfigFromContext (
196
+ const { config, projectRoot, projectSourceRoot, i18n } = await buildBrowserWebpackConfigFromContext (
220
197
options ,
221
198
context ,
222
199
host ,
200
+ true ,
223
201
) ;
224
202
225
- if ( i18n . shouldInline ) {
226
- // Remove localize "polyfill"
227
- if ( ! config . resolve ) {
228
- config . resolve = { } ;
229
- }
230
- if ( ! config . resolve . alias ) {
231
- config . resolve . alias = { } ;
232
- }
233
- config . resolve . alias [ '@angular/localize/init' ] = require . resolve ( './empty.js' ) ;
234
- }
235
-
236
203
let transformedConfig ;
237
204
if ( webpackConfigurationTransform ) {
238
205
transformedConfig = await webpackConfigurationTransform ( config ) ;
239
206
}
240
207
241
208
if ( options . deleteOutputPath ) {
242
- await deleteOutputDir (
243
- normalize ( context . workspaceRoot ) ,
244
- normalize ( originalOutputPath ) ,
245
- host ,
246
- ) . toPromise ( ) ;
209
+ deleteOutputDir (
210
+ context . workspaceRoot ,
211
+ originalOutputPath ,
212
+ ) ;
247
213
}
248
214
249
215
return { config : transformedConfig || config , projectRoot, projectSourceRoot, i18n } ;
@@ -312,15 +278,7 @@ export function buildWebpackBrowser(
312
278
313
279
return { success } ;
314
280
} else if ( success ) {
315
- const outputPaths =
316
- i18n . shouldInline && ! i18n . flatOutput
317
- ? [ ...i18n . inlineLocales ] . map ( l => path . join ( baseOutputPath , l ) )
318
- : [ baseOutputPath ] ;
319
- for ( const outputPath of outputPaths ) {
320
- if ( ! fs . existsSync ( outputPath ) ) {
321
- fs . mkdirSync ( outputPath , { recursive : true } ) ;
322
- }
323
- }
281
+ const outputPaths = ensureOutputPaths ( baseOutputPath , i18n ) ;
324
282
325
283
let noModuleFiles : EmittedFiles [ ] | undefined ;
326
284
let moduleFiles : EmittedFiles [ ] | undefined ;
@@ -586,14 +544,6 @@ export function buildWebpackBrowser(
586
544
}
587
545
} finally {
588
546
executor . stop ( ) ;
589
-
590
- if ( i18n . shouldInline ) {
591
- try {
592
- // Remove temporary directory used for i18n processing
593
- // tslint:disable-next-line: no-non-null-assertion
594
- await host . delete ( normalize ( webpackStats . outputPath ! ) ) . toPromise ( ) ;
595
- } catch { }
596
- }
597
547
}
598
548
599
549
// Copy assets
@@ -787,70 +737,6 @@ function generateIndex(
787
737
} ) . toPromise ( ) ;
788
738
}
789
739
790
- async function i18nInlineEmittedFiles (
791
- context : BuilderContext ,
792
- emittedFiles : EmittedFiles [ ] ,
793
- i18n : I18nOptions ,
794
- baseOutputPath : string ,
795
- outputPaths : string [ ] ,
796
- scriptsEntryPointName : string [ ] ,
797
- emittedPath : string ,
798
- es5 : boolean ,
799
- missingTranslation : 'error' | 'warning' | 'ignore' | undefined ,
800
- ) {
801
- const executor = new BundleActionExecutor ( { i18n } ) ;
802
- let hasErrors = false ;
803
- try {
804
- const { options, originalFiles : processedFiles } = emittedFilesToInlineOptions (
805
- emittedFiles ,
806
- scriptsEntryPointName ,
807
- emittedPath ,
808
- baseOutputPath ,
809
- es5 ,
810
- missingTranslation ,
811
- ) ;
812
-
813
- for await ( const result of executor . inlineAll ( options ) ) {
814
- for ( const diagnostic of result . diagnostics ) {
815
- if ( diagnostic . type === 'error' ) {
816
- hasErrors = true ;
817
- context . logger . error ( diagnostic . message ) ;
818
- } else {
819
- context . logger . warn ( diagnostic . message ) ;
820
- }
821
- }
822
- }
823
-
824
- // Copy any non-processed files into the output locations
825
- await copyAssets (
826
- [
827
- {
828
- glob : '**/*' ,
829
- input : emittedPath ,
830
- output : '' ,
831
- ignore : [ ...processedFiles ] . map ( f => path . relative ( emittedPath , f ) ) ,
832
- } ,
833
- ] ,
834
- outputPaths ,
835
- '' ,
836
- ) ;
837
- } catch ( err ) {
838
- context . logger . error ( 'Localized bundle generation failed: ' + err . message ) ;
839
-
840
- return false ;
841
- } finally {
842
- executor . stop ( ) ;
843
- }
844
-
845
- context . logger . info ( `Localized bundle generation ${ hasErrors ? 'failed' : 'complete' } .` ) ;
846
-
847
- if ( hasErrors ) {
848
- return false ;
849
- }
850
-
851
- return true ;
852
- }
853
-
854
740
function mapErrorToMessage ( error : unknown ) : string | undefined {
855
741
if ( error instanceof Error ) {
856
742
return error . message ;
0 commit comments