Skip to content

Commit 776b847

Browse files
committed
Update example utilizing plugin from:
#566
1 parent e6dc2f7 commit 776b847

File tree

20 files changed

+295
-283
lines changed

20 files changed

+295
-283
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;

advanced-api/dynamic-remotes-synchronous-imports/app3/package-lock.json renamed to advanced-api/dynamic-remotes-synchronous-imports/app1/package-lock.json

Lines changed: 3 additions & 102 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

advanced-api/dynamic-remotes-synchronous-imports/app3/package.json renamed to advanced-api/dynamic-remotes-synchronous-imports/app1/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@dynamic-remotes/app3",
2+
"name": "@dynamic-remotes/app2",
33
"version": "0.0.0",
44
"private": true,
55
"devDependencies": {
@@ -15,14 +15,12 @@
1515
"scripts": {
1616
"start": "webpack-cli serve",
1717
"build": "webpack --mode production",
18-
"serve": "serve dist -p 3003",
18+
"serve": "serve dist -p 3002",
1919
"clean": "rm -rf dist"
2020
},
2121
"dependencies": {
2222
"moment": "^2.24.0",
2323
"react": "^16.13.0",
24-
"react-dom": "^16.13.0",
25-
"react-redux": "^7.2.0",
26-
"redux": "^4.0.5"
24+
"react-dom": "^16.13.0"
2725
}
2826
}
File renamed without changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Widget from "./Widget";
2+
import React, { Suspense } from "react";
3+
import WidgetRemote from "app2/Widget";
4+
5+
const App = () => (
6+
<div>
7+
<h1>Dynamic System Host</h1>
8+
<h2>App 1</h2>
9+
<Widget />
10+
<Suspense fallback="Loading widget">
11+
<WidgetRemote />
12+
</Suspense>
13+
</div>
14+
);
15+
16+
export default App;

advanced-api/dynamic-remotes-synchronous-imports/app3/src/Widget.js renamed to advanced-api/dynamic-remotes-synchronous-imports/app1/src/Widget.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ export default function Widget() {
77
style={{
88
borderRadius: "4px",
99
padding: "2em",
10-
backgroundColor: "purple",
10+
backgroundColor: "red",
1111
color: "white",
1212
}}
1313
>
14-
<h2>App 3 Widget</h2>
14+
<h2>App 1 Widget</h2>
1515
<p>
16-
Using <strong>momentjs</strong> to format the date
16+
Moment shouldn't download twice, the host has no moment.js <br />{" "}
17+
{moment().format("MMMM Do YYYY, h:mm:ss a")}
1718
</p>
18-
<p>{moment().format("MMMM Do YYYY, h:mm:ss a")}</p>
1919
</div>
2020
);
2121
}
File renamed without changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { app2Module } from "../../moduleConfig";
2+
3+
window[app2Module.urlGlobalVariable] = app2Module.url;
4+
5+
import("./bootstrap");

0 commit comments

Comments
 (0)