Skip to content

Commit 836e5ff

Browse files
jmvtrinidadScriptedAlchemyclaude
authored
error boundary (#4281)
* error boundary * update to MF enhanced to 0.6.8 * Remove medusa examples from repository - Removed medusa-delegate-example directory - Removed medusa-example directory - Removed medusa-nx-native-federation-example directory - Removed modernjs-medusa directory - Updated package.json workspaces to remove medusa references 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: update dependencies via repotools - Updated module federation packages across all examples - Upgraded @rspack/core from 0.7.5/1.0.8 to 1.4.11 - Ran pnpm install to sync lockfile 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: locks --------- Co-authored-by: Zack Jackson <25274700+ScriptedAlchemy@users.noreply.github.com> Co-authored-by: ScriptedAlchemy <zackaryjackson@bytedance.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5ace25f commit 836e5ff

21 files changed

+898
-32
lines changed

error-boundary/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Error Boundary
2+
3+
This demo boots only app1, app2 remains offline.
4+
Loading localhost:3001 will render a error message from the runtime plugin as a react module when the container if offline.

error-boundary/app1/package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "error-boundary_app1",
3+
"version": "0.0.0",
4+
"devDependencies": {
5+
"@babel/core": "7.24.7",
6+
"@babel/preset-react": "7.24.7",
7+
"babel-loader": "9.1.3",
8+
"html-webpack-plugin": "5.6.0",
9+
"serve": "14.2.3",
10+
"@rspack/core": "1.4.11",
11+
"@rspack/cli": "1.4.11",
12+
"@rspack/dev-server": "1.1.3",
13+
"webpack": "5.101.0",
14+
"webpack-cli": "5.1.4",
15+
"webpack-dev-server": "5.1.0",
16+
"@module-federation/runtime": "0.17.1",
17+
"@module-federation/enhanced": "0.17.1"
18+
},
19+
"scripts": {
20+
"start": "rspack serve -c rspack.config.js",
21+
"build": "rspack build --mode production -c rspack.config.js",
22+
"legacy:start": "webpack serve --config webpack.config.js",
23+
"legacy:build": "webpack --config webpack.config.js --mode production",
24+
"serve": "serve dist -p 3001",
25+
"clean": "rm -rf dist"
26+
},
27+
"dependencies": {
28+
"react": "^17.0.2",
29+
"react-dom": "^17.0.2",
30+
"lodash": "^4.17.21"
31+
}
32+
}

error-boundary/app1/public/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head> </head>
4+
<body>
5+
<div id="root"></div>
6+
</body>
7+
</html>

error-boundary/app1/rspack.config.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
const {
2+
HtmlRspackPlugin,
3+
container: { ModuleFederationPlugin },
4+
} = require('@rspack/core');
5+
const path = require('path');
6+
7+
// adds all your dependencies as shared modules
8+
// version is inferred from package.json in the dependencies
9+
// requiredVersion is used from your package.json
10+
// dependencies will automatically use the highest available package
11+
// in the federated app, based on version requirement in package.json
12+
// multiple different versions might coexist in the federated app
13+
// Note that this will not affect nested paths like "lodash/pluck"
14+
// Note that this will disable some optimization on these packages
15+
// with might lead the bundle size problems
16+
const deps = require('./package.json').dependencies;
17+
18+
module.exports = {
19+
entry: './src/index',
20+
mode: 'development',
21+
devServer: {
22+
static: {
23+
directory: path.join(__dirname, 'dist'),
24+
},
25+
hot: true,
26+
port: 3001,
27+
liveReload: true,
28+
},
29+
target: 'web',
30+
output: {
31+
publicPath: 'auto',
32+
},
33+
module: {
34+
rules: [
35+
{
36+
test: /\.js$/,
37+
include: path.resolve(__dirname, 'src'),
38+
use: {
39+
loader: 'builtin:swc-loader',
40+
options: {
41+
jsc: {
42+
parser: {
43+
syntax: 'ecmascript',
44+
jsx: true,
45+
},
46+
transform: {
47+
react: {
48+
runtime: 'automatic',
49+
},
50+
},
51+
},
52+
},
53+
},
54+
},
55+
{
56+
test: /\.ts$/,
57+
use: {
58+
loader: 'builtin:swc-loader',
59+
options: {
60+
jsc: {
61+
parser: {
62+
syntax: 'typescript',
63+
jsx: true,
64+
},
65+
transform: {
66+
react: {
67+
runtime: 'automatic',
68+
},
69+
},
70+
},
71+
},
72+
},
73+
},
74+
],
75+
},
76+
plugins: [
77+
new ModuleFederationPlugin({
78+
name: 'app1',
79+
filename: 'remoteEntry.js',
80+
remotes: {
81+
app2: 'app2@http://localhost:3002/remoteEntry.js',
82+
},
83+
exposes: {
84+
'./Button': './src/Button',
85+
},
86+
shared: {
87+
...deps,
88+
react: {
89+
singleton: true,
90+
},
91+
'react-dom': {
92+
singleton: true,
93+
},
94+
lodash: {},
95+
},
96+
}),
97+
new HtmlRspackPlugin({
98+
template: './public/index.html',
99+
}),
100+
],
101+
};

