feat(css-modules): added multiple modules support; re-write tests & add more css module scenarios #2045
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hello,
The issue was first posted in CSS-Loader webpack-contrib/css-loader#1518 as I wasn't sure if was a css-loader issue or a vue-loader issue. After very helpful assistance from Alex and upon further investigation, the issue lies in how vue-loader imports each file's style tags.
You can read my post in the link above, and also see my PoC for various test cases https://github.com/RaphaelDDL/vue3-css-module (and ofcourse, the PR where I added most of the cases as fixtures + tests)
To try sum up, in vue-loader documentation there's an entry for CSS Module regarding Custom Inject Name:
This and different does NOT work in a few scenarios. In this specific scenario of a and b, it only works if each module has it's own classes, e.g.
module=a
has class.a
andmodule=b
has class.b
. If both contain class.c
, instead of havinga.c
andb.c
as two different styles, they both end up with same name, same hash, generate same css and overwrite each other in the browser. Discussing below I'll go through this scenario in the test "multiple named modules (different module names, same class name)
".The module issues
The main gist is that even though styleLoader loops through each style correctly, and giving the data correctly to
genCSSModulesCode
, each loop will overwrite the last css module class hashmap depending on the setup. This way, only the LAST style actually contains it's classes added to$style
(or your name of choice for namedmodule="something"
).Upon further investigation, unfortunately there's no test which would highlight these issues. The current test contains one scenario which is (named)+(nameless scoped) (file tested: https://github.com/vuejs/vue-loader/blob/main/test/fixtures/css-modules.vue and test itself: https://github.com/vuejs/vue-loader/blob/main/test/style.spec.ts#L127-L151 )
With my new suite of test scenarios, here's the current test results with no code changes:
Here's with my fix in cssModules.ts:
Pending issues
You'll see there are 3 cases which still are broken. So of course, the CI run will fail, as those 3 fail LOL. That's because I'm not entirely sure on where to fix those scenarios and I would love to get your input on how to fix those as well.
I left the comment in each test, and I'll discuss here as well:
In this scenario, as mentioned prior, classes created have same name+hash as hash not taking module name into account, therefore by having same class names in different modules, each module gets same hash. According to Alex in the css-loader, vue-loader needs to pass it to css-loader too for the hash to be properly done. He mention something regarding vue-loader not using css-loader's specific
!=!
syntax for that.An example on how the request path is built with current code:
extend is adding both classes to style tags in document but instance.$style.red className points to the file's original style (hexcolor)
(a677feb62ef42886b712f1b16b71e851-vue) and not the extended version (red keyword)
e.g.
I would expect that when extending with same class names, the extension would overwrite? Or my assumption is incorrect?
Styles for both own file's style tag and the extended file are being added to style tags in document BUT instance.$style has not received the
red
in the hashmap soinstance.$style.red
does't existI am also not sure if my assumption is correct, but extending using
extends
from anoyher vue I would expect that the extended vue's styles would be now available in the locals/$style
.Extra changes
I also included a few fixes which were present in the original CSS Module tests and that I also used in my new ones:
\w{5}
for the customlocalIdentName
which includes a short hash[hash:base64:5]
is incomplete. The hash can also include-
and+
, which are not included in the\w
keyword, e.g. Expected:/^red-\w{5}
, received:red_-euaf
andred--pnf+t
/^\w{21,}/
and was fixed to/^[\w-+]{21,}/
textContent
, some styles are being scaped, specially the ones with=
in the hash. Example: Expected class name:.AB2VVFkhhj-I4oTbd0Gcsw==
, received:.AB2VVFkhhj-I4oTbd0Gcsw\\=\\=
. So I added anormalizeEscapedHash
in utils in order to match classNames with style contents correctly in tests.--
The reasoning behind having more than one module is explained in the css-loader issue, though even without our specific extra
brand
attribute, the module as is does have issues, as the test suite shows using the vue-loader's docs example as prior mentioned.I hope you consider evaluating my changes and help with the 3 remaining tests.
I'm available for any questions.
Thank you