Skip to content

Commit

Permalink
fix: css runtime should have hmr handler when lazy-compilation (#8400)
Browse files Browse the repository at this point in the history
  • Loading branch information
JSerFeng authored Nov 11, 2024
1 parent 82b19c4 commit f23d638
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 32 deletions.
6 changes: 6 additions & 0 deletions crates/rspack_core/src/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1408,13 +1408,18 @@ impl Compilation {
let mut runtime_requirements;

loop {
// runtime_requirements: rt_requirements of last time
// runtime_requirements_mut: changed rt_requirements
// requirements: all rt_requirements
runtime_requirements = runtime_requirements_mut;
runtime_requirements_mut = RuntimeGlobals::default();
call_hook(
requirements,
&runtime_requirements,
&mut runtime_requirements_mut,
)?;

// check if we have changes to runtime_requirements
runtime_requirements_mut =
runtime_requirements_mut.difference(requirements.intersection(runtime_requirements_mut));
if runtime_requirements_mut.is_empty() {
Expand Down Expand Up @@ -1891,6 +1896,7 @@ impl Compilation {
let runtime_module_identifier =
ModuleIdentifier::from(format!("{}/{}", &chunk.runtime, module.identifier()));
module.attach(*chunk_ukey);

self.chunk_graph.add_module(runtime_module_identifier);
self
.chunk_graph
Expand Down
34 changes: 13 additions & 21 deletions crates/rspack_plugin_extract_css/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,35 +432,29 @@ async fn compilation(
}

#[plugin_hook(CompilationRuntimeRequirementInTree for PluginCssExtract)]
fn runtime_requirements_in_tree(
fn runtime_requirement_in_tree(
&self,
compilation: &mut Compilation,
chunk_ukey: &ChunkUkey,
_all_runtime_requirements: &RuntimeGlobals,
runtime_requirements: &RuntimeGlobals,
runtime_requirements_mut: &mut RuntimeGlobals,
) -> Result<Option<()>> {
// different from webpack, Rspack can invoke this multiple times,
// each time with current runtime_globals, and records every mutation
// by `runtime_requirements_mut`, but this RuntimeModule depends on
// 2 runtimeGlobals, if check current runtime_requirements, we might
// insert CssLoadingRuntimeModule with with_loading: true but with_hmr: false
// for the first time, and with_loading: false but with_hmr: true for the
// second time
// For plugin that depends on 2 runtime_globals, should check all_runtime_requirements
if !self.options.runtime {
return Ok(None);
}

let with_loading = runtime_requirements.contains(RuntimeGlobals::ENSURE_CHUNK_HANDLERS) && {
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);

chunk
.get_all_async_chunks(&compilation.chunk_group_by_ukey)
.iter()
.any(|chunk| {
!compilation
.chunk_graph
.get_chunk_modules_by_source_type(chunk, SOURCE_TYPE[0], &compilation.get_module_graph())
.is_empty()
})
};

let with_hmr = runtime_requirements.contains(RuntimeGlobals::HMR_DOWNLOAD_UPDATE_HANDLERS);

if with_loading || with_hmr {
if runtime_requirements.contains(RuntimeGlobals::HMR_DOWNLOAD_UPDATE_HANDLERS)
|| runtime_requirements.contains(RuntimeGlobals::ENSURE_CHUNK_HANDLERS)
{
if let Some(chunk_filename) = self.options.chunk_filename.template()
&& chunk_filename.contains("hash")
{
Expand Down Expand Up @@ -499,8 +493,6 @@ fn runtime_requirements_in_tree(
self.options.attributes.clone(),
self.options.link_type.clone(),
self.options.insert.clone(),
with_loading,
with_hmr,
)),
)?;
}
Expand Down Expand Up @@ -668,7 +660,7 @@ impl Plugin for PluginCssExtract {
.context
.compilation_hooks
.runtime_requirement_in_tree
.tap(runtime_requirements_in_tree::new(self));
.tap(runtime_requirement_in_tree::new(self));
ctx
.context
.compilation_hooks
Expand Down
44 changes: 33 additions & 11 deletions crates/rspack_plugin_extract_css/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ use std::sync::Arc;
use cow_utils::CowUtils;
use rspack_collections::UkeySet;
use rspack_core::{
impl_runtime_module, rspack_sources::RawSource, ChunkUkey, Compilation, CrossOriginLoading,
RuntimeGlobals, RuntimeModule, RuntimeModuleStage,
impl_runtime_module,
rspack_sources::{RawSource, SourceExt},
ChunkUkey, Compilation, CrossOriginLoading, RuntimeGlobals, RuntimeModule, RuntimeModuleStage,
};
use rspack_error::Result;
use rspack_plugin_runtime::get_chunk_runtime_requirements;
use rustc_hash::FxHashMap;

use crate::plugin::{InsertType, SOURCE_TYPE};
Expand All @@ -22,9 +24,6 @@ pub(crate) struct CssLoadingRuntimeModule {
attributes: FxHashMap<String, String>,
link_type: Option<String>,
insert: InsertType,

loading: bool,
hmr: bool,
}

impl CssLoadingRuntimeModule {
Expand All @@ -33,10 +32,8 @@ impl CssLoadingRuntimeModule {
attributes: FxHashMap<String, String>,
link_type: Option<String>,
insert: InsertType,
loading: bool,
hmr: bool,
) -> Self {
Self::with_default(chunk, attributes, link_type, insert, loading, hmr)
Self::with_default(chunk, attributes, link_type, insert)
}

fn get_css_chunks(&self, compilation: &Compilation) -> UkeySet<ChunkUkey> {
Expand Down Expand Up @@ -73,9 +70,34 @@ impl RuntimeModule for CssLoadingRuntimeModule {
compilation: &rspack_core::Compilation,
) -> Result<rspack_core::rspack_sources::BoxSource> {
let runtime = RUNTIME_CODE;
let runtime_requirements = get_chunk_runtime_requirements(compilation, &self.chunk);

let with_loading = runtime_requirements.contains(RuntimeGlobals::ENSURE_CHUNK_HANDLERS) && {
let chunk = compilation.chunk_by_ukey.expect_get(&self.chunk);

chunk
.get_all_async_chunks(&compilation.chunk_group_by_ukey)
.iter()
.any(|chunk| {
!compilation
.chunk_graph
.get_chunk_modules_by_source_type(
chunk,
SOURCE_TYPE[0],
&compilation.get_module_graph(),
)
.is_empty()
})
};

let with_hmr = runtime_requirements.contains(RuntimeGlobals::HMR_DOWNLOAD_UPDATE_HANDLERS);

if !with_hmr && !with_loading {
return Ok(RawSource::from("").boxed());
}

let mut attr = String::default();
let mut attributes = self.attributes.iter().collect::<Vec<_>>();
let mut attributes: Vec<(&String, &String)> = self.attributes.iter().collect::<Vec<_>>();
attributes.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));

for (attr_key, attr_value) in attributes {
Expand Down Expand Up @@ -121,7 +143,7 @@ impl RuntimeModule for CssLoadingRuntimeModule {
),
};

let runtime = if self.loading {
let runtime = if with_loading {
let chunks = self.get_css_chunks(compilation);
if chunks.is_empty() {
runtime.cow_replace("__WITH_LOADING__", "// no chunk loading")
Expand Down Expand Up @@ -171,7 +193,7 @@ impl RuntimeModule for CssLoadingRuntimeModule {
runtime.cow_replace("__WITH_LOADING__", "// no chunk loading")
};

let runtime = if self.hmr {
let runtime = if with_hmr {
runtime.cow_replace(
"__WITH_HMT__",
&WITH_HMR.cow_replace(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect, test } from "@/fixtures";

test("should update style", async ({ page }) => {
const body = await page.$("body");
const backgroundColor = await body!.evaluate(
el => window.getComputedStyle(el).backgroundColor
);
// first time enter the page, style is red
expect(backgroundColor, "red");

// second time enter the page, this time brings query,
// trigger lazy-compile
const url = await body!.evaluate(() => window.location.href);
await page.goto(`${url}?1`);
const updatedBody = await page.$("body");
const updatedBackgroundColor = await updatedBody!.evaluate(
el => window.getComputedStyle(el).backgroundColor
);
// first time enter the page, style is red
expect(updatedBackgroundColor, "blue");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const rspack = require("@rspack/core");

/** @type { import('@rspack/core').RspackOptions } */
module.exports = {
context: __dirname,
entry: "./src/index.js",
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [rspack.CssExtractRspackPlugin.loader, "css-loader"]
}
]
},
plugins: [new rspack.HtmlRspackPlugin(), new rspack.CssExtractRspackPlugin()],
experiments: {
css: false,
lazyCompilation: true
},
optimization: {
splitChunks: {
minSize: 0,
chunks: "all",
cacheGroups: {
styles: {
test: /\.css$/,
name: "style.css"
}
}
}
},
devServer: {
hot: true,
port: 5678
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: blue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./blue.css";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import "./red.css";

if (new URL(window.location.href).search) {
// @ts-expect-error change.js no dts
import("./change.js");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: red;
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ __webpack_require__.e = function (chunkId) {
return "" + chunkId + ".js";
};

})();
// webpack/runtime/get mini-css chunk filename
(() => {
// This function allow to reference chunks
__webpack_require__.miniCssF = function (chunkId) {
// return url for filenames not based on template

// return url for filenames based on template
return "" + chunkId + ".css";
};

})();
// webpack/runtime/global
(() => {
Expand Down

2 comments on commit f23d638

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ✅ success
_selftest ✅ success
rspress ✅ success
rslib ✅ success
rsbuild ✅ success
examples ✅ success
devserver ✅ success

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-11-11 2ac4a11) Current Change
10000_big_production-mode + exec 44.3 s ± 799 ms 44.8 s ± 1.04 s +1.02 %
10000_development-mode + exec 1.85 s ± 27 ms 1.83 s ± 18 ms -0.91 %
10000_development-mode_hmr + exec 642 ms ± 6.8 ms 644 ms ± 6.9 ms +0.32 %
10000_production-mode + exec 2.44 s ± 34 ms 2.42 s ± 28 ms -0.62 %
arco-pro_development-mode + exec 1.78 s ± 79 ms 1.78 s ± 82 ms +0.34 %
arco-pro_development-mode_hmr + exec 430 ms ± 0.53 ms 430 ms ± 0.96 ms -0.03 %
arco-pro_production-mode + exec 3.17 s ± 72 ms 3.18 s ± 83 ms +0.41 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.24 s ± 79 ms 3.27 s ± 88 ms +0.86 %
threejs_development-mode_10x + exec 1.58 s ± 13 ms 1.59 s ± 11 ms +0.18 %
threejs_development-mode_10x_hmr + exec 774 ms ± 12 ms 772 ms ± 6.6 ms -0.20 %
threejs_production-mode_10x + exec 4.96 s ± 35 ms 4.97 s ± 31 ms +0.12 %

Please sign in to comment.