@@ -13,11 +13,9 @@ import {
13
13
targetFromTargetString ,
14
14
} from '@angular-devkit/architect' ;
15
15
import { JsonObject } from '@angular-devkit/core' ;
16
- import type { Type } from '@angular/core' ;
17
- import type * as platformServer from '@angular/platform-server' ;
18
- import assert from 'assert' ;
19
16
import * as fs from 'fs' ;
20
17
import * as path from 'path' ;
18
+ import Piscina from 'piscina' ;
21
19
import { normalizeOptimization } from '../../utils' ;
22
20
import { assertIsError } from '../../utils/error' ;
23
21
import { InlineCriticalCssProcessor } from '../../utils/index-file/inline-critical-css' ;
@@ -45,10 +43,9 @@ async function _renderUniversal(
45
43
browserBuilderName ,
46
44
) ;
47
45
48
- // Initialize zone.js
46
+ // Locate zone.js to load in the render worker
49
47
const root = context . workspaceRoot ;
50
48
const zonePackage = require . resolve ( 'zone.js' , { paths : [ root ] } ) ;
51
- await import ( zonePackage ) ;
52
49
53
50
const projectName = context . target && context . target . project ;
54
51
if ( ! projectName ) {
@@ -66,69 +63,63 @@ async function _renderUniversal(
66
63
} )
67
64
: undefined ;
68
65
69
- for ( const { path : outputPath , baseHref } of browserResult . outputs ) {
70
- const localeDirectory = path . relative ( browserResult . baseOutputPath , outputPath ) ;
71
- const browserIndexOutputPath = path . join ( outputPath , 'index.html' ) ;
72
- const indexHtml = await fs . promises . readFile ( browserIndexOutputPath , 'utf8' ) ;
73
- const serverBundlePath = await _getServerModuleBundlePath (
74
- options ,
75
- context ,
76
- serverResult ,
77
- localeDirectory ,
78
- ) ;
79
-
80
- const { AppServerModule, renderModule, ɵSERVER_CONTEXT } = ( await import ( serverBundlePath ) ) as {
81
- renderModule : typeof platformServer . renderModule | undefined ;
82
- ɵSERVER_CONTEXT : typeof platformServer . ɵSERVER_CONTEXT | undefined ;
83
- AppServerModule : Type < unknown > | undefined ;
84
- } ;
85
-
86
- assert ( renderModule , `renderModule was not exported from: ${ serverBundlePath } .` ) ;
87
- assert ( AppServerModule , `AppServerModule was not exported from: ${ serverBundlePath } .` ) ;
88
- assert ( ɵSERVER_CONTEXT , `ɵSERVER_CONTEXT was not exported from: ${ serverBundlePath } .` ) ;
89
-
90
- // Load platform server module renderer
91
- let html = await renderModule ( AppServerModule , {
92
- document : indexHtml ,
93
- url : options . route ,
94
- extraProviders : [
95
- {
96
- provide : ɵSERVER_CONTEXT ,
97
- useValue : 'app-shell' ,
98
- } ,
99
- ] ,
100
- } ) ;
101
-
102
- // Overwrite the client index file.
103
- const outputIndexPath = options . outputIndexPath
104
- ? path . join ( root , options . outputIndexPath )
105
- : browserIndexOutputPath ;
106
-
107
- if ( inlineCriticalCssProcessor ) {
108
- const { content, warnings, errors } = await inlineCriticalCssProcessor . process ( html , {
109
- outputPath,
66
+ const renderWorker = new Piscina ( {
67
+ filename : require . resolve ( './render-worker' ) ,
68
+ maxThreads : 1 ,
69
+ workerData : { zonePackage } ,
70
+ } ) ;
71
+
72
+ try {
73
+ for ( const { path : outputPath , baseHref } of browserResult . outputs ) {
74
+ const localeDirectory = path . relative ( browserResult . baseOutputPath , outputPath ) ;
75
+ const browserIndexOutputPath = path . join ( outputPath , 'index.html' ) ;
76
+ const indexHtml = await fs . promises . readFile ( browserIndexOutputPath , 'utf8' ) ;
77
+ const serverBundlePath = await _getServerModuleBundlePath (
78
+ options ,
79
+ context ,
80
+ serverResult ,
81
+ localeDirectory ,
82
+ ) ;
83
+
84
+ let html : string = await renderWorker . run ( {
85
+ serverBundlePath,
86
+ document : indexHtml ,
87
+ url : options . route ,
110
88
} ) ;
111
- html = content ;
112
89
113
- if ( warnings . length || errors . length ) {
114
- spinner . stop ( ) ;
115
- warnings . forEach ( ( m ) => context . logger . warn ( m ) ) ;
116
- errors . forEach ( ( m ) => context . logger . error ( m ) ) ;
117
- spinner . start ( ) ;
90
+ // Overwrite the client index file.
91
+ const outputIndexPath = options . outputIndexPath
92
+ ? path . join ( root , options . outputIndexPath )
93
+ : browserIndexOutputPath ;
94
+
95
+ if ( inlineCriticalCssProcessor ) {
96
+ const { content, warnings, errors } = await inlineCriticalCssProcessor . process ( html , {
97
+ outputPath,
98
+ } ) ;
99
+ html = content ;
100
+
101
+ if ( warnings . length || errors . length ) {
102
+ spinner . stop ( ) ;
103
+ warnings . forEach ( ( m ) => context . logger . warn ( m ) ) ;
104
+ errors . forEach ( ( m ) => context . logger . error ( m ) ) ;
105
+ spinner . start ( ) ;
106
+ }
118
107
}
119
- }
120
108
121
- await fs . promises . writeFile ( outputIndexPath , html ) ;
109
+ await fs . promises . writeFile ( outputIndexPath , html ) ;
122
110
123
- if ( browserOptions . serviceWorker ) {
124
- await augmentAppWithServiceWorker (
125
- projectRoot ,
126
- root ,
127
- outputPath ,
128
- baseHref ?? '/' ,
129
- browserOptions . ngswConfigPath ,
130
- ) ;
111
+ if ( browserOptions . serviceWorker ) {
112
+ await augmentAppWithServiceWorker (
113
+ projectRoot ,
114
+ root ,
115
+ outputPath ,
116
+ baseHref ?? '/' ,
117
+ browserOptions . ngswConfigPath ,
118
+ ) ;
119
+ }
131
120
}
121
+ } finally {
122
+ await renderWorker . destroy ( ) ;
132
123
}
133
124
134
125
return browserResult ;
0 commit comments