Skip to content

Commit 3e7988f

Browse files
authored
fix(webpack/css-extract): CSS HMR not working (#456)
<!-- Thank you for submitting a pull request! We appreciate the time and effort you have invested in making these changes. Please ensure that you provide enough information to allow others to review your pull request. Upon submission, your pull request will be automatically assigned with reviewers. If you want to learn more about contributing to this project, please visit: https://github.com/lynx-family/lynx-stack/blob/main/CONTRIBUTING.md. --> ## Summary <!-- Can you explain the reasoning behind implementing this change? What problem or issue does this pull request resolve? --> We do not use `chunkLoading: 'require'` in Rspack after #400. So we need to change the CSS hot update runtime, too. This patch avoid using the `compilation.hooks.runtimeModule`, but use the standard `RuntimeModule`. Also fix CSS HMR not working when using nested entry. <!-- It would be helpful if you could provide any relevant context, such as GitHub issues or related discussions. --> ## Checklist <!--- Check and mark with an "x" --> - [x] Tests updated (or not required). - [ ] Documentation updated (or **not required**).
1 parent 670335a commit 3e7988f

File tree

25 files changed

+585
-6687
lines changed

25 files changed

+585
-6687
lines changed

.changeset/slick-wasps-raise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@lynx-js/css-extract-webpack-plugin": patch
3+
---
4+
5+
Fix CSS HMR not working with nested entry name.

packages/webpack/css-extract-webpack-plugin/src/CssExtractRspackPlugin.ts

Lines changed: 72 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import { createRequire } from 'node:module';
66

77
import type {
8-
Compilation,
8+
Chunk,
99
Compiler,
1010
CssExtractRspackPluginOptions as ExternalCssExtractRspackPluginOptions,
1111
} from '@rspack/core';
@@ -136,10 +136,6 @@ class CssExtractRspackPlugin {
136136
export { CssExtractRspackPlugin };
137137
export type { CssExtractRspackPluginOptions };
138138

139-
type RuntimeModule = Parameters<
140-
Compilation['hooks']['runtimeModule']['call']
141-
>[0];
142-
143139
class CssExtractRspackPluginImpl {
144140
name = 'CssExtractRspackPlugin';
145141
private hash: string | null = null;
@@ -163,54 +159,82 @@ class CssExtractRspackPluginImpl {
163159
compiler.options.mode === 'development'
164160
|| process.env['NODE_ENV'] === 'development'
165161
) {
166-
// We require publicPath to get css.hot-update.json
167-
compilation.hooks.additionalTreeRuntimeRequirements.tap(
168-
this.name,
169-
(_, set) => {
170-
set.add(compiler.webpack.RuntimeGlobals.publicPath);
171-
},
172-
);
162+
const { RuntimeGlobals, RuntimeModule } = compiler.webpack;
173163

174-
compilation.hooks.runtimeModule.tap(
175-
this.name,
176-
(runtimeModule, chunk) => {
177-
if (runtimeModule.name === 'require_chunk_loading') {
178-
const asyncChunks = Array.from(chunk.getAllAsyncChunks())
179-
.map(c => {
180-
const { path } = compilation.getAssetPathWithInfo(
181-
options.chunkFilename ?? '.rspeedy/async/[name]/[name].css',
182-
{ chunk: c },
183-
);
184-
return [c.name!, path];
185-
});
164+
class CSSHotUpdateRuntimeModule extends RuntimeModule {
165+
hash: string | null;
186166

187-
const { path } = compilation.getPathWithInfo(
188-
options.filename ?? '[name].css',
189-
// Rspack does not pass JsChunk to Rust.
190-
// See: https://github.com/web-infra-dev/rspack/blob/73c31abcb78472eb5a3d93e4ece19d9f106727a6/crates/rspack_binding_values/src/path_data.rs#L62
191-
{ filename: chunk.name! },
192-
);
167+
constructor(hash: string | null) {
168+
super('lynx css hot update');
169+
this.hash = hash;
170+
}
193171

194-
const initialChunk = [chunk.name!, path];
172+
override generate(): string {
173+
const chunk = this.chunk!;
195174

196-
const cssHotUpdateList = [...asyncChunks, initialChunk].map((
197-
[chunkName, cssHotUpdatePath],
198-
) => [
199-
chunkName!,
200-
cssHotUpdatePath!.replace(
201-
'.css',
202-
`${this.hash ? `.${this.hash}` : ''}.css.hot-update.json`,
203-
),
204-
]);
175+
const asyncChunks = Array.from(chunk.getAllAsyncChunks())
176+
.map(c => {
177+
const { path } = compilation.getAssetPathWithInfo(
178+
options.chunkFilename ?? '.rspeedy/async/[name]/[name].css',
179+
{ chunk: c },
180+
);
181+
return [c.name!, path];
182+
});
205183

206-
this.#overrideChunkLoadingRuntimeModule(
207-
compiler,
208-
runtimeModule,
209-
cssHotUpdateList,
210-
);
211-
}
212-
},
213-
);
184+
const { path } = compilation.getPathWithInfo(
185+
options.filename ?? '[name].css',
186+
{ chunk },
187+
);
188+
189+
const initialChunk = [chunk.name!, path];
190+
191+
const cssHotUpdateList = [...asyncChunks, initialChunk].map((
192+
[chunkName, cssHotUpdatePath],
193+
) => [
194+
chunkName!,
195+
cssHotUpdatePath!.replace(
196+
'.css',
197+
`${this.hash ? `.${this.hash}` : ''}.css.hot-update.json`,
198+
),
199+
]);
200+
201+
return `
202+
${RuntimeGlobals.require}.cssHotUpdateList = ${
203+
cssHotUpdateList ? JSON.stringify(cssHotUpdateList) : 'null'
204+
};
205+
`;
206+
}
207+
}
208+
209+
const onceForChunkSet = new WeakSet<Chunk>();
210+
const handler = (chunk: Chunk, runtimeRequirements: Set<string>) => {
211+
if (onceForChunkSet.has(chunk)) return;
212+
onceForChunkSet.add(chunk);
213+
runtimeRequirements.add(RuntimeGlobals.publicPath);
214+
compilation.addRuntimeModule(
215+
chunk,
216+
new CSSHotUpdateRuntimeModule(this.hash),
217+
);
218+
};
219+
220+
compilation.hooks.runtimeRequirementInTree
221+
.for(RuntimeGlobals.ensureChunkHandlers)
222+
.tap(this.name, handler);
223+
compilation.hooks.runtimeRequirementInTree
224+
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
225+
.tap(this.name, handler);
226+
compilation.hooks.runtimeRequirementInTree
227+
.for(RuntimeGlobals.hmrDownloadManifest)
228+
.tap(this.name, handler);
229+
compilation.hooks.runtimeRequirementInTree
230+
.for(RuntimeGlobals.baseURI)
231+
.tap(this.name, handler);
232+
compilation.hooks.runtimeRequirementInTree
233+
.for(RuntimeGlobals.externalInstallChunk)
234+
.tap(this.name, handler);
235+
compilation.hooks.runtimeRequirementInTree
236+
.for(RuntimeGlobals.onChunksLoaded)
237+
.tap(this.name, handler);
214238

215239
compilation.hooks.processAssets.tapPromise(
216240
{
@@ -301,21 +325,4 @@ class CssExtractRspackPluginImpl {
301325
}
302326
});
303327
}
304-
305-
#overrideChunkLoadingRuntimeModule(
306-
compiler: Compiler,
307-
runtimeModule: RuntimeModule,
308-
cssHotUpdateList: string[][],
309-
) {
310-
const { RuntimeGlobals } = compiler.webpack;
311-
runtimeModule.source!.source = Buffer.concat([
312-
Buffer.from(runtimeModule.source!.source as Buffer),
313-
// cssHotUpdateList
314-
Buffer.from(`
315-
${RuntimeGlobals.require}.cssHotUpdateList = ${
316-
cssHotUpdateList ? JSON.stringify(cssHotUpdateList) : 'null'
317-
};
318-
`),
319-
]);
320-
}
321328
}

0 commit comments

Comments
 (0)