error-boundary/app1/src/App.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import lodash from 'lodash';
4+
5+
import LocalButton from './Button';
6+
const RemoteButtonLazy = React.lazy(() => import('app2/Button'));
7+
8+
// A function to generate a color from a string
9+
const getColorFromString = str => {
10+
// Prime numbers used for generating a hash
11+
let primes = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23];
12+
let hash = 0;
13+
14+
// Generate a hash from the string
15+
for (let i = 0; i < str.length; i++) {
16+
hash += str.charCodeAt(i) * primes[i % primes.length];
17+
}
18+
19+
// Convert the hash to a color
20+
let color = '#';
21+
for (let i = 0; i < 3; i++) {
22+
const value = (hash >> (i * 8)) & 0xff;
23+
color += ('00' + value.toString(16)).substr(-2);
24+
}
25+
26+
return color;
27+
};
28+
29+
// The main App component
30+
const App = () => (
31+
<div>
32+
<h1>Offline Remote</h1>
33+
<h2>Remotes currently in use</h2>
34+
{/* Display the names of the remotes loaded by the CustomPlugin */}
35+
{__FEDERATION__.__INSTANCES__.map(inst => (
36+
<span
37+
style={{
38+
padding: 10,
39+
color: '#fff',
40+
background: getColorFromString(inst.name.split().reverse().join('')),
41+
}}
42+
key={inst.name}
43+
>
44+
{inst.name}
45+
</span>
46+
))}
47+
<p>
48+
Click The second button. This will cause the <i>pick-remote.ts</i> to load remoteEntry urls
49+
from a mock api call.
50+
</p>
51+
{/* LocalButton is a button component from the local app */}
52+
<LocalButton />
53+
{/* RemoteButton is a button component loaded from a remote app */}
54+
<ErrorBoundary>
55+
<React.Suspense fallback="Loading Button">
56+
<RemoteButtonLazy />
57+
</React.Suspense>
58+
</ErrorBoundary>
59+
{/* The Reset button clears the 'button' item from localStorage */}
60+
<button
61+
onClick={() => {
62+
localStorage.clear('button');
63+
window.location.reload();
64+
}}
65+
>
66+
Reset{' '}
67+
</button>
68+
</div>
69+
);
70+
71+
export default App;
72+
73+
class ErrorBoundary extends React.Component {
74+
state = {
75+
hasError: false,
76+
};
77+
78+
componentDidCatch(error, errorInfo) {
79+
console.error(error, errorInfo);
80+
this.setState({ hasError: true });
81+
}
82+
83+
render() {
84+
const { children } = this.props;
85+
if (this.state.hasError) {
86+
return (
87+
<div>
88+
<h1>Something went wrong</h1>
89+
<p>Try refreshing the page.</p>
90+
</div>
91+
);
92+
}
93+
return children;
94+
}
95+
}

