Skip to content

Commit 9e55f10

Browse files
authored
fix: code splitting incremental missing module to update (#11510)
1 parent bb519b6 commit 9e55f10

File tree

9 files changed

+145
-11
lines changed

9 files changed

+145
-11
lines changed

crates/rspack_core/src/build_chunk_graph/incremental.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,15 @@ impl CodeSplitter {
529529
}
530530
}
531531

532+
for m in affected_modules {
533+
for module_map in self.block_modules_runtime_map.values_mut() {
534+
module_map.remove(&DependenciesBlockIdentifier::Module(m));
535+
}
536+
537+
let more_edges = self.invalidate_from_module(m, compilation)?;
538+
edges.extend(more_edges);
539+
}
540+
532541
if !removed_modules.is_empty() {
533542
// TODO:
534543
// if we have removed module, we should invalidate its
@@ -540,15 +549,6 @@ impl CodeSplitter {
540549
}
541550
}
542551

543-
for m in affected_modules {
544-
for module_map in self.block_modules_runtime_map.values_mut() {
545-
module_map.remove(&DependenciesBlockIdentifier::Module(m));
546-
}
547-
548-
let more_edges = self.invalidate_from_module(m, compilation)?;
549-
edges.extend(more_edges);
550-
}
551-
552552
self.stat_invalidated_caches = dirty_blocks.len() as u32;
553553
for block in dirty_blocks {
554554
self.chunk_caches.remove(&block);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { test, expect } from "@/fixtures";
2+
import path from "path";
3+
4+
test("should error with invalid syntax", async ({ page, fileAction, rspack }) => {
5+
const codePath = path.resolve(rspack.outDir, "AppIndex.js");
6+
await expect(page.locator("button")).toHaveText("count is 0");
7+
await page.click("button");
8+
await expect(page.locator("button")).toHaveText("count is 1");
9+
fileAction.updateFile("src/App.jsx", content =>
10+
content.replace("</div>", "{/* </div> */}")
11+
);
12+
await expect(page.locator("#webpack-dev-server-client-overlay")).toHaveCount(
13+
1
14+
);
15+
const brokenCode = rspack.compiler.outputFileSystem.readFileSync(codePath, "utf-8");
16+
expect(/throw new Error\(".*Unexpected token. Did you mean `{'}'}`/.test(brokenCode)).toBe(true);
17+
});
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const { rspack } = require("@rspack/core");
2+
const ReactRefreshPlugin = require("@rspack/plugin-react-refresh");
3+
4+
module.exports = {
5+
mode: "development",
6+
context: __dirname,
7+
entry: {
8+
main: "./src/main.jsx"
9+
},
10+
devtool: false,
11+
resolve: {
12+
extensions: ["...", ".jsx"]
13+
},
14+
module: {
15+
rules: [
16+
{
17+
test: /\.(jsx?|tsx?)$/,
18+
use: [
19+
{
20+
loader: "builtin:swc-loader",
21+
options: {
22+
jsc: {
23+
parser: {
24+
syntax: "typescript",
25+
tsx: true
26+
},
27+
transform: {
28+
react: {
29+
runtime: "automatic",
30+
development: true,
31+
refresh: true,
32+
}
33+
},
34+
},
35+
}
36+
},
37+
]
38+
}
39+
]
40+
},
41+
plugins: [
42+
new rspack.HtmlRspackPlugin({ template: "./src/index.html" }),
43+
new ReactRefreshPlugin(),
44+
],
45+
optimization: {
46+
runtimeChunk: {
47+
name: "builder-runtime"
48+
},
49+
splitChunks: {
50+
chunks: "all",
51+
minSize: 0,
52+
cacheGroups: {
53+
react: {
54+
name: "lib-react",
55+
test: /node_modules[\\/](?:react|react-dom|scheduler|react-refresh|@rspack[\\/]plugin-react-refresh)[\\/]/,
56+
priority: 0
57+
},
58+
}
59+
}
60+
},
61+
devServer: {
62+
hot: true,
63+
devMiddleware: {
64+
writeToDisk: true
65+
}
66+
}
67+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from "react";
2+
3+
function App() {
4+
const [count, setCount] = React.useState(0);
5+
return (
6+
<div>
7+
<button type="button" onClick={() => setCount(count => count + 1)}>
8+
count is {count}
9+
</button>
10+
</div>
11+
);
12+
}
13+
14+
export default App;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import App from "./App";
2+
3+
const Index = () => <App />;
4+
5+
export default Index;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Document</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
</body>
12+
</html>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react";
2+
import ReactDOM from "react-dom/client";
3+
4+
import(/* webpackChunkName: "AppIndex" */"./AppIndex").then(({ default: App }) => {
5+
global.webpackRequire = __webpack_modules__;
6+
ReactDOM.createRoot(document.getElementById("root")).render(
7+
<React.StrictMode>
8+
<App />
9+
</React.StrictMode>
10+
);
11+
});

tests/e2e/cases/hooks/asset-emitted/index.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ test("asset emitted hook should only emit modified assets", async ({
3131
// check dist dir
3232
// the outputFileSystem can contain only one main hot-update.js
3333
const files = rspack.compiler.outputFileSystem.readdirSync(
34-
"dist",
34+
rspack.outDir,
3535
{}
3636
) as string[];
3737
expect(
@@ -57,7 +57,7 @@ test("asset emitted should not emit removed assets", async ({
5757

5858
// check dist dir
5959
const files = rspack.compiler.outputFileSystem.readdirSync(
60-
"dist",
60+
rspack.outDir,
6161
{}
6262
) as string[];
6363
expect(files.every(item => item !== "src_foo_js.js")).toBeTruthy();

tests/e2e/fixtures/rspack.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { PathInfoFixtures } from "./pathInfo";
1313
class Rspack {
1414
private config: RspackConfig;
1515
projectDir: string;
16+
outDir: string;
1617
compiler: Compiler;
1718
devServer: RspackDevServer;
1819
private onDone: Array<() => void> = [];
@@ -24,6 +25,7 @@ class Rspack {
2425
this.config = handleRspackConfig(require(configPath));
2526
delete require.cache[configPath];
2627
this.projectDir = projectDir;
28+
this.outDir = this.config.output!.path!;
2729
}
2830

2931
// waiting for build done, not hmr done
@@ -117,6 +119,12 @@ export const rspackFixtures = (): RspackFixtures => {
117119
config.context = tempProjectDir;
118120
}
119121

122+
// set default output path
123+
if (!config.output) {
124+
config.output = {};
125+
}
126+
config.output.path = path.resolve(tempProjectDir, "dist");
127+
120128
if (incremental) {
121129
config.experiments ??= {};
122130
config.experiments.incremental = true;

0 commit comments

Comments
 (0)