Skip to content

Commit 39ea577

Browse files
committed
add rspack to sample app
1 parent b09f89b commit 39ea577

3 files changed

Lines changed: 2177 additions & 25 deletions

File tree

packages/sample-app/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
"clean": "rm -rf dist",
88
"build": "yarn clean && yarn webpack",
99
"build-prod": "yarn clean && NODE_ENV=production yarn webpack",
10+
"build-rspack": "yarn clean && NODE_ENV=production yarn rspack",
1011
"analyze": "yarn clean && NODE_ENV=production ANALYZE_BUNDLES=true yarn webpack",
1112
"lint": "yarn run -T eslint $INIT_CWD",
1213
"webpack": "node -r ts-node/register ./node_modules/.bin/webpack",
14+
"rspack": "node -r ts-node/register ./node_modules/.bin/rspack",
1315
"http-server": "http-server dist -p 9000 -c-1"
1416
},
1517
"devDependencies": {
@@ -20,6 +22,8 @@
2022
"@patternfly/react-styles": "^6.4.0",
2123
"@patternfly/react-table": "^6.4.0",
2224
"@patternfly/react-tokens": "^6.4.0",
25+
"@rspack/cli": "^1.6.7",
26+
"@rspack/core": "^1.6.7",
2327
"@types/webpack-bundle-analyzer": "~4.7.0",
2428
"copy-webpack-plugin": "^13.0.1",
2529
"css-loader": "^7.1.2",
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import path from 'path';
2+
import type { WebpackSharedObject } from '@openshift/dynamic-plugin-sdk-webpack';
3+
import type { Configuration, WebpackPluginInstance } from '@rspack/core';
4+
import {
5+
CopyRspackPlugin,
6+
EnvironmentPlugin,
7+
CssExtractRspackPlugin,
8+
container,
9+
LightningCssMinimizerRspackPlugin,
10+
} from '@rspack/core';
11+
import HTMLPlugin from 'html-webpack-plugin';
12+
import { escapeRegExp } from 'lodash';
13+
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
14+
15+
const isProd = process.env.NODE_ENV === 'production';
16+
const analyzeBundles = process.env.ANALYZE_BUNDLES === 'true';
17+
18+
const pathTo = (relativePath: string) => path.resolve(__dirname, relativePath);
19+
20+
export const getNodeModulesTest = (modulePaths: string[]) =>
21+
new RegExp(`/node_modules/(${modulePaths.map(escapeRegExp).join('|')})/`);
22+
23+
/**
24+
* Shared modules provided by the host application to its plugins.
25+
*
26+
* `eager: true` means include the module in the application's initial chunk.
27+
* We generally want this for all shared modules provided by the application.
28+
*
29+
* `singleton: true` means allow only a single version of the module to be loaded.
30+
* We want this for libraries which are meant to be used as singletons, including
31+
* the ones which rely on global state.
32+
*
33+
* `requiredVersion` can be used to manually specify the required module version
34+
* as a semver range. We're using it here because the sample application's package
35+
* manifest refers to plugin SDK packages via the `portal:` protocol. You normally
36+
* don't need this in real world applications.
37+
*
38+
* @see https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints
39+
*/
40+
const appSharedModules: WebpackSharedObject = {
41+
'@openshift/dynamic-plugin-sdk': { eager: true, singleton: true, requiredVersion: false },
42+
'@patternfly/react-core': { eager: true },
43+
'@patternfly/react-table': { eager: true },
44+
react: { eager: true, singleton: true, requiredVersion: '^17.0.0' },
45+
'react-dom': { eager: true, singleton: true, requiredVersion: '^17.0.0' },
46+
};
47+
48+
const plugins: WebpackPluginInstance[] = [
49+
new EnvironmentPlugin({
50+
NODE_ENV: 'development',
51+
}),
52+
new container.ModuleFederationPluginV1({
53+
name: 'sample_app',
54+
shared: appSharedModules,
55+
}),
56+
new HTMLPlugin({
57+
template: pathTo('src/app-index.html.ejs'),
58+
title: 'Sample Plugin Host Application',
59+
chunks: ['app'],
60+
}),
61+
new CopyRspackPlugin({
62+
patterns: [{ from: 'src/images/favicon.png', to: 'images' }],
63+
}),
64+
];
65+
66+
const config: Configuration = {
67+
mode: isProd ? 'production' : 'development',
68+
entry: {
69+
app: './src/app.tsx',
70+
},
71+
output: {
72+
path: pathTo('dist'),
73+
filename: isProd ? '[name].[contenthash].bundle.js' : '[name].bundle.js',
74+
chunkFilename: isProd ? 'chunks/[id].[chunkhash].min.js' : 'chunks/[id].js',
75+
},
76+
resolve: {
77+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
78+
},
79+
module: {
80+
rules: [
81+
{
82+
test: /\.(jsx?|tsx?)$/,
83+
exclude: /\/node_modules\//,
84+
use: [
85+
{
86+
loader: 'ts-loader',
87+
options: {
88+
configFile: pathTo('tsconfig.json'),
89+
},
90+
},
91+
],
92+
},
93+
{
94+
test: /\.(svg|ttf|eot|otf|woff2?)$/,
95+
include: getNodeModulesTest([
96+
'@patternfly/react-core/dist/styles/assets/fonts',
97+
'@patternfly/react-core/dist/styles/assets/pficon',
98+
]),
99+
type: 'asset',
100+
parser: {
101+
dataUrlCondition: {
102+
maxSize: 50 * 1024, // Files smaller than 50 kB will be inlined as data URLs
103+
},
104+
},
105+
generator: {
106+
filename: isProd ? 'fonts/[contenthash][ext]' : 'fonts/[name][ext]',
107+
},
108+
},
109+
{
110+
test: /\.(svg|png|jpg|jpeg|gif)$/,
111+
include: [
112+
getNodeModulesTest([
113+
'@patternfly/react-core/dist/styles/assets/images',
114+
'@patternfly/react-styles/css/assets/images',
115+
]),
116+
pathTo('src'),
117+
],
118+
type: 'asset',
119+
parser: {
120+
dataUrlCondition: {
121+
maxSize: 50 * 1024, // Files smaller than 50 kB will be inlined as data URLs
122+
},
123+
},
124+
generator: {
125+
filename: isProd ? 'images/[contenthash][ext]' : 'images/[name][ext]',
126+
},
127+
},
128+
{
129+
test: /\.(css)$/,
130+
include: [
131+
getNodeModulesTest([
132+
'@patternfly/react-core/dist/styles',
133+
'@patternfly/react-styles/css',
134+
]),
135+
pathTo('src'),
136+
],
137+
use: [isProd ? CssExtractRspackPlugin.loader : 'style-loader', 'css-loader'],
138+
},
139+
],
140+
},
141+
plugins,
142+
devtool: isProd ? 'source-map' : 'cheap-source-map',
143+
optimization: {
144+
minimize: isProd,
145+
minimizer: [
146+
'...', // The '...' string represents the webpack default TerserPlugin instance
147+
new LightningCssMinimizerRspackPlugin(),
148+
],
149+
splitChunks: {
150+
cacheGroups: {
151+
vendorReact: {
152+
test: getNodeModulesTest(['react', 'react-dom']),
153+
name: 'vendor-react',
154+
chunks: 'all',
155+
},
156+
vendorPatternFly: {
157+
test: getNodeModulesTest([
158+
'@patternfly/react-core',
159+
'@patternfly/react-icons',
160+
'@patternfly/react-styles',
161+
'@patternfly/react-table',
162+
'@patternfly/react-tokens',
163+
]),
164+
name: 'vendor-patternfly',
165+
chunks: 'all',
166+
},
167+
},
168+
},
169+
},
170+
};
171+
172+
if (isProd) {
173+
plugins.push(
174+
new CssExtractRspackPlugin({
175+
filename: '[name].[contenthash].css',
176+
chunkFilename: '[id].[chunkhash].css',
177+
}),
178+
);
179+
}
180+
181+
if (analyzeBundles) {
182+
plugins.push(
183+
new BundleAnalyzerPlugin({
184+
analyzerMode: 'static',
185+
reportFilename: pathTo('dist/bundle-report.html'),
186+
openAnalyzer: false,
187+
}),
188+
);
189+
}
190+
191+
export default config;

0 commit comments

Comments
 (0)