@@ -50,6 +50,42 @@ export function add(options: MfSchematicSchema): Rule {
5050 return config ( options ) ;
5151}
5252
53+ export function adjustSSR ( sourceRoot : string , ssrMappings : string ) : Rule {
54+ return async function ( tree , context ) {
55+
56+ const server = path . join ( sourceRoot , 'server.ts' ) ;
57+
58+ if ( ! tree . exists ( server ) ) {
59+ return ;
60+ }
61+
62+ let content = tree . read ( server ) . toString ( 'utf-8' ) ;
63+
64+ const imports = `import { CustomResourceLoader } from '@nguniversal/common/clover/server/src/custom-resource-loader';
65+ import { createFetch } from '@angular-architects/module-federation/nguniversal';
66+ ` ;
67+
68+ content = imports + content ;
69+ content = content . replace ( 'const ssrEngine = new Engine();' , `
70+ // Without mappings, remotes are loaded via HTTP
71+ const mappings = ${ ssrMappings } ;
72+
73+ // Monkey Patching Angular Universal for Module Federation
74+ CustomResourceLoader.prototype.fetch = createFetch(mappings);
75+
76+ const ssrEngine = new Engine();
77+ ` ) ;
78+
79+ // Compensate for issue with version 12.0.0
80+ content = content . replace (
81+ 'const HOST = `http://localhost:${PORT}`;' ,
82+ 'const HOST = `localhost:${PORT}`;' ) ;
83+
84+ tree . overwrite ( server , content ) ;
85+
86+ }
87+ }
88+
5389function makeMainAsync ( main : string ) : Rule {
5490 return async function ( tree , context ) {
5591
@@ -68,7 +104,7 @@ function makeMainAsync(main: string): Rule {
68104 }
69105}
70106
71- function getWorkspaceFileName ( tree : Tree ) : string {
107+ export function getWorkspaceFileName ( tree : Tree ) : string {
72108 if ( tree . exists ( 'angular.json' ) ) {
73109 return 'angular.json' ;
74110 }
@@ -122,6 +158,7 @@ export default function config (options: MfSchematicSchema): Rule {
122158 }
123159
124160 const projectRoot : string = projectConfig . root ;
161+ const projectSourceRoot : string = projectConfig . sourceRoot ;
125162
126163 const configPath = path . join ( projectRoot , 'webpack.config.js' ) . replace ( / \\ / g, '/' ) ;
127164 const configProdPath = path . join ( projectRoot , 'webpack.prod.config.js' ) . replace ( / \\ / g, '/' ) ;
@@ -170,18 +207,41 @@ export default function config (options: MfSchematicSchema): Rule {
170207 projectConfig . architect . test . options . extraWebpackConfig = configPath ;
171208 }
172209
210+ if ( projectConfig ?. architect ?. [ 'extract-i18n' ] ?. options ) {
211+ projectConfig . architect [ 'extract-i18n' ] . options . extraWebpackConfig = configPath ;
212+ }
213+
214+ updateServerBuilder ( projectConfig , configPath ) ;
215+ const ssrMappings = generateSsrMappings ( workspace , projectName ) ;
216+
173217 tree . overwrite ( workspaceFileName , JSON . stringify ( workspace , null , '\t' ) ) ;
174218
175219 updatePackageJson ( tree ) ;
176220
177221 return chain ( [
178222 makeMainAsync ( main ) ,
223+ adjustSSR ( projectSourceRoot , ssrMappings ) ,
179224 externalSchematic ( 'ngx-build-plus' , 'ng-add' , { project : options . project } ) ,
180225 ] ) ;
181226
182227 }
183228}
184229
230+ export function updateServerBuilder ( projectConfig : any , configPath : string ) {
231+
232+ if ( projectConfig ?. architect ?. server ) {
233+ projectConfig . architect . server . builder = 'ngx-build-plus:server' ;
234+ }
235+
236+ if ( projectConfig ?. architect ?. server ?. options ) {
237+ projectConfig . architect . server . options . extraWebpackConfig = configPath ;
238+ }
239+
240+ if ( projectConfig ?. architect ?. server ?. configurations ?. production ) {
241+ projectConfig . architect . server . configurations . production . extraWebpackConfig = configPath ;
242+ }
243+ }
244+
185245function generateRemoteConfig ( workspace : any , projectName : string ) {
186246 let remotes = '' ;
187247 for ( const p in workspace . projects ) {
@@ -204,3 +264,30 @@ function generateRemoteConfig(workspace: any, projectName: string) {
204264 return remotes ;
205265}
206266
267+ export function generateSsrMappings ( workspace : any , projectName : string ) : string {
268+ let remotes = '{\n' ;
269+
270+ const projectOutPath = workspace . projects [ projectName ] . architect . build . options . outputPath ;
271+
272+ for ( const p in workspace . projects ) {
273+ const project = workspace . projects [ p ] ;
274+ const projectType = project . projectType ?? 'application' ;
275+
276+ if ( p !== projectName
277+ && projectType === 'application'
278+ && project ?. architect ?. serve
279+ && project ?. architect ?. build ) {
280+
281+ const pPort = project . architect . serve . options ?. port ?? 4200 ;
282+ const outPath = project . architect . build . options . outputPath ;
283+ const relOutPath = path . relative ( projectOutPath , outPath ) . replace ( / \\ / g, '/' ) + '/' ;
284+
285+ remotes += `\t// 'http://localhost:${ pPort } /': join(__dirname, '${ relOutPath } ')\n` ;
286+ }
287+ }
288+
289+ remotes += '}' ;
290+
291+ return remotes ;
292+ }
293+
0 commit comments