From f2ee106b5251c7a6a5eb5829d30a45783df2a2e0 Mon Sep 17 00:00:00 2001
From: Qingyu Wang <40660121+colinaaa@users.noreply.github.com>
Date: Wed, 26 Mar 2025 22:48:59 +0800
Subject: [PATCH 1/2] fix(rspeedy/core): chunk loading on Web platform
---
.changeset/shy-pears-serve.md | 5 ++
.../core/src/plugins/chunkLoading.plugin.ts | 33 ++++++---
.../rspeedy/core/src/plugins/target.plugin.ts | 13 +++-
packages/rspeedy/core/src/utils/is-lynx.ts | 11 +++
packages/rspeedy/core/src/utils/is-web.ts | 11 +++
.../test/plugins/chunkLoading.plugin.test.ts | 67 +++++++++++++++++++
.../core/test/plugins/target.plugin.test.ts | 26 +++++++
7 files changed, 155 insertions(+), 11 deletions(-)
create mode 100644 .changeset/shy-pears-serve.md
create mode 100644 packages/rspeedy/core/src/utils/is-lynx.ts
create mode 100644 packages/rspeedy/core/src/utils/is-web.ts
diff --git a/.changeset/shy-pears-serve.md b/.changeset/shy-pears-serve.md
new file mode 100644
index 0000000000..924d078361
--- /dev/null
+++ b/.changeset/shy-pears-serve.md
@@ -0,0 +1,5 @@
+---
+"@lynx-js/rspeedy": patch
+---
+
+Use `chunkLoading: 'import-scripts'` for Web platform
diff --git a/packages/rspeedy/core/src/plugins/chunkLoading.plugin.ts b/packages/rspeedy/core/src/plugins/chunkLoading.plugin.ts
index d254704783..38353ee60b 100644
--- a/packages/rspeedy/core/src/plugins/chunkLoading.plugin.ts
+++ b/packages/rspeedy/core/src/plugins/chunkLoading.plugin.ts
@@ -6,13 +6,25 @@ import type { RsbuildPlugin } from '@rsbuild/core'
import { ChunkLoadingWebpackPlugin } from '@lynx-js/chunk-loading-webpack-plugin'
+import { isLynx } from '../utils/is-lynx.js'
+import { isWeb } from '../utils/is-web.js'
+
export function pluginChunkLoading(): RsbuildPlugin {
return {
name: 'lynx:rsbuild:chunk-loading',
setup(api) {
- api.modifyBundlerChain(chain => {
- // dprint-ignore
- chain
+ api.modifyBundlerChain((chain, { environment }) => {
+ if (isWeb(environment)) {
+ chain
+ .output
+ .chunkLoading('import-scripts')
+ .end()
+ return
+ }
+
+ if (isLynx(environment)) {
+ // dprint-ignore
+ chain
.plugin('lynx:chunk-loading')
.use(ChunkLoadingWebpackPlugin)
.end()
@@ -23,14 +35,17 @@ export function pluginChunkLoading(): RsbuildPlugin {
.chunkFormat('commonjs')
.iife(false)
.end()
+ }
})
- api.modifyWebpackChain(chain => {
- chain
- .output
- // For webpack, we directly use `chunkLoading: 'lynx'`.
- .chunkLoading('lynx')
- .end()
+ api.modifyWebpackChain((chain, { environment }) => {
+ if (isLynx(environment)) {
+ chain
+ .output
+ // For webpack, we directly use `chunkLoading: 'lynx'`.
+ .chunkLoading('lynx')
+ .end()
+ }
})
},
}
diff --git a/packages/rspeedy/core/src/plugins/target.plugin.ts b/packages/rspeedy/core/src/plugins/target.plugin.ts
index 69c2c60432..68e0b5b3de 100644
--- a/packages/rspeedy/core/src/plugins/target.plugin.ts
+++ b/packages/rspeedy/core/src/plugins/target.plugin.ts
@@ -5,13 +5,22 @@
import type { RsbuildPlugin } from '@rsbuild/core'
import { getESVersionTarget } from '../utils/getESVersionTarget.js'
+import { isWeb } from '../utils/is-web.js'
export function pluginTarget(): RsbuildPlugin {
return {
name: 'lynx:rsbuild:target',
setup(api) {
- api.modifyBundlerChain((options) => {
- options.target([getESVersionTarget()])
+ api.modifyBundlerChain((options, { environment }) => {
+ if (isWeb(environment)) {
+ options.target([
+ getESVersionTarget(),
+ // Add `target: 'web'` to make Rsbuild inject HMR related code.
+ 'web',
+ ])
+ } else {
+ options.target([getESVersionTarget()])
+ }
})
},
}
diff --git a/packages/rspeedy/core/src/utils/is-lynx.ts b/packages/rspeedy/core/src/utils/is-lynx.ts
new file mode 100644
index 0000000000..94bfe87c58
--- /dev/null
+++ b/packages/rspeedy/core/src/utils/is-lynx.ts
@@ -0,0 +1,11 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+import type { EnvironmentContext } from '@rsbuild/core'
+
+export function isLynx(environment: EnvironmentContext | string): boolean {
+ return typeof environment === 'string'
+ ? environment === 'lynx'
+ : environment.name === 'lynx'
+}
diff --git a/packages/rspeedy/core/src/utils/is-web.ts b/packages/rspeedy/core/src/utils/is-web.ts
new file mode 100644
index 0000000000..0fd862b39d
--- /dev/null
+++ b/packages/rspeedy/core/src/utils/is-web.ts
@@ -0,0 +1,11 @@
+// Copyright 2024 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+import type { EnvironmentContext } from '@rsbuild/core'
+
+export function isWeb(environment: EnvironmentContext | string): boolean {
+ return typeof environment === 'string'
+ ? environment === 'web'
+ : environment.name === 'web'
+}
diff --git a/packages/rspeedy/core/test/plugins/chunkLoading.plugin.test.ts b/packages/rspeedy/core/test/plugins/chunkLoading.plugin.test.ts
index a9a6ee245b..9441909dd7 100644
--- a/packages/rspeedy/core/test/plugins/chunkLoading.plugin.test.ts
+++ b/packages/rspeedy/core/test/plugins/chunkLoading.plugin.test.ts
@@ -36,4 +36,71 @@ describe('Plugins - chunkLoading', () => {
),
).toBeTruthy()
})
+
+ describe('Web', () => {
+ test('Rspack', async () => {
+ const rspeedy = await createStubRspeedy({
+ environments: {
+ web: {},
+ },
+ })
+
+ const config = await rspeedy.unwrapConfig()
+
+ expect(config.output?.chunkLoading).toBe('import-scripts')
+ expect(config.output?.chunkFormat).not.toBe('commonjs')
+ expect(config.output?.iife).not.toBe(false)
+ })
+
+ test('Webpack', async () => {
+ const { webpackProvider } = await import('@rsbuild/webpack')
+ const rspeedy = await createStubRspeedy({
+ provider: webpackProvider,
+ environments: {
+ web: {},
+ },
+ })
+
+ const config = await rspeedy.unwrapConfig()
+
+ expect(config.output?.chunkLoading).toBe('import-scripts')
+ expect(config.output?.chunkFormat).not.toBe('commonjs')
+ expect(config.output?.iife).not.toBe(false)
+ })
+
+ test('multiple environments', async () => {
+ const rspeedy = await createStubRspeedy({
+ environments: {
+ web: {},
+ lynx: {},
+ },
+ })
+
+ const [webConfig, lynxConfig] = await rspeedy.initConfigs()
+
+ expect(webConfig?.output?.chunkLoading).toBe('import-scripts')
+ expect(webConfig?.output?.chunkFormat).not.toBe('commonjs')
+ expect(webConfig?.output?.iife).not.toBe(false)
+
+ expect(lynxConfig?.output?.chunkLoading).toBe('require')
+ expect(lynxConfig?.output?.chunkFormat).toBe('commonjs')
+ expect(lynxConfig?.output?.iife).toBe(false)
+ })
+
+ test('override with tools.rspack.output.chunkLoading', async () => {
+ const rspeedy = await createStubRspeedy({
+ environments: {
+ web: {
+ tools: {
+ rspack: { output: { chunkLoading: 'import' } },
+ },
+ },
+ },
+ })
+
+ const config = await rspeedy.unwrapConfig()
+
+ expect(config.output?.chunkLoading).toBe('import')
+ })
+ })
})
diff --git a/packages/rspeedy/core/test/plugins/target.plugin.test.ts b/packages/rspeedy/core/test/plugins/target.plugin.test.ts
index d01f71ea00..40a7ad754b 100644
--- a/packages/rspeedy/core/test/plugins/target.plugin.test.ts
+++ b/packages/rspeedy/core/test/plugins/target.plugin.test.ts
@@ -28,4 +28,30 @@ describe('target.plugin', () => {
expect(config.target).toEqual(['es2019'])
})
+
+ test('Web', async () => {
+ const rspeedy = await createStubRspeedy({
+ environments: {
+ web: {},
+ },
+ })
+
+ const config = await rspeedy.unwrapConfig()
+
+ expect(config.target).toEqual(['es2019', 'web'])
+ })
+
+ test('multiple environments', async () => {
+ const rspeedy = await createStubRspeedy({
+ environments: {
+ web: {},
+ lynx: {},
+ },
+ })
+
+ const [webConfig, lynxConfig] = await rspeedy.initConfigs()
+
+ expect(webConfig?.target).toEqual(['es2019', 'web'])
+ expect(lynxConfig?.target).toEqual(['es2019'])
+ })
})
From 4caf2ef444586ad4be96198a5510c62830f745c9 Mon Sep 17 00:00:00 2001
From: Qingyu Wang <40660121+colinaaa@users.noreply.github.com>
Date: Thu, 27 Mar 2025 12:16:58 +0800
Subject: [PATCH 2/2] test: enable chunk-split tests
---
.../web-tests/tests/main-thread-apis.test.ts | 10 -------
.../web-tests/tests/react.spec.ts | 22 ++------------
.../index.jsx | 25 ----------------
.../rspeedy.config.ts | 29 -------------------
.../rspeedy.config.ts | 7 +++--
.../rspeedy.config.ts | 7 +++--
.../rspeedy.config.ts | 7 +++--
.../web-tests/tests/web-elements.spec.ts | 7 +----
8 files changed, 19 insertions(+), 95 deletions(-)
delete mode 100644 packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/index.jsx
delete mode 100644 packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/rspeedy.config.ts
diff --git a/packages/web-platform/web-tests/tests/main-thread-apis.test.ts b/packages/web-platform/web-tests/tests/main-thread-apis.test.ts
index f5d69ae01e..07038bb711 100644
--- a/packages/web-platform/web-tests/tests/main-thread-apis.test.ts
+++ b/packages/web-platform/web-tests/tests/main-thread-apis.test.ts
@@ -9,12 +9,6 @@ import {
} from '@lynx-js/web-constants';
import { test, expect } from './coverage-fixture.js';
import type { Page } from '@playwright/test';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import fs from 'node:fs/promises';
-import v8toIstanbul from 'v8-to-istanbul';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
const wait = async (ms: number) => {
await new Promise((resolve) => {
@@ -22,10 +16,6 @@ const wait = async (ms: number) => {
});
};
-const getTitle = (titlePath: string[]) => {
- return path.join(...[titlePath.pop()!, titlePath.pop()!].reverse());
-};
-
test.describe('main thread api tests', () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/main-thread-test.html`, {
diff --git a/packages/web-platform/web-tests/tests/react.spec.ts b/packages/web-platform/web-tests/tests/react.spec.ts
index 2dd649a301..31327f408c 100644
--- a/packages/web-platform/web-tests/tests/react.spec.ts
+++ b/packages/web-platform/web-tests/tests/react.spec.ts
@@ -4,12 +4,6 @@
import { swipe, dragAndHold } from './utils.js';
import { test, expect } from './coverage-fixture.js';
import type { Page } from '@playwright/test';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import fs from 'node:fs/promises';
-import v8toIstanbul from 'v8-to-istanbul';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
const wait = async (ms: number) => {
await new Promise((resolve) => {
@@ -964,7 +958,7 @@ test.describe('reactlynx3 tests', () => {
await expect(target).toHaveCSS('height', '100px');
},
);
- test.fixme( // TODO(@colinaaa): update the template plugin
+ test(
'config-splitchunk-single-vendor',
async ({ page }, { title }) => {
await goto(page, title, true);
@@ -973,7 +967,7 @@ test.describe('reactlynx3 tests', () => {
await expect(target).toHaveCSS('background-color', 'rgb(0, 128, 0)'); // green
},
);
- test.fixme( // TODO(@colinaaa): update the template plugin
+ test(
'config-splitchunk-split-by-experience',
async ({ page }, { title }) => {
await goto(page, title, true);
@@ -982,7 +976,7 @@ test.describe('reactlynx3 tests', () => {
await expect(target).toHaveCSS('background-color', 'rgb(0, 128, 0)'); // green
},
);
- test.fixme( // TODO(@colinaaa): update the template plugin
+ test(
'config-splitchunk-split-by-module',
async ({ page }, { title }) => {
await goto(page, title, true);
@@ -992,16 +986,6 @@ test.describe('reactlynx3 tests', () => {
},
);
- test.fixme( // TODO(@colinaaa): update the template plugin
- 'config-splitchunk-error-assertPrefix',
- async ({ page }, { title }) => {
- await goto(page, title, true);
- await wait(1500);
- const target = page.locator('#target');
- await expect(target).toHaveCSS('background-color', 'rgb(0, 128, 0)'); // green
- },
- );
-
test('config-mode-dev-with-all-in-one', async ({ page }, { title }) => {
await goto(page, title, true);
await wait(100);
diff --git a/packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/index.jsx b/packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/index.jsx
deleted file mode 100644
index 1d8f5fc701..0000000000
--- a/packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/index.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2023 The Lynx Authors. All rights reserved.
-// Licensed under the Apache License Version 2.0 that can be found in the
-// LICENSE file in the root directory of this source tree.
-import { root, useEffect, useState } from '@lynx-js/react';
-
-function App() {
- const [color, setColor] = useState('pink');
- useEffect(() => {
- setTimeout(() => {
- setColor('green');
- }, 1000);
- }, [setColor]);
- return (
-
- );
-}
-
-root.render();
diff --git a/packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/rspeedy.config.ts b/packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/rspeedy.config.ts
deleted file mode 100644
index 703efd1075..0000000000
--- a/packages/web-platform/web-tests/tests/react/config-splitchunk-error-assertPrefix/rspeedy.config.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2023 The Lynx Authors. All rights reserved.
-// Licensed under the Apache License Version 2.0 that can be found in the
-// LICENSE file in the root directory of this source tree.
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { defineConfig } from '@lynx-js/rspeedy';
-import { commonConfig } from '../commonConfig.js';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-const caseName = path.basename(__dirname);
-
-const root = path.join(__dirname, '..', '..', '..', 'dist', caseName);
-const commonConfigResult = commonConfig();
-commonConfigResult.output!.distPath = { root };
-commonConfigResult.output!.assetPrefix += `error://example.com/`;
-export default defineConfig({
- ...commonConfigResult,
- source: {
- entry: {
- [caseName]: path.join(__dirname, 'index.jsx'),
- },
- },
- performance: {
- chunkSplit: {
- // Rspack 1.2.8 introduced a bug that causes the split-by-module strategy to fail.
- // strategy: 'split-by-module',
- },
- },
-});
diff --git a/packages/web-platform/web-tests/tests/react/config-splitchunk-single-vendor/rspeedy.config.ts b/packages/web-platform/web-tests/tests/react/config-splitchunk-single-vendor/rspeedy.config.ts
index b3b9ba4e04..421d2b99db 100644
--- a/packages/web-platform/web-tests/tests/react/config-splitchunk-single-vendor/rspeedy.config.ts
+++ b/packages/web-platform/web-tests/tests/react/config-splitchunk-single-vendor/rspeedy.config.ts
@@ -22,8 +22,11 @@ export default defineConfig({
},
performance: {
chunkSplit: {
- // Rspack 1.2.8 introduced a bug that causes the single-vendor strategy to fail.
- // strategy: 'single-vendor',
+ strategy: 'single-vendor',
+ override: {
+ // See: https://github.com/web-infra-dev/rspack/issues/9812
+ filename: '[name].[contenthash:8].js',
+ },
},
},
});
diff --git a/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-experience/rspeedy.config.ts b/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-experience/rspeedy.config.ts
index 77c2ea92f7..c3ffda250a 100644
--- a/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-experience/rspeedy.config.ts
+++ b/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-experience/rspeedy.config.ts
@@ -22,8 +22,11 @@ export default defineConfig({
},
performance: {
chunkSplit: {
- // Rspack 1.2.8 introduced a bug that causes the split-by-experience strategy to fail.
- // strategy: 'split-by-experience',
+ strategy: 'split-by-experience',
+ override: {
+ // See: https://github.com/web-infra-dev/rspack/issues/9812
+ filename: '[name].[contenthash:8].js',
+ },
},
},
});
diff --git a/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-module/rspeedy.config.ts b/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-module/rspeedy.config.ts
index 71ca2aac18..419e098768 100644
--- a/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-module/rspeedy.config.ts
+++ b/packages/web-platform/web-tests/tests/react/config-splitchunk-split-by-module/rspeedy.config.ts
@@ -22,8 +22,11 @@ export default defineConfig({
},
performance: {
chunkSplit: {
- // Rspack 1.2.8 introduced a bug that causes the split-by-module strategy to fail.
- // strategy: 'split-by-module',
+ strategy: 'split-by-module',
+ override: {
+ // See: https://github.com/web-infra-dev/rspack/issues/9812
+ filename: '[name].[contenthash:8].js',
+ },
},
},
});
diff --git a/packages/web-platform/web-tests/tests/web-elements.spec.ts b/packages/web-platform/web-tests/tests/web-elements.spec.ts
index 1a86f0b4c1..be534a4b59 100644
--- a/packages/web-platform/web-tests/tests/web-elements.spec.ts
+++ b/packages/web-platform/web-tests/tests/web-elements.spec.ts
@@ -1,15 +1,10 @@
// Copyright 2024 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import { swipe, dragAndHold } from './utils';
+import { swipe, dragAndHold } from './utils.js';
import { test, expect } from './coverage-fixture.js';
import type { Page } from '@playwright/test';
import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import fs from 'node:fs/promises';
-import v8toIstanbul from 'v8-to-istanbul';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
const wait = async (ms: number) => {
await new Promise((resolve) => {