@@ -2,6 +2,11 @@ import {
2
2
chain ,
3
3
Rule ,
4
4
Tree ,
5
+ url ,
6
+ apply ,
7
+ mergeWith ,
8
+ template ,
9
+ move
5
10
} from '@angular-devkit/schematics' ;
6
11
7
12
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks' ;
@@ -18,38 +23,6 @@ import { MfSchematicSchema } from './schema';
18
23
19
24
import { addPackageJsonDependency , getPackageJsonDependency , NodeDependencyType } from '@schematics/angular/utility/dependencies' ;
20
25
21
- // export async function npmInstall(packageName: string) {
22
- // await new Promise<boolean>((resolve) => {
23
- // console.log('Installing packages...');
24
- // spawn('npm', ['install', packageName, '-D'])
25
- // .on('close', (code: number) => {
26
- // if (code === 0) {
27
- // console.log('Packages installed successfully ✅');
28
- // resolve(true);
29
- // } else {
30
- // throw new Error(
31
- // `Error installing '${packageName}'`
32
- // );
33
- // }
34
- // });
35
- // });
36
- // }
37
-
38
- // export async function yarnAdd(packageName: string) {
39
- // await new Promise<boolean>((resolve) => {
40
- // spawn('npm', ['install', packageName, '-D'])
41
- // .on('close', (code: number) => {
42
- // if (code === 0) {
43
- // resolve(true);
44
- // } else {
45
- // throw new Error(
46
- // `Error installing '${packageName}'`
47
- // );
48
- // }
49
- // });
50
- // });
51
- // }
52
-
53
26
export function add ( options : MfSchematicSchema ) : Rule {
54
27
return config ( options ) ;
55
28
}
@@ -90,7 +63,7 @@ const ssrEngine = new Engine();
90
63
}
91
64
}
92
65
93
- function makeMainAsync ( main : string ) : Rule {
66
+ function makeMainAsync ( main : string , options : MfSchematicSchema ) : Rule {
94
67
return async function ( tree , context ) {
95
68
96
69
const mainPath = path . dirname ( main ) ;
@@ -103,8 +76,22 @@ function makeMainAsync(main: string): Rule {
103
76
104
77
const mainContent = tree . read ( main ) ;
105
78
tree . create ( bootstrapName , mainContent ) ;
106
- tree . overwrite ( main , "import('./bootstrap')\n\t.catch(err => console.error(err));\n" ) ;
107
79
80
+ let newMainContent = '' ;
81
+ if ( options . type === 'dynamic-host' ) {
82
+ newMainContent = `import { loadManifest } from '@angular-architects/module-federation';
83
+
84
+ loadManifest("/assets/mf.manifest.json")
85
+ .catch(err => console.error(err))
86
+ .then(_ => import('./bootstrap'))
87
+ .catch(err => console.error(err));
88
+ ` ;
89
+ }
90
+ else {
91
+ newMainContent = "import('./bootstrap')\n\t.catch(err => console.error(err));\n"
92
+ }
93
+
94
+ tree . overwrite ( main , newMainContent ) ;
108
95
}
109
96
}
110
97
@@ -115,7 +102,7 @@ export function getWorkspaceFileName(tree: Tree): string {
115
102
if ( tree . exists ( 'workspace.json' ) ) {
116
103
return 'workspace.json' ;
117
104
}
118
- throw new Error ( 'angular.json or workspae .json expected! Did you call this in your project\'s root?' ) ;
105
+ throw new Error ( 'angular.json or workspace .json expected! Did you call this in your project\'s root?' ) ;
119
106
}
120
107
121
108
interface PackageJson {
@@ -162,7 +149,21 @@ function nxBuildersAvailable(tree: Tree): boolean {
162
149
163
150
}
164
151
165
- export default function config ( options : MfSchematicSchema ) : Rule {
152
+ async function generateWebpackConfig ( remoteMap : Record < string , string > , src : string , options : MfSchematicSchema ) {
153
+ const tmpl = url ( './files' ) ;
154
+
155
+ const applied = apply ( tmpl , [
156
+ template ( {
157
+ remoteMap,
158
+ ...options
159
+ } ) ,
160
+ move ( src )
161
+ ] ) ;
162
+
163
+ return mergeWith ( applied ) ;
164
+ }
165
+
166
+ export default function config ( options : MfSchematicSchema ) : Rule {
166
167
167
168
return async function ( tree , context ) {
168
169
@@ -191,6 +192,8 @@ export default function config (options: MfSchematicSchema): Rule {
191
192
192
193
const configPath = path . join ( projectRoot , 'webpack.config.js' ) . replace ( / \\ / g, '/' ) ;
193
194
const configProdPath = path . join ( projectRoot , 'webpack.prod.config.js' ) . replace ( / \\ / g, '/' ) ;
195
+ const manifestPath = path . join ( projectRoot , 'src/assets/mf.manifest.json' ) . replace ( / \\ / g, '/' ) ;
196
+
194
197
const port = parseInt ( options . port ) ;
195
198
const main = projectConfig . architect . build . options . main ;
196
199
@@ -206,12 +209,25 @@ export default function config (options: MfSchematicSchema): Rule {
206
209
throw new Error ( `Port must be a number!` ) ;
207
210
}
208
211
209
- const remotes = generateRemoteConfig ( workspace , projectName ) ;
210
- const webpackConfig = createConfig ( projectName , remotes , relTsConfigPath , projectRoot , port ) ;
212
+ const remoteMap = await generateRemoteMap ( workspace , projectName ) ;
213
+
214
+ let generateRule = null ;
215
+
216
+ if ( options . type === 'legacy' ) {
217
+ const remotes = generateRemoteConfig ( workspace , projectName ) ;
218
+ const webpackConfig = createConfig ( projectName , remotes , relTsConfigPath , projectRoot , port ) ;
219
+ tree . create ( configPath , webpackConfig ) ;
220
+ }
221
+ else {
222
+ generateRule = await generateWebpackConfig ( remoteMap , projectRoot , options ) ;
223
+ }
211
224
212
- tree . create ( configPath , webpackConfig ) ;
213
225
tree . create ( configProdPath , prodConfig ) ;
214
226
227
+ if ( options . type === 'dynamic-host' ) {
228
+ tree . create ( manifestPath , JSON . stringify ( remoteMap , null , '\t' ) ) ;
229
+ }
230
+
215
231
if ( options . nxBuilders && ! nxBuildersAvailable ( tree ) ) {
216
232
console . info ( 'To use Nx builders, make sure you have Nx version 12.9 or higher!' ) ;
217
233
options . nxBuilders = false ;
@@ -270,7 +286,6 @@ export default function config (options: MfSchematicSchema): Rule {
270
286
projectConfig . architect [ 'extract-i18n' ] . options . extraWebpackConfig = configPath ;
271
287
}
272
288
273
-
274
289
updateTsConfig ( tree , tsConfigName ) ;
275
290
276
291
const localTsConfig = path . join ( projectRoot , 'tsconfig.app.json' ) ;
@@ -298,9 +313,9 @@ export default function config (options: MfSchematicSchema): Rule {
298
313
}
299
314
300
315
return chain ( [
301
- makeMainAsync ( main ) ,
316
+ ...( generateRule ) ? [ generateRule ] : [ ] ,
317
+ makeMainAsync ( main , options ) ,
302
318
adjustSSR ( projectSourceRoot , ssrMappings ) ,
303
- // externalSchematic('ngx-build-plus', 'ng-add', { project: options.project }),
304
319
] ) ;
305
320
306
321
}
@@ -346,6 +361,31 @@ function generateRemoteConfig(workspace: any, projectName: string) {
346
361
return remotes ;
347
362
}
348
363
364
+ function generateRemoteMap ( workspace : any , projectName : string ) {
365
+ const result = { } ;
366
+
367
+ for ( const p in workspace . projects ) {
368
+ const project = workspace . projects [ p ] ;
369
+ const projectType = project . projectType ?? 'application' ;
370
+
371
+ if ( p !== projectName
372
+ && projectType === 'application'
373
+ && project ?. architect ?. serve
374
+ && project ?. architect ?. build ) {
375
+
376
+ const pPort = project . architect . serve . options ?. port ?? 4200 ;
377
+ result [ strings . camelize ( p ) ] = `http://localhost:${ pPort } /remoteEntry.js` ;
378
+
379
+ }
380
+ }
381
+
382
+ if ( Object . keys ( result ) . length === 0 ) {
383
+ result [ "mfe1" ] = `http://localhost:3000/remoteEntry.js` ;
384
+ }
385
+
386
+ return result ;
387
+ }
388
+
349
389
export function generateSsrMappings ( workspace : any , projectName : string ) : string {
350
390
let remotes = '{\n' ;
351
391
0 commit comments