Skip to content

Commit

Permalink
fix: css-extract-plugin should keep file dependencies (#6576)
Browse files Browse the repository at this point in the history
  • Loading branch information
JSerFeng authored May 20, 2024
1 parent 4917589 commit 093a237
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 45 deletions.
13 changes: 7 additions & 6 deletions crates/rspack_core/src/normal_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,13 @@ impl Module for NormalModule {

let mut code_generation_dependencies: Vec<Box<dyn ModuleDependency>> = Vec::new();

build_info.cacheable = loader_result.cacheable;
build_info.file_dependencies = loader_result.file_dependencies;
build_info.context_dependencies = loader_result.context_dependencies;
build_info.missing_dependencies = loader_result.missing_dependencies;
build_info.build_dependencies = loader_result.build_dependencies;
build_info.asset_filenames = loader_result.asset_filenames;

let (
ParseResult {
source,
Expand Down Expand Up @@ -540,12 +547,6 @@ impl Module for NormalModule {
build_meta.hash(&mut hasher);

build_info.hash = Some(hasher.digest(&build_context.compiler_options.output.hash_digest));
build_info.cacheable = loader_result.cacheable;
build_info.file_dependencies = loader_result.file_dependencies;
build_info.context_dependencies = loader_result.context_dependencies;
build_info.missing_dependencies = loader_result.missing_dependencies;
build_info.build_dependencies = loader_result.build_dependencies;
build_info.asset_filenames = loader_result.asset_filenames;

Ok(BuildResult {
build_info,
Expand Down
33 changes: 21 additions & 12 deletions crates/rspack_plugin_extract_css/src/css_dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,26 @@ use crate::css_module::DEPENDENCY_TYPE;

#[derive(Debug, Clone)]
pub struct CssDependency {
pub id: DependencyId,
pub identifier: String,
pub content: String,
pub context: String,
pub media: String,
pub supports: String,
pub source_map: String,
pub(crate) id: DependencyId,
pub(crate) identifier: String,
pub(crate) content: String,
pub(crate) context: String,
pub(crate) media: String,
pub(crate) supports: String,
pub(crate) source_map: String,

// One module can be split apart by using `@import` in the middle of one module
pub identifier_index: u32,
pub(crate) identifier_index: u32,

// determine module's postOrderIndex
pub order_index: u32,
pub(crate) order_index: u32,

resource_identifier: String,

pub filepath: PathBuf,
pub(crate) file_dependencies: FxHashSet<PathBuf>,
pub(crate) context_dependencies: FxHashSet<PathBuf>,
pub(crate) missing_dependencies: FxHashSet<PathBuf>,
pub(crate) build_dependencies: FxHashSet<PathBuf>,
}

impl CssDependency {
Expand All @@ -40,7 +43,10 @@ impl CssDependency {
source_map: String,
identifier_index: u32,
order_index: u32,
filepath: PathBuf,
file_dependencies: FxHashSet<PathBuf>,
context_dependencies: FxHashSet<PathBuf>,
missing_dependencies: FxHashSet<PathBuf>,
build_dependencies: FxHashSet<PathBuf>,
) -> Self {
let resource_identifier = format!("css-module-{}-{}", &identifier, identifier_index);
Self {
Expand All @@ -54,7 +60,10 @@ impl CssDependency {
identifier_index,
order_index,
resource_identifier,
filepath,
file_dependencies,
context_dependencies,
missing_dependencies,
build_dependencies,
}
}
}
Expand Down
19 changes: 13 additions & 6 deletions crates/rspack_plugin_extract_css/src/css_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ pub(crate) struct CssModule {
dependencies: Vec<DependencyId>,

identifier__: Identifier,
filepath: PathBuf,

file_dependencies: FxHashSet<PathBuf>,
context_dependencies: FxHashSet<PathBuf>,
missing_dependencies: FxHashSet<PathBuf>,
build_dependencies: FxHashSet<PathBuf>,
}

impl Hash for CssModule {
Expand Down Expand Up @@ -80,7 +84,10 @@ impl CssModule {
build_meta: None,
source_map_kind: rspack_util::source_map::SourceMapKind::empty(),
identifier__,
filepath: dep.filepath,
file_dependencies: dep.file_dependencies,
context_dependencies: dep.context_dependencies,
missing_dependencies: dep.missing_dependencies,
build_dependencies: dep.build_dependencies,
}
}

Expand Down Expand Up @@ -150,13 +157,13 @@ impl Module for CssModule {
build_context: BuildContext<'_>,
_compilation: Option<&Compilation>,
) -> Result<BuildResult> {
let mut file_deps = FxHashSet::default();
file_deps.insert(self.filepath.clone());

Ok(BuildResult {
build_info: BuildInfo {
hash: Some(self.compute_hash(build_context.compiler_options)),
file_dependencies: file_deps,
file_dependencies: self.file_dependencies.clone(),
context_dependencies: self.context_dependencies.clone(),
missing_dependencies: self.missing_dependencies.clone(),
build_dependencies: self.build_dependencies.clone(),
..Default::default()
},
..Default::default()
Expand Down
7 changes: 5 additions & 2 deletions crates/rspack_plugin_extract_css/src/parser_and_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl ParserAndGenerator for CssExtractParserAndGenerator {
supports,
source_map,
identifier_index,
filepath,
..
}| {
let dep = Box::new(CssDependency::new(
identifier.into(),
Expand All @@ -87,7 +87,10 @@ impl ParserAndGenerator for CssExtractParserAndGenerator {
source_map.clone(),
*identifier_index,
idx,
filepath.clone(),
parse_context.build_info.file_dependencies.clone(),
parse_context.build_info.context_dependencies.clone(),
parse_context.build_info.missing_dependencies.clone(),
parse_context.build_info.build_dependencies.clone(),
));
idx += 1;
dep
Expand Down
49 changes: 30 additions & 19 deletions crates/rspack_plugin_extract_css/src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use std::{borrow::Cow, cmp::max, hash::Hash, sync::Arc};
use std::{
borrow::Cow,
cmp::max,
hash::Hash,
sync::{atomic::AtomicBool, Arc},
};

use once_cell::sync::Lazy;
use regex::Regex;
Expand Down Expand Up @@ -58,7 +63,8 @@ struct CssOrderConflicts {
#[plugin]
#[derive(Debug)]
pub struct PluginCssExtract {
pub options: Arc<CssExtractOptions>,
pub(crate) options: Arc<CssExtractOptions>,
registered: AtomicBool,
}

impl Eq for PluginCssExtractInner {}
Expand Down Expand Up @@ -113,7 +119,7 @@ pub enum InsertType {

impl PluginCssExtract {
pub fn new(options: CssExtractOptions) -> Self {
Self::new_inner(Arc::new(options))
Self::new_inner(Arc::new(options), false.into())
}

// port from https://github.com/webpack-contrib/mini-css-extract-plugin/blob/d5e540baf8280442e523530ebbbe31c57a4c4336/src/index.js#L1127
Expand Down Expand Up @@ -430,22 +436,27 @@ async fn compilation(
) -> Result<()> {
compilation.set_dependency_factory(DEPENDENCY_TYPE.clone(), Arc::new(CssModuleFactory));

let (_, parser_and_generator) = compilation
.plugin_driver
.registered_parser_and_generator_builder
.remove(&ModuleType::Js)
.expect("No JavaScript parser registered");

compilation
.plugin_driver
.registered_parser_and_generator_builder
.insert(
ModuleType::Js,
Box::new(move |parser_opt, generator_opt| {
let parser = parser_and_generator(parser_opt, generator_opt);
Box::new(CssExtractParserAndGenerator::new(parser))
}),
);
if !self
.registered
.swap(true, std::sync::atomic::Ordering::Relaxed)
{
let (_, parser_and_generator) = compilation
.plugin_driver
.registered_parser_and_generator_builder
.remove(&ModuleType::Js)
.expect("No JavaScript parser registered");

compilation
.plugin_driver
.registered_parser_and_generator_builder
.insert(
ModuleType::Js,
Box::new(move |parser_opt, generator_opt| {
let parser = parser_and_generator(parser_opt, generator_opt);
Box::new(CssExtractParserAndGenerator::new(parser))
}),
);
}
Ok(())
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { test, expect } from "@/fixtures";

test("tailwindcss should work when modify js file", async ({
page,
fileAction,
rspack
}) => {
function getAppFontSize() {
return page.evaluate(() => {
const app = document.querySelector("#app");
if (!app) {
return "";
}
return window.getComputedStyle(app).fontSize;
});
}

let appFontSize = await getAppFontSize();
expect(appFontSize).toBe("24px");

// update
fileAction.updateFile("src/App.jsx", content => {
return content.replace("text-2xl", "text-3xl");
});

await expect(page.locator("#app")).toHaveClass(/text-3xl/);

appFontSize = await getAppFontSize();
expect(appFontSize).toBe("30px");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const path = require("path");
const rspack = require("@rspack/core");
const ReactRefreshPlugin = require("@rspack/plugin-react-refresh");

module.exports = {
context: __dirname,
mode: "development",
entry: {
main: "./src/main.jsx"
},
plugins: [
new rspack.HtmlRspackPlugin({ template: "./src/index.html" }),
new ReactRefreshPlugin(),
new rspack.CssExtractRspackPlugin()
],
resolve: {
extensions: ["...", ".ts", ".tsx", ".jsx"]
},
experiments: {
css: false
},
module: {
rules: [
{
test: /\.jsx$/,
use: {
loader: "builtin:swc-loader",
options: {
jsc: {
parser: {
syntax: "ecmascript",
jsx: true
},
transform: {
react: {
runtime: "automatic",
development: true,
refresh: true
}
}
}
}
}
},
{
test: /\.css$/,
use: [
rspack.CssExtractRspackPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: {
tailwindcss: {
config: path.join(__dirname, "./tailwind.config.js")
}
}
}
}
}
]
}
]
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";
import "./App.css";

function App() {
return (
<h1 id="app" className="text-2xl font-bold underline">
Hello world!
</h1>
);
}

export default App;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!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>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const path = require("path");
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [path.join(__dirname, "./src/**/*.{html,js,jsx}")],
theme: {
extend: {}
},
plugins: []
};

2 comments on commit 093a237

@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-05-20 549ab61) Current Change
10000_development-mode + exec 2.59 s ± 19 ms 2.6 s ± 24 ms +0.37 %
10000_development-mode_hmr + exec 703 ms ± 5.7 ms 707 ms ± 7.2 ms +0.51 %
10000_production-mode + exec 2.45 s ± 45 ms 2.48 s ± 26 ms +1.06 %
arco-pro_development-mode + exec 2.48 s ± 51 ms 2.46 s ± 68 ms -0.43 %
arco-pro_development-mode_hmr + exec 432 ms ± 1.7 ms 433 ms ± 0.77 ms +0.10 %
arco-pro_development-mode_hmr_intercept-plugin + exec 442 ms ± 3.4 ms 442 ms ± 1 ms 0.00 %
arco-pro_development-mode_intercept-plugin + exec 3.3 s ± 50 ms 3.32 s ± 39 ms +0.42 %
arco-pro_production-mode + exec 4 s ± 87 ms 4.01 s ± 115 ms +0.09 %
arco-pro_production-mode_intercept-plugin + exec 4.84 s ± 62 ms 4.87 s ± 68 ms +0.58 %
threejs_development-mode_10x + exec 1.97 s ± 23 ms 1.97 s ± 14 ms -0.09 %
threejs_development-mode_10x_hmr + exec 748 ms ± 8.5 ms 750 ms ± 11 ms +0.36 %
threejs_production-mode_10x + exec 5.19 s ± 30 ms 5.19 s ± 22 ms -0.04 %

@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, self-hosted, Linux, ci ✅ success
_selftest, ubuntu-latest ✅ success
nx, ubuntu-latest ❌ failure
rspress, ubuntu-latest ✅ success
rsbuild, ubuntu-latest ✅ success
compat, ubuntu-latest ✅ success
examples, ubuntu-latest ❌ failure

Please sign in to comment.