feat: remove empty needless js output for normal css module#20162
feat: remove empty needless js output for normal css module#20162alexander-akait merged 6 commits intowebpack:mainfrom
Conversation
Merging this PR will degrade performance by 35.22%
Performance Changes
Comparing |
lib/css/CssModulesPlugin.js
Outdated
| { | ||
| name: PLUGIN_NAME, | ||
| stage: 100 | ||
| }, |
There was a problem hiding this comment.
Why we need to change stage here?
There was a problem hiding this comment.
The 100 is just a draft here, main reason is to ensure this plugin run after JavascriptPlugin
We register dependencyTemplate, we don't want it to be override by others. compilation.dependencyTemplates.set. Can we do that in other hook maybe ?
There was a problem hiding this comment.
hm, need to think about it, lets' look at tests firstly, I will think about it
alexander-akait
left a comment
There was a problem hiding this comment.
I am fine with both solution to be honestly, just maybe ProxyHarmonyTemplate rename to ProxyHarmonyImportSideEffectDependency to be more clear and move it to HarmonyImportSideEffectDependency file
Done
I think I'm checking the tests and see if HMR has issues |
|
@JSerFeng Feel free to ping me if you will need a help |
8510363 to
a05afc4
Compare
lib/css/CssModulesPlugin.js
Outdated
| compilation.dependencyTemplates.set( | ||
| HarmonyImportSideEffectDependency, | ||
| new ProxyHarmonyImportSideEffectDependencyTemplate() | ||
| ); |
There was a problem hiding this comment.
There is another question, what about require or other things, I think we should try to solve it for any cases, not just for side effect imports...
There was a problem hiding this comment.
Currently I think it's the most safe way, I choose EsmSideEffectDependency because it just means this connection is for side effect, and we can ensure the js output of CssModule has no side effect(when disabled hmr). so this connection can be safely removed.
But others like require, user can write like this
const o = require('./foo.css')
call(o)There is only one connection, and it contains CjsRequireDependency. CjsRequireDependency is not like EsmSideEffectDependency, it can have side effect and likely to consume the result. We cannot safely remove this connection.
There was a problem hiding this comment.
What about just require('./foo.css')? Technically we can remove empty JS modules here too
There was a problem hiding this comment.
Yes, but we can't do the same for require using the solution of this PR
SideEffectDependency means connection and executing side effect, we can know css has no side effect so we can remove SideEffectDependency.
If exports is used, there is SideEffectDependency and SpecifierDependency, so we can know it's exports are used
If exports is not used, there is only SideEffectDependency, so we can know it's exports are not used
But RequireDependency means connection and has access the exports, we can't know if the importer uses exports or not. Whether exports are used or not can not be told just by dependencies.
You can see there is no difference.
There was a problem hiding this comment.
How about reading exportsType info ? Seems a way, I'll check if that's doable without affecting performance.
There was a problem hiding this comment.
@JSerFeng I am fine with only for import, just think how we can solve it more common way (discussion, no more)
How about reading exportsType info ? Seems a way, I'll check if that's doable without affecting performance.
Feel free to experiments 👍
There was a problem hiding this comment.
I tried, but unfortunately we can't tell if exports are used or not from exports info.
require('style.css')FlagDependencyUsagePlugin doesn't analyze above syntax, even with __esModule.
I originally want to try removing js when CssModule has exportType === 'link' && !buildInfo.isCssModule, but that would break users who use if (require('./style.css') === undefined) {})
There was a problem hiding this comment.
@JSerFeng PR looks good, let's resolve it, I still think we can move logic to HarmonyImportSideEffectDependency.apply and avoid stage here, so we will have the only one HarmonyImportSideEffectDependencyTemplate
There was a problem hiding this comment.
Got it, done.
I was thinking that HarmonyImportSideEffectDependency should only render when ref module's sourceType is JavaScript. But it seems other sourceType need it too, like ConsumeShared or Remote or Runtime.
So now don't render if only all sourceType is Css.
889a09a to
958ec76
Compare
🦋 Changeset detectedLatest commit: 1ed3fa0 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
21e8c42 to
b4a3363
Compare
lib/css/CssGenerator.js
Outdated
| // when no hmr required, css module js output contains no sideEffects at all | ||
| // js sideeffect connection doesn't require js type output | ||
| if ( | ||
| module.hot !== true && |
There was a problem hiding this comment.
It seems we can remove the module.hot !== true line.
Since we no longer generate JS code for import "./index.css", it doesn’t exist in the output __webpack_modules__, Its behavior is closer to being self-accepted. Then will skip generating the side-effect hmrCode for it.
|
@JSerFeng And let's rebase, we made more optimizations, but this will be useful too, thanks |
a16a587 to
a52f09d
Compare
| "B-2Index": "0: ./B-2.js", | ||
| BIndex: "0: ./B.js", | ||
| mainIndex: "0: ./main.js", | ||
| sharedIndex: "1: css ./m.css" |
There was a problem hiding this comment.
don't know why there is no ./n.css in previous version, seems it should be here
There was a problem hiding this comment.
No issues with the test case changes here, ./n.css got concatenated earlier.
| data[`${name}Index`] = text; | ||
| } | ||
| expect(data).toEqual({ | ||
| dynamicIndex: "0: css ./a.css", |
|
@JSerFeng Oh, sorry, forgot about this PR, can you rebase and we will merge, thank you |
a52f09d to
1ed3fa0
Compare
|
This PR is packaged and the instant preview is available (e43fcd0). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@e43fcd0
yarn add -D webpack@https://pkg.pr.new/webpack@e43fcd0
pnpm add -D webpack@https://pkg.pr.new/webpack@e43fcd0 |
Summary
See https://github.com/orgs/webpack/discussions/20161
What kind of change does this PR introduce?
Did you add tests for your changes?
Does this PR introduce a breaking change?
If relevant, what needs to be documented once your changes are merged or what have you already documented?