Skip to content

Commit 433f73a

Browse files
authored
Federated Modules: Dynamic Remotes with synchronous imports (#557)
Utilizing plugin from: #566
1 parent c607440 commit 433f73a

File tree

20 files changed

+28026
-0
lines changed

20 files changed

+28026
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Dynamic Remote with Vendor Sharing and Synchronous imports Example
2+
3+
This example demos a basic host application loading remote component and sharing vendor code dynamically between unknown remotes
4+
5+
- `app1` standalone application which exposes `Widget` component.
6+
- `app2` standalone application which exposes `Widget` component that requires
7+
`momentjs`.
8+
9+
# Running Demo
10+
11+
Run `yarn start`. This will build and serve both `app1` and `app2` on ports
12+
`3001` and `3002` respectively.
13+
14+
- [localhost:3001](http://localhost:3001/) (HOST)
15+
- [localhost:3002](http://localhost:3002/) (STANDALONE REMOTE)
16+
<img src="https://ssl.google-analytics.com/collect?v=1&t=event&ec=email&ea=open&t=event&tid=UA-120967034-1&z=1589682154&cid=ae045149-9d17-0367-bbb0-11c41d92b411&dt=ModuleFederationExamples&dp=/email/advanced-api/dynamic-remotes">
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// From: https://github.com/module-federation/module-federation-examples/issues/566
2+
const extractUrlAndGlobal = require('webpack/lib/util/extractUrlAndGlobal');
3+
const { RawSource } = require('webpack-sources');
4+
5+
const PLUGIN_NAME = 'ExternalTemplateRemotesPlugin';
6+
7+
class ExternalTemplateRemotesPlugin {
8+
apply(compiler) {
9+
compiler.hooks.make.tap(PLUGIN_NAME, compilation => {
10+
const scriptExternalModules = [];
11+
12+
compilation.hooks.buildModule.tap(PLUGIN_NAME, module => {
13+
if (module.constructor.name === 'ExternalModule' && module.externalType === 'script') {
14+
scriptExternalModules.push(module);
15+
}
16+
});
17+
18+
compilation.hooks.afterCodeGeneration.tap(PLUGIN_NAME, function() {
19+
scriptExternalModules.map(module => {
20+
const urlTemplate = extractUrlAndGlobal(module.request)[0];
21+
const urlExpression = toExpression(urlTemplate);
22+
const sourceMap = compilation.codeGenerationResults.get(module).sources;
23+
const rawSource = sourceMap.get('javascript');
24+
sourceMap.set(
25+
'javascript',
26+
new RawSource(rawSource.source().replace(`"${urlTemplate}"`, urlExpression))
27+
);
28+
});
29+
});
30+
});
31+
}
32+
}
33+
34+
function toExpression(templateUrl) {
35+
const result = [];
36+
const current = [];
37+
let isExpression = false;
38+
let invalid = false;
39+
for (const c of templateUrl) {
40+
if (c === '[') {
41+
if (isExpression) {
42+
invalid = true;
43+
break;
44+
}
45+
isExpression = true;
46+
if (current.length) {
47+
result.push(`"${current.join('')}"`);
48+
current.length = 0;
49+
}
50+
} else if (c === ']') {
51+
if (!isExpression) {
52+
invalid = true;
53+
break;
54+
}
55+
isExpression = false;
56+
if (current.length) {
57+
result.push(`${current.join('')}`);
58+
current.length = 0;
59+
}
60+
current.length = 0;
61+
} else {
62+
current.push(c);
63+
}
64+
}
65+
if (isExpression || invalid) {
66+
throw new Error(`Invalid template URL "${templateUrl}"`);
67+
}
68+
if (current.length) {
69+
result.push(`"${current.join('')}"`);
70+
}
71+
return result.join(' + ');
72+
}
73+
74+
module.exports = ExternalTemplateRemotesPlugin;

0 commit comments

Comments
 (0)