diff --git a/.github/workflows/reusable-build-test.yml b/.github/workflows/reusable-build-test.yml
index 653b70db4e73..dd71aee68af9 100644
--- a/.github/workflows/reusable-build-test.yml
+++ b/.github/workflows/reusable-build-test.yml
@@ -16,7 +16,7 @@ on:
jobs:
e2e:
name: E2E Testing
- if: inputs.target == 'x86_64-unknown-linux-gnu'
+ if: inputs.target == 'x86_64-unknown-linux-gnu' || inputs.target == 'wasm32-wasip1-threads'
runs-on: ${{ fromJSON(inputs.runner) }}
defaults:
run:
@@ -51,6 +51,7 @@ jobs:
- name: Run e2e
uses: ./.github/actions/docker/run
+ if: inputs.target == 'x86_64-unknown-linux-gnu'
with:
# Jammy uses ubuntu 22.04
# If this is to change, make sure to upgrade the ubuntu version in GitHub Actions
@@ -63,6 +64,22 @@ jobs:
pnpm run build:js
pnpm run test:e2e
+ - name: Run e2e for @rspack/browser
+ uses: ./.github/actions/docker/run
+ if: inputs.target == 'wasm32-wasip1-threads'
+ with:
+ # Jammy uses ubuntu 22.04
+ # If this is to change, make sure to upgrade the ubuntu version in GitHub Actions
+ image: mcr.microsoft.com/playwright:v1.57.0-jammy
+ # .cache is required by download artifact, and mount in ./.github/actions/docker/run
+ # .tool_cache is required by pnpm
+ options: -v ${{ runner.tool_cache }}:${{runner.tool_cache}}
+ script: |
+ export PATH=${{ steps.calculate-node-bin-path.outputs.path }}:$PATH
+ export WASM=1
+ pnpm run build:js
+ pnpm run test:e2e
+
test:
runs-on: ${{ fromJSON(inputs.runner) }}
timeout-minutes: 60
diff --git a/packages/rspack/rslib.browser.config.mts b/packages/rspack/rslib.browser.config.mts
index 2d1a16262fd5..0555f966f887 100644
--- a/packages/rspack/rslib.browser.config.mts
+++ b/packages/rspack/rslib.browser.config.mts
@@ -23,7 +23,7 @@ export default defineConfig({
},
},
{
- format: 'esm',
+ format: 'iife',
syntax: 'es2021',
dts: false,
autoExtension: false,
@@ -109,6 +109,10 @@ export default defineConfig({
/src[/\\]loader-runner[/\\]service\.ts/,
path.resolve('./src/browser/service.ts'),
),
+ new rspack.NormalModuleReplacementPlugin(
+ /src[/\\]builtin-plugin[/\\]lazy-compilation[/\\]middleware\.ts/,
+ path.resolve('./src/browser/middleware.ts'),
+ ),
);
},
},
diff --git a/packages/rspack/src/browser/middleware.ts b/packages/rspack/src/browser/middleware.ts
new file mode 100644
index 000000000000..3d66bf2e1d03
--- /dev/null
+++ b/packages/rspack/src/browser/middleware.ts
@@ -0,0 +1,3 @@
+export const lazyCompilationMiddleware = () => {
+ throw new Error('lazy compilation middleware is not supported in browser');
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 97be27569e2b..ba5e48313f72 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -648,6 +648,9 @@ importers:
'@playwright/test':
specifier: 1.57.0
version: 1.57.0
+ '@rspack/browser':
+ specifier: workspace:*
+ version: link:../../packages/rspack-browser
'@rspack/core':
specifier: workspace:*
version: link:../../packages/rspack
diff --git a/tests/e2e/browser-cases/basic-react/index.test.ts b/tests/e2e/browser-cases/basic-react/index.test.ts
new file mode 100644
index 000000000000..3f3283034ae0
--- /dev/null
+++ b/tests/e2e/browser-cases/basic-react/index.test.ts
@@ -0,0 +1,13 @@
+import { test, expect } from '@/fixtures';
+
+test('@rspack/browser should bundle react app successfully', async ({
+ page,
+}) => {
+ // There should be a long bundle result
+ await expect
+ .poll(async () => {
+ const text = await page.locator('#output').innerText();
+ return text.length;
+ })
+ .toBeGreaterThan(500);
+});
diff --git a/tests/e2e/browser-cases/basic-react/rspack.config.js b/tests/e2e/browser-cases/basic-react/rspack.config.js
new file mode 100644
index 000000000000..0be1285f81d4
--- /dev/null
+++ b/tests/e2e/browser-cases/basic-react/rspack.config.js
@@ -0,0 +1,25 @@
+const rspack = require('@rspack/core');
+
+/** @type {import("@rspack/core").Configuration} */
+module.exports = {
+ entry: './src/index.js',
+ context: __dirname,
+ mode: 'development',
+ plugins: [new rspack.HtmlRspackPlugin()],
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: [/node_modules/],
+ include: [/src/],
+ loader: 'builtin:swc-loader',
+ },
+ ],
+ },
+ devServer: {
+ headers: {
+ 'Cross-Origin-Opener-Policy': 'same-origin',
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
+ },
+ },
+};
diff --git a/tests/e2e/browser-cases/basic-react/src/files.js b/tests/e2e/browser-cases/basic-react/src/files.js
new file mode 100644
index 000000000000..71aaffcdec2f
--- /dev/null
+++ b/tests/e2e/browser-cases/basic-react/src/files.js
@@ -0,0 +1,213 @@
+import { BrowserHttpImportEsmPlugin } from '@rspack/browser';
+
+export const files = {
+ './src/assets/react.svg': ``,
+ './src/main.jsx': `import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+import "./index.css";
+
+ReactDOM.createRoot(document.getElementById("root")).render(
+
+ Edit src/App.jsx and save to test HMR
+
+ Click on the Rspack and React logos to learn more +
+