@@ -38,62 +38,64 @@ export function createBrowserCodeBundleOptions(
38
38
target : string [ ] ,
39
39
sourceFileCache : SourceFileCache ,
40
40
stylesheetBundler : ComponentStylesheetBundler ,
41
- ) : BuildOptions {
42
- const { entryPoints, outputNames, polyfills } = options ;
43
-
44
- const pluginOptions = createCompilerPluginOptions ( options , sourceFileCache ) ;
45
-
46
- const zoneless = isZonelessApp ( polyfills ) ;
47
-
48
- const buildOptions : BuildOptions = {
49
- ...getEsBuildCommonOptions ( options ) ,
50
- platform : 'browser' ,
51
- // Note: `es2015` is needed for RxJS v6. If not specified, `module` would
52
- // match and the ES5 distribution would be bundled and ends up breaking at
53
- // runtime with the RxJS testing library.
54
- // More details: https://github.com/angular/angular-cli/issues/25405.
55
- mainFields : [ 'es2020' , 'es2015' , 'browser' , 'module' , 'main' ] ,
56
- entryNames : outputNames . bundles ,
57
- entryPoints,
58
- target,
59
- supported : getFeatureSupport ( target , zoneless ) ,
60
- plugins : [
61
- createLoaderImportAttributePlugin ( ) ,
62
- createWasmPlugin ( { allowAsync : zoneless , cache : sourceFileCache ?. loadResultCache } ) ,
63
- createSourcemapIgnorelistPlugin ( ) ,
64
- createCompilerPlugin (
65
- // JS/TS options
66
- pluginOptions ,
67
- // Component stylesheet bundler
68
- stylesheetBundler ,
69
- ) ,
70
- ] ,
71
- } ;
41
+ ) : BundlerOptionsFactory {
42
+ return ( loadCache ) => {
43
+ const { entryPoints, outputNames, polyfills } = options ;
44
+
45
+ const pluginOptions = createCompilerPluginOptions ( options , sourceFileCache , loadCache ) ;
46
+
47
+ const zoneless = isZonelessApp ( polyfills ) ;
48
+
49
+ const buildOptions : BuildOptions = {
50
+ ...getEsBuildCommonOptions ( options ) ,
51
+ platform : 'browser' ,
52
+ // Note: `es2015` is needed for RxJS v6. If not specified, `module` would
53
+ // match and the ES5 distribution would be bundled and ends up breaking at
54
+ // runtime with the RxJS testing library.
55
+ // More details: https://github.com/angular/angular-cli/issues/25405.
56
+ mainFields : [ 'es2020' , 'es2015' , 'browser' , 'module' , 'main' ] ,
57
+ entryNames : outputNames . bundles ,
58
+ entryPoints,
59
+ target,
60
+ supported : getFeatureSupport ( target , zoneless ) ,
61
+ plugins : [
62
+ createLoaderImportAttributePlugin ( ) ,
63
+ createWasmPlugin ( { allowAsync : zoneless , cache : loadCache } ) ,
64
+ createSourcemapIgnorelistPlugin ( ) ,
65
+ createCompilerPlugin (
66
+ // JS/TS options
67
+ pluginOptions ,
68
+ // Component stylesheet bundler
69
+ stylesheetBundler ,
70
+ ) ,
71
+ ] ,
72
+ } ;
72
73
73
- if ( options . plugins ) {
74
- buildOptions . plugins ?. push ( ...options . plugins ) ;
75
- }
74
+ if ( options . plugins ) {
75
+ buildOptions . plugins ?. push ( ...options . plugins ) ;
76
+ }
76
77
77
- if ( options . externalPackages ) {
78
- // Package files affected by a customized loader should not be implicitly marked as external
79
- if (
80
- options . loaderExtensions ||
81
- options . plugins ||
82
- typeof options . externalPackages === 'object'
83
- ) {
84
- // Plugin must be added after custom plugins to ensure any added loader options are considered
85
- buildOptions . plugins ?. push (
86
- createExternalPackagesPlugin (
87
- options . externalPackages !== true ? options . externalPackages : undefined ,
88
- ) ,
89
- ) ;
90
- } else {
91
- // Safe to use the packages external option directly
92
- buildOptions . packages = 'external' ;
78
+ if ( options . externalPackages ) {
79
+ // Package files affected by a customized loader should not be implicitly marked as external
80
+ if (
81
+ options . loaderExtensions ||
82
+ options . plugins ||
83
+ typeof options . externalPackages === 'object'
84
+ ) {
85
+ // Plugin must be added after custom plugins to ensure any added loader options are considered
86
+ buildOptions . plugins ?. push (
87
+ createExternalPackagesPlugin (
88
+ options . externalPackages !== true ? options . externalPackages : undefined ,
89
+ ) ,
90
+ ) ;
91
+ } else {
92
+ // Safe to use the packages external option directly
93
+ buildOptions . packages = 'external' ;
94
+ }
93
95
}
94
- }
95
96
96
- return buildOptions ;
97
+ return buildOptions ;
98
+ } ;
97
99
}
98
100
99
101
export function createBrowserPolyfillBundleOptions (
@@ -158,7 +160,7 @@ export function createBrowserPolyfillBundleOptions(
158
160
export function createServerPolyfillBundleOptions (
159
161
options : NormalizedApplicationBuildOptions ,
160
162
target : string [ ] ,
161
- sourceFileCache ?: SourceFileCache ,
163
+ loadResultCache : LoadResultCache | undefined ,
162
164
) : BundlerOptionsFactory | undefined {
163
165
const serverPolyfills : string [ ] = [ ] ;
164
166
const polyfillsFromConfig = new Set ( options . polyfills ) ;
@@ -185,7 +187,7 @@ export function createServerPolyfillBundleOptions(
185
187
} ,
186
188
namespace ,
187
189
false ,
188
- sourceFileCache ?. loadResultCache ,
190
+ loadResultCache ,
189
191
) ;
190
192
191
193
if ( ! polyfillBundleOptions ) {
@@ -372,137 +374,139 @@ export function createSsrEntryCodeBundleOptions(
372
374
target : string [ ] ,
373
375
sourceFileCache : SourceFileCache ,
374
376
stylesheetBundler : ComponentStylesheetBundler ,
375
- ) : BuildOptions {
377
+ ) : BundlerOptionsFactory {
376
378
const { workspaceRoot, ssrOptions, externalPackages } = options ;
377
379
const serverEntryPoint = ssrOptions ?. entry ;
378
380
assert (
379
381
serverEntryPoint ,
380
382
'createSsrEntryCodeBundleOptions should not be called without a defined serverEntryPoint.' ,
381
383
) ;
382
384
383
- const pluginOptions = createCompilerPluginOptions ( options , sourceFileCache ) ;
384
-
385
- const ssrEntryNamespace = 'angular:ssr-entry' ;
386
- const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest' ;
387
- const ssrInjectRequireNamespace = 'angular:ssr-entry-inject-require' ;
388
- const isNodePlatform = options . ssrOptions ?. platform !== ExperimentalPlatform . Neutral ;
389
-
390
- const inject : string [ ] = [ ssrInjectManifestNamespace ] ;
391
- if ( isNodePlatform ) {
392
- inject . unshift ( ssrInjectRequireNamespace ) ;
393
- }
394
-
395
- const buildOptions : BuildOptions = {
396
- ...getEsBuildServerCommonOptions ( options ) ,
397
- target,
398
- entryPoints : {
399
- // TODO: consider renaming to index
400
- 'server' : ssrEntryNamespace ,
401
- } ,
402
- supported : getFeatureSupport ( target , true ) ,
403
- plugins : [
404
- createSourcemapIgnorelistPlugin ( ) ,
405
- createCompilerPlugin (
406
- // JS/TS options
407
- { ...pluginOptions , noopTypeScriptCompilation : true } ,
408
- // Component stylesheet bundler
409
- stylesheetBundler ,
410
- ) ,
411
- ] ,
412
- inject,
413
- } ;
414
-
415
- buildOptions . plugins ??= [ ] ;
385
+ return ( loadResultCache ) => {
386
+ const pluginOptions = createCompilerPluginOptions ( options , sourceFileCache , loadResultCache ) ;
416
387
417
- if ( externalPackages ) {
418
- buildOptions . packages = 'external' ;
419
- } else {
420
- buildOptions . plugins . push ( createRxjsEsmResolutionPlugin ( ) ) ;
421
- }
388
+ const ssrEntryNamespace = 'angular:ssr-entry' ;
389
+ const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest' ;
390
+ const ssrInjectRequireNamespace = 'angular:ssr-entry-inject-require' ;
391
+ const isNodePlatform = options . ssrOptions ?. platform !== ExperimentalPlatform . Neutral ;
422
392
423
- // Mark manifest file as external. As this will be generated later on.
424
- ( buildOptions . external ??= [ ] ) . push ( '*/main.server.mjs' , ...SERVER_GENERATED_EXTERNALS ) ;
393
+ const inject : string [ ] = [ ssrInjectManifestNamespace ] ;
394
+ if ( isNodePlatform ) {
395
+ inject . unshift ( ssrInjectRequireNamespace ) ;
396
+ }
425
397
426
- if ( ! isNodePlatform ) {
427
- // `@angular/platform-server` lazily depends on `xhr2` for XHR usage with the HTTP client.
428
- // Since `xhr2` has Node.js dependencies, it cannot be used when targeting non-Node.js platforms.
429
- // Note: The framework already issues a warning when using XHR with SSR.
430
- buildOptions . external . push ( 'xhr2' ) ;
431
- }
398
+ const buildOptions : BuildOptions = {
399
+ ...getEsBuildServerCommonOptions ( options ) ,
400
+ target,
401
+ entryPoints : {
402
+ // TODO: consider renaming to index
403
+ 'server' : ssrEntryNamespace ,
404
+ } ,
405
+ supported : getFeatureSupport ( target , true ) ,
406
+ plugins : [
407
+ createSourcemapIgnorelistPlugin ( ) ,
408
+ createCompilerPlugin (
409
+ // JS/TS options
410
+ { ...pluginOptions , noopTypeScriptCompilation : true } ,
411
+ // Component stylesheet bundler
412
+ stylesheetBundler ,
413
+ ) ,
414
+ ] ,
415
+ inject,
416
+ } ;
432
417
433
- buildOptions . plugins . push (
434
- createServerBundleMetadata ( { ssrEntryBundle : true } ) ,
435
- createVirtualModulePlugin ( {
436
- namespace : ssrInjectRequireNamespace ,
437
- cache : sourceFileCache ?. loadResultCache ,
438
- loadContent : ( ) => {
439
- const contents : string [ ] = [
440
- // Note: Needed as esbuild does not provide require shims / proxy from ESModules.
441
- // See: https://github.com/evanw/esbuild/issues/1921.
442
- `import { createRequire } from 'node:module';` ,
443
- `globalThis['require'] ??= createRequire(import.meta.url);` ,
444
- ] ;
418
+ buildOptions . plugins ??= [ ] ;
445
419
446
- return {
447
- contents : contents . join ( '\n' ) ,
448
- loader : 'js' ,
449
- resolveDir : workspaceRoot ,
450
- } ;
451
- } ,
452
- } ) ,
453
- createVirtualModulePlugin ( {
454
- namespace : ssrInjectManifestNamespace ,
455
- cache : sourceFileCache ?. loadResultCache ,
456
- loadContent : ( ) => {
457
- const contents : string [ ] = [
458
- // Configure `@angular/ssr` app engine manifest.
459
- `import manifest from './${ SERVER_APP_ENGINE_MANIFEST_FILENAME } ';` ,
460
- `import { ɵsetAngularAppEngineManifest } from '@angular/ssr';` ,
461
- `ɵsetAngularAppEngineManifest(manifest);` ,
462
- ] ;
420
+ if ( externalPackages ) {
421
+ buildOptions . packages = 'external' ;
422
+ } else {
423
+ buildOptions . plugins . push ( createRxjsEsmResolutionPlugin ( ) ) ;
424
+ }
463
425
464
- return {
465
- contents : contents . join ( '\n' ) ,
466
- loader : 'js' ,
467
- resolveDir : workspaceRoot ,
468
- } ;
469
- } ,
470
- } ) ,
471
- createVirtualModulePlugin ( {
472
- namespace : ssrEntryNamespace ,
473
- cache : sourceFileCache ?. loadResultCache ,
474
- loadContent : ( ) => {
475
- const serverEntryPointJsImport = entryFileToWorkspaceRelative (
476
- workspaceRoot ,
477
- serverEntryPoint ,
478
- ) ;
479
- const contents : string [ ] = [
480
- // Re-export all symbols including default export
481
- `import * as server from '${ serverEntryPointJsImport } ';` ,
482
- `export * from '${ serverEntryPointJsImport } ';` ,
483
- // The below is needed to avoid
484
- // `Import "default" will always be undefined because there is no matching export` warning when no default is present.
485
- `const defaultExportName = 'default';` ,
486
- `export default server[defaultExportName]` ,
426
+ // Mark manifest file as external. As this will be generated later on.
427
+ ( buildOptions . external ??= [ ] ) . push ( '*/main.server.mjs' , ...SERVER_GENERATED_EXTERNALS ) ;
487
428
488
- // Add @angular /ssr exports
489
- `export { AngularAppEngine } from '@angular/ssr';` ,
490
- ] ;
429
+ if ( ! isNodePlatform ) {
430
+ // `@angular/platform-server` lazily depends on `xhr2` for XHR usage with the HTTP client.
431
+ // Since `xhr2` has Node.js dependencies, it cannot be used when targeting non-Node.js platforms.
432
+ // Note: The framework already issues a warning when using XHR with SSR.
433
+ buildOptions . external . push ( 'xhr2' ) ;
434
+ }
491
435
492
- return {
493
- contents : contents . join ( '\n' ) ,
494
- loader : 'js' ,
495
- resolveDir : workspaceRoot ,
496
- } ;
497
- } ,
498
- } ) ,
499
- ) ;
436
+ buildOptions . plugins . push (
437
+ createServerBundleMetadata ( { ssrEntryBundle : true } ) ,
438
+ createVirtualModulePlugin ( {
439
+ namespace : ssrInjectRequireNamespace ,
440
+ cache : loadResultCache ,
441
+ loadContent : ( ) => {
442
+ const contents : string [ ] = [
443
+ // Note: Needed as esbuild does not provide require shims / proxy from ESModules.
444
+ // See: https://github.com/evanw/esbuild/issues/1921.
445
+ `import { createRequire } from 'node:module';` ,
446
+ `globalThis['require'] ??= createRequire(import.meta.url);` ,
447
+ ] ;
448
+
449
+ return {
450
+ contents : contents . join ( '\n' ) ,
451
+ loader : 'js' ,
452
+ resolveDir : workspaceRoot ,
453
+ } ;
454
+ } ,
455
+ } ) ,
456
+ createVirtualModulePlugin ( {
457
+ namespace : ssrInjectManifestNamespace ,
458
+ cache : loadResultCache ,
459
+ loadContent : ( ) => {
460
+ const contents : string [ ] = [
461
+ // Configure `@angular/ssr` app engine manifest.
462
+ `import manifest from './${ SERVER_APP_ENGINE_MANIFEST_FILENAME } ';` ,
463
+ `import { ɵsetAngularAppEngineManifest } from '@angular/ssr';` ,
464
+ `ɵsetAngularAppEngineManifest(manifest);` ,
465
+ ] ;
466
+
467
+ return {
468
+ contents : contents . join ( '\n' ) ,
469
+ loader : 'js' ,
470
+ resolveDir : workspaceRoot ,
471
+ } ;
472
+ } ,
473
+ } ) ,
474
+ createVirtualModulePlugin ( {
475
+ namespace : ssrEntryNamespace ,
476
+ cache : loadResultCache ,
477
+ loadContent : ( ) => {
478
+ const serverEntryPointJsImport = entryFileToWorkspaceRelative (
479
+ workspaceRoot ,
480
+ serverEntryPoint ,
481
+ ) ;
482
+ const contents : string [ ] = [
483
+ // Re-export all symbols including default export
484
+ `import * as server from '${ serverEntryPointJsImport } ';` ,
485
+ `export * from '${ serverEntryPointJsImport } ';` ,
486
+ // The below is needed to avoid
487
+ // `Import "default" will always be undefined because there is no matching export` warning when no default is present.
488
+ `const defaultExportName = 'default';` ,
489
+ `export default server[defaultExportName]` ,
490
+
491
+ // Add @angular /ssr exports
492
+ `export { AngularAppEngine } from '@angular/ssr';` ,
493
+ ] ;
494
+
495
+ return {
496
+ contents : contents . join ( '\n' ) ,
497
+ loader : 'js' ,
498
+ resolveDir : workspaceRoot ,
499
+ } ;
500
+ } ,
501
+ } ) ,
502
+ ) ;
500
503
501
- if ( options . plugins ) {
502
- buildOptions . plugins . push ( ...options . plugins ) ;
503
- }
504
+ if ( options . plugins ) {
505
+ buildOptions . plugins . push ( ...options . plugins ) ;
506
+ }
504
507
505
- return buildOptions ;
508
+ return buildOptions ;
509
+ } ;
506
510
}
507
511
508
512
function getEsBuildServerCommonOptions ( options : NormalizedApplicationBuildOptions ) : BuildOptions {
0 commit comments