error-boundary/app1/src/Button.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
3+
const style = {
4+
background: '#800',
5+
color: '#fff',
6+
padding: 12,
7+
};
8+
9+
const Button = () => <button style={style}>App 1 Button</button>;
10+
11+
export default Button;

error-boundary/app1/src/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import App from './App';
2+
import React from 'react';
3+
import ReactDOM from 'react-dom';
4+
5+
ReactDOM.render(<App />, document.getElementById('root'));

error-boundary/app1/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import('./bootstrap');

error-boundary/app1/webpack.config.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const HtmlWebpackPlugin = require('html-webpack-plugin');
2+
const { ModuleFederationPlugin } = require('@module-federation/enhanced');
3+
const path = require('path');
4+
5+
// adds all your dependencies as shared modules
6+
// version is inferred from package.json in the dependencies
7+
// requiredVersion is used from your package.json
8+
// dependencies will automatically use the highest available package
9+
// in the federated app, based on version requirement in package.json
10+
// multiple different versions might coexist in the federated app
11+
// Note that this will not affect nested paths like "lodash/pluck"
12+
// Note that this will disable some optimization on these packages
13+
// with might lead the bundle size problems
14+
const deps = require('./package.json').dependencies;
15+
16+
module.exports = {
17+
entry: './src/index',
18+
cache: false,
19+
mode: 'development',
20+
devServer: {
21+
static: {
22+
directory: path.join(__dirname, 'dist'),
23+
},
24+
port: 3001,
25+
},
26+
target: 'web',
27+
output: {
28+
publicPath: 'auto',
29+
},
30+
module: {
31+
rules: [
32+
{
33+
test: /\.jsx?$/,
34+
loader: 'babel-loader',
35+
exclude: /node_modules/,
36+
options: {
37+
presets: ['@babel/preset-react'],
38+
},
39+
},
40+
],
41+
},
42+
plugins: [
43+
new ModuleFederationPlugin({
44+
name: 'app1',
45+
filename: 'remoteEntry.js',
46+
remotes: {
47+
app2: 'app2@http://localhost:3002/remoteEntry.js',
48+
},
49+
exposes: {
50+
'./Button': './src/Button',
51+
},
52+
shared: {
53+
...deps,
54+
react: {
55+
singleton: true,
56+
},
57+
'react-dom': {
58+
singleton: true,
59+
},
60+
},
61+
}),
62+
new HtmlWebpackPlugin({
63+
template: './public/index.html',
64+
}),
65+
],
66+
};

error-boundary/app2/package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "error-boundary_app2",
3+
"version": "0.0.0",
4+
"devDependencies": {
5+
"@babel/core": "7.24.7",
6+
"@babel/preset-react": "7.24.7",
7+
"babel-loader": "9.1.3",
8+
"html-webpack-plugin": "5.6.0",
9+
"serve": "14.2.3",
10+
"@rspack/core": "1.4.11",
11+
"@rspack/cli": "1.4.11",
12+
"@rspack/dev-server": "1.1.3",
13+
"webpack": "5.101.0",
14+
"webpack-cli": "5.1.4",
15+
"webpack-dev-server": "5.0.4",
16+
"@module-federation/runtime": "0.17.1",
17+
"@module-federation/enhanced": "0.17.1"
18+
},
19+
"scripts": {
20+
"start": "rspack serve -c rspack.config.js",
21+
"build": "rspack build --mode production -c rspack.config.js",
22+
"legacy:start": "webpack serve --config webpack.config.js",
23+
"legacy:build": "webpack --config webpack.config.js --mode production",
24+
"serve": "serve dist -p 3002",
25+
"clean": "rm -rf dist"
26+
},
27+
"dependencies": {
28+
"react": "^16.13.0",
29+
"react-dom": "^16.13.0",
30+
"lodash": "^3.10.1"
31+
}
32+
}

0 commit comments

Comments
 (0)