Skip to content

Commit

Permalink
fix: chunk load failed with hashed id strategy (#805)
Browse files Browse the repository at this point in the history
* fix: chunk load failed with hased id strategy

* test: add hased case for code splitting

* test: add hased case for css chunk hmr
  • Loading branch information
PeachScript authored Dec 18, 2023
1 parent b245dac commit 86e8b80
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 12 deletions.
10 changes: 4 additions & 6 deletions crates/mako/src/hmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ impl Compiler {
let module_graph = &self.context.module_graph.read().unwrap();
let (js_stmts, _) = modules_to_js_stmts(module_ids, module_graph, &self.context).unwrap();
let mut content = include_str!("runtime/runtime_hmr.js").to_string();
content = content
.replace("__CHUNK_ID__", &chunk.id.generate(&self.context))
.replace(
"__runtime_code__",
&format!("runtime._h='{}';", current_hash),
);
content = content.replace("__CHUNK_ID__", &chunk.id.id).replace(
"__runtime_code__",
&format!("runtime._h='{}';", current_hash),
);
// TODO: handle error
let mut js_ast = build_js_ast(filename, content.as_str(), &self.context)
.unwrap()
Expand Down
2 changes: 1 addition & 1 deletion crates/mako/src/transformers/transform_dep_replacer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl VisitMut for DepReplacer<'_> {
chunk_graph.get_chunk_for_module(&dep_module_id.clone());

if let Some(chunk) = chunk {
let chunk_id = chunk.id.generate(self.context);
let chunk_id = chunk.id.id.clone();
// `import('./xxx.css')` => `__mako_require__.ensure('./xxx.css')`
*expr = member_expr!(DUMMY_SP, __mako_require__.ensure)
.as_call(DUMMY_SP, vec![quote_str!(chunk_id).as_arg()]);
Expand Down
8 changes: 3 additions & 5 deletions crates/mako/src/transformers/transform_dynamic_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use mako_core::swc_ecma_ast::{ArrayLit, Expr, ExprOrSpread, Lit};
use mako_core::swc_ecma_visit::{VisitMut, VisitMutWith};

use super::utils::{id, member_call, member_prop, promise_all, require_ensure};
use crate::chunk::ChunkId;
use crate::compiler::Context;
use crate::module::{generate_module_id, ModuleId};
use crate::plugins::javascript::is_dynamic_import;

pub struct DynamicImport<'a> {
Expand All @@ -27,7 +27,7 @@ impl VisitMut for DynamicImport<'_> {
{
// note: the source is replaced !
let resolved_source = source.value.clone().to_string();
let chunk_id: ModuleId = resolved_source.clone().into();
let chunk_id: ChunkId = resolved_source.clone().into();

let chunk_graph = &self.context.chunk_graph.read().unwrap();

Expand All @@ -42,14 +42,12 @@ impl VisitMut for DynamicImport<'_> {
.concat()
.iter()
.filter_map(|chunk_id| {
let id = generate_module_id(chunk_id.id.clone(), self.context);

// skip empty chunk because it will not be generated
if chunk_graph
.chunk(chunk_id)
.is_some_and(|c| !c.modules.is_empty())
{
Some(id)
Some(chunk_id.id.clone())
} else {
None
}
Expand Down
22 changes: 22 additions & 0 deletions e2e/fixtures/code-splitting.hashed/expect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const assert = require("assert");
const { testWithBrowser } = require("../../../scripts/test-utils");

const test = async () => {
try {
await testWithBrowser({
cwd: __dirname,
fn: async ({ page }) => {
const elm = await page.locator('#root');
const content = await elm.evaluate((el) => el.innerHTML);
assert.equal(content, 'a utils', 'async chunk and common chunk should be loaded');

const styles = await elm.evaluate((el) => window.getComputedStyle(el));
assert.equal(styles.fontSize, '100px', 'async css chunk should be loaded');
},
entry: "index.js",
});
} catch (e) {
throw new Error(e);
}
};
module.exports = test;
13 changes: 13 additions & 0 deletions e2e/fixtures/code-splitting.hashed/mako.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"moduleIdStrategy": "hashed",
"codeSplitting": {
"minSize": 1,
"groups": [
{
"name": "common",
"test": "utils\\.ts",
"minSize": 1
}
]
}
}
8 changes: 8 additions & 0 deletions e2e/fixtures/code-splitting.hashed/src/a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import utils from './utils';

// @ts-ignore
import('./b.css').then(() => {
document.getElementById('root')!.innerHTML = `a ${utils}`;
});

export default 'a';
3 changes: 3 additions & 0 deletions e2e/fixtures/code-splitting.hashed/src/b.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
font-size: 100px;
}
1 change: 1 addition & 0 deletions e2e/fixtures/code-splitting.hashed/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import('./a').then(console.log);
1 change: 1 addition & 0 deletions e2e/fixtures/code-splitting.hashed/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'utils';
60 changes: 60 additions & 0 deletions scripts/test-hmr.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,66 @@ runTest('css: entry > css hmr with hostname runtime public', async () => {
await cleanup({ process, browser });
});

runTest('css: entry > css chunk hmr with hashed chunk id', async () => {
write(
normalizeFiles(
{
'/public/index.html': `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="/index.js"></script>
</body>
</html>
`,
'/src/App.css': `.foo {color:red;}`,
'/src/App.tsx': `
import('./App.css');
function App() {
return <div className="foo">App</div>;
}
export default App;
`,
'/src/index.tsx': `
import React from 'react';
import ReactDOM from "react-dom/client";
import App from './App';
ReactDOM.createRoot(document.getElementById("root")!).render(<><App /><section>{Math.random()}</section></>);
`,
},
{ moduleIdStrategy: 'hashed' },
),
);
await startMakoDevServer();
await delay(DELAY_TIME);
const { browser, page } = await startBrowser();
let lastResult;
let thisResult;
let isReload;
lastResult = normalizeHtml(await getRootHtml(page));
const lastColor = await getElementColor(page, '.foo');
assert.equal(lastColor, 'rgb(255, 0, 0)', 'Initial render');
write({
'/src/App.css': `.foo {color:blue;}`,
});
await delay(DELAY_TIME);
thisResult = normalizeHtml(await getRootHtml(page));
const thisColor = await getElementColor(page, '.foo');
console.log(`new color`, thisColor, 'expect color', 'rgb(0, 0, 255)');
assert.equal(thisColor, 'rgb(0, 0, 255)', 'Second render');
isReload = lastResult.random !== thisResult.random;
assert.equal(isReload, false, 'should not reload');
lastResult = thisResult;
await cleanup({ process, browser });
});

runTest('js: entry > js, remove then add back', async () => {
write(
normalizeFiles({
Expand Down

0 comments on commit 86e8b80

Please sign in to comment.