Skip to content

Commit bf4a63e

Browse files
committed
docs: update tutorials for ng 13
1 parent 6d75921 commit bf4a63e

File tree

3 files changed

+68
-43
lines changed

3 files changed

+68
-43
lines changed

libs/mf-tools/tutorial/index.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
3434
path: 'react',
3535
component: WebComponentWrapper,
3636
data: {
37+
type: 'script',
3738
remoteEntry: 'https://witty-wave-0a695f710.azurestaticapps.net/remoteEntry.js',
3839
remoteName: 'react',
3940
exposedModule: './web-components',
@@ -45,6 +46,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
4546
path: 'angular1',
4647
component: WebComponentWrapper,
4748
data: {
49+
type: 'script',
4850
remoteEntry: 'https://nice-grass-018f7d910.azurestaticapps.net/remoteEntry.js',
4951
remoteName: 'angular1',
5052
exposedModule: './web-components',
@@ -56,6 +58,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
5658
path: 'angular2',
5759
component: WebComponentWrapper,
5860
data: {
61+
type: 'script',
5962
remoteEntry: 'https://gray-pond-030798810.azurestaticapps.net//remoteEntry.js',
6063
remoteName: 'angular2',
6164
exposedModule: './web-components',
@@ -67,6 +70,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
6770
matcher: startsWith('angular3'),
6871
component: WebComponentWrapper,
6972
data: {
73+
type: 'script',
7074
remoteEntry: 'https://gray-river-0b8c23a10.azurestaticapps.net/remoteEntry.js',
7175
remoteName: 'angular3',
7276
exposedModule: './web-components',
@@ -78,6 +82,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
7882
path: 'vue',
7983
component: WebComponentWrapper,
8084
data: {
85+
type: 'script',
8186
remoteEntry: 'https://mango-field-0d0778c10.azurestaticapps.net/remoteEntry.js',
8287
remoteName: 'vue',
8388
exposedModule: './web-components',
@@ -89,6 +94,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
8994
path: 'angularjs',
9095
component: WebComponentWrapper,
9196
data: {
97+
type: 'script',
9298
remoteEntry: 'https://calm-mud-0a3ee4a10.azurestaticapps.net/remoteEntry.js',
9399
remoteName: 'angularjs',
94100
exposedModule: './web-components',
@@ -100,6 +106,7 @@ If you don't want to do the upstream tutorial first, you can use [this example](
100106
matcher: startsWith('angular3'),
101107
component: WebComponentWrapper,
102108
data: {
109+
type: 'script',
103110
remoteEntry: 'https://gray-river-0b8c23a10.azurestaticapps.net/remoteEntry.js',
104111
remoteName: 'angular3',
105112
exposedModule: './web-components',
@@ -116,7 +123,10 @@ If you don't want to do the upstream tutorial first, you can use [this example](
116123
];
117124
```
118125
119-
Hint: Add the missing imports using your IDE's auto import feature.
126+
**Hint:** Add the missing imports using your IDE's auto import feature.
127+
128+
**Remarks:** Please note that we are using ``type: 'script'`` here. This is needed for classic webpack setups as normally used in the Vue and React world as well as for Angular before version 13. Beginning with version 13, the CLI emits EcmaScript module instead of "plain old" JavaScript files. Hence, when loading a remote compiled with Angular 13 or higher, you need to set `type` to ``module``. In our case, however, the remotes we find at the shown URLs in the cloud are Angular 12-based, hence we need ``type: 'script'``.
129+
120130
121131
4. Open your shell's ``app.component.html`` and add the following links:
122132

libs/mf/tutorial/tutorial.md

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ This tutorial shows how to use Webpack Module Federation together with the Angul
66
![Microfrontend Loaded into Shell](https://github.com/angular-architects/module-federation-plugin/raw/main/libs/mf/tutorial/result.png)
77

88

9+
**Important**: This tutorial is written for Angular and **Angular CLI 13.1** and higher. To find out about the small differences for lower versions of Angular and for the migration from such a lower version, please have a look to our [migration guide](https://github.com/angular-architects/module-federation-plugin/blob/main/migration-guide.md).
10+
11+
912
## Part 1: Clone and Inspect the Starterkit
1013

1114
In this part you will clone the starterkit and inspect its projects.
@@ -46,7 +49,9 @@ Now, let's activate and configure module federation:
4649
4750
This activates module federation, assigns a port for ng serve, and generates the skeleton of a module federation configuration.
4851
49-
2. Switch into the project ``mfe1`` and open the generated configuration file ``projects\mfe1\webpack.config.js``. It contains the module federation configuration for ``mfe1``. Adjust it as follows:
52+
2. Open the ``tsconfig.json`` in your workspace's root and ensure your self that the ``target`` property points to ``ES2020`` or higher. This is a prerequisite for using Module Federation with Angular 13.1 or higher.
53+
54+
3. Switch into the project ``mfe1`` and open the generated configuration file ``projects\mfe1\webpack.config.js``. It contains the module federation configuration for ``mfe1``. Adjust it as follows:
5055
5156
```javascript
5257
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
@@ -57,6 +62,8 @@ Now, let's activate and configure module federation:
5762
[...],
5863
plugins: [
5964
new ModuleFederationPlugin({
65+
66+
library: { type: "module" },
6067
6168
// For remotes (please adjust)
6269
name: "mfe1",
@@ -65,19 +72,20 @@ Now, let's activate and configure module federation:
6572
// Update this:
6673
'./Module': './projects/mfe1/src/app/flights/flights.module.ts',
6774
},
68-
shared: {
69-
"@angular/core": { singleton: true, strictVersion: true },
70-
"@angular/common": { singleton: true, strictVersion: true },
71-
"@angular/router": { singleton: true, strictVersion: true },
75+
shared: share({
76+
"@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
77+
"@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
78+
"@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
79+
"@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
7280
[...]
73-
}
81+
})
7482
}),
7583
[...]
7684
],
7785
};
7886
```
7987
80-
This exposes the ``FlightsModule`` under the Name ``./Module.``. Hence, the shell can use this path to load it.
88+
This exposes the ``FlightsModule`` under the Name ``./Module``. Hence, the shell can use this path to load it.
8189
8290
3. Switch into the ``shell`` project and open the file ``projects\shell\webpack.config.js``. Adjust it as follows:
8391
@@ -90,17 +98,20 @@ Now, let's activate and configure module federation:
9098
[...],
9199
plugins: [
92100
new ModuleFederationPlugin({
101+
102+
library: { type: "module" },
93103
94104
// Make sure to use port 3000
95105
remotes: {
96-
'mfe1': "mfe1@http://localhost:3000/remoteEntry.js"
106+
'mfe1': "http://localhost:3000/remoteEntry.js"
97107
},
98-
shared: {
99-
"@angular/core": { singleton: true, strictVersion: true },
100-
"@angular/common": { singleton: true, strictVersion: true },
101-
"@angular/router": { singleton: true, strictVersion: true },
108+
shared: share({
109+
"@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
110+
"@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
111+
"@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
112+
"@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
102113
[...]
103-
}
114+
})
104115
}),
105116
[...]
106117
],
@@ -159,11 +170,11 @@ Now, let's remove the need for registering the micro frontends upfront with with
159170
```javascript
160171
remotes: {
161172
// Remove this line or comment it out:
162-
// "mfe1": "mfe1@http://localhost:3000/remoteEntry.js",
173+
// "mfe1": "http://localhost:3000/remoteEntry.js",
163174
},
164175
```
165176
166-
1. Open the file ``app.routes.ts`` and use the function ``loadRemoteModule`` instead of the dynamic ``import`` statement:
177+
2. Open the file ``app.routes.ts`` and use the function ``loadRemoteModule`` instead of the dynamic ``import`` statement:
167178
168179
```typescript
169180
import { loadRemoteModule } from '@angular-architects/module-federation';
@@ -175,8 +186,8 @@ Now, let's remove the need for registering the micro frontends upfront with with
175186
path: 'flights',
176187
loadChildren: () =>
177188
loadRemoteModule({
189+
type: 'module',
178190
remoteEntry: 'http://localhost:3000/remoteEntry.js',
179-
remoteName: 'mfe1',
180191
exposedModule: './Module'
181192
})
182193
.then(m => m.FlightsModule)
@@ -185,9 +196,11 @@ Now, let's remove the need for registering the micro frontends upfront with with
185196
]
186197
```
187198
188-
2. Restart both, the ``shell`` and the micro frontend (``mfe1``).
199+
*Remarks:* ``type: 'module'`` is needed for Angular 13.1 or higher as beginning with version 13 the CLI emits EcmaScript modules instead of "plain old" JavaScript files.
200+
201+
3. Restart both, the ``shell`` and the micro frontend (``mfe1``).
189202
190-
3. The shell should still be able to load the micro frontend. However, now it's loaded dynamically.
203+
4. The shell should still be able to load the micro frontend. However, now it's loaded dynamically.
191204
192205
This was quite easy, wasn't it? However, we can improve this solution a bit. Ideally, we load the remote entry upfront before Angular bootstraps. In this early phase, Module Federation tries to determine the highest compatible versions of all dependencies. Let's assume, the shell provides version 1.0.0 of a dependency (specifying ^1.0.0 in its ``package.json``) and the micro frontend uses version 1.1.0 (specifying ^1.1.0 in its ``package.json``). In this case, they would go with version 1.1.0. However, this is only possible if the remote's entry is loaded upfront.
193206
@@ -197,34 +210,12 @@ This was quite easy, wasn't it? However, we can improve this solution a bit. Ide
197210
import { loadRemoteEntry } from '@angular-architects/module-federation';
198211
199212
Promise.all([
200-
loadRemoteEntry('http://localhost:3000/remoteEntry.js', 'mfe1')
213+
loadRemoteEntry({type: 'module', remoteEntry: 'http://localhost:3000/remoteEntry.js')
201214
])
202215
.catch(err => console.error('Error loading remote entries', err))
203216
.then(() => import('./bootstrap'))
204217
.catch(err => console.error(err));
205218
```
206-
207-
1. Open the file ``app.routes.ts`` and comment out (or remove) the property ``remoteEntry``:
208-
209-
```typescript
210-
import { loadRemoteModule } from '@angular-architects/module-federation';
211-
212-
[...]
213-
const routes: Routes = [
214-
[...]
215-
{
216-
path: 'flights',
217-
loadChildren: () =>
218-
loadRemoteModule({
219-
// remoteEntry: 'http://localhost:3000/remoteEntry.js',
220-
remoteName: 'mfe1',
221-
exposedModule: './Module'
222-
})
223-
.then(m => m.FlightsModule)
224-
},
225-
[...]
226-
]
227-
```
228219
229220
2. Restart both, the ``shell`` and the micro frontend (``mfe1``).
230221

migration-guide.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ In the following example, ``mfe1`` is loaded as a module while ``mfe2`` is loade
145145
```javascript
146146
remotes: {
147147
// Load as module:
148-
mfe1": "mfe2@http://localhost:3000/remoteEntry.js",
148+
mfe1": "http://localhost:3000/remoteEntry.js",
149149

150150
// Load as script:
151151
mfe2": "script mfe2@http://localhost:3000/remoteEntry.js",
@@ -167,6 +167,30 @@ module.exports = {
167167
}
168168
```
169169

170+
Also, don't use the settings introduced above for Angular 13.1+:
171+
172+
173+
```diff
174+
[...]
175+
module.exports = {
176+
[...]
177+
- experiments: {
178+
- outputModule: true
179+
- },
180+
plugins: [
181+
new ModuleFederationPlugin({
182+
- library: { type: "module" },
183+
184+
[...]
185+
})
186+
]
187+
};
188+
```
189+
190+
## SSR
191+
192+
We have a sound solution including Schematics for SSR in Angular 12. However, because of a bug in Angular Universal 13, SSR is currently not supported for Angular 13. However, we are monitoring this situation and providing a solution as soon as these issues are fixed.
193+
170194
## Example
171195

172196
see https://github.com/manfredsteyer/mf-angular-13

0 commit comments

Comments
 (0)