vue-loader
vue-loader copied to clipboard
css modules "composes: <style> from <file>" does not work with .vue files
I'd like to use CSSModules
via vue-loader
to compose styles from another component.
❗️ The following currently fails with an error:
GrandChild.vue
<style module>
.message {
padding: 10px;
border: 2px dashed #ccc;
}
</style>
Parent.vue
<style module>
.message {
composes: message from './GrandChild.vue';
padding: 100px;
}
</style>
Error:
ERROR in ./~/css-loader!./src/components/GrandChild.vue
Module build failed: Unknown word (22:1)
20 | border: 2px dashed #ccc;
21 | }
> 22 | </style>
| ^
23 |
✅ The code below works, but requires the CSS to be exacted from my component (which is undesirable for me):
GrandChild.css
.message {
padding: 10px;
border: 2px dashed #ccc;
}
Parent.vue
<style module>
.message {
composes: message from './GrandChild.css';
padding: 100px;
}
</style>
Simple project to reproduce the issue:
https://github.com/nemtsov/vue-style-experiments/blob/6309e9ee8211746900e80c392012b3069a8b131a/src/components/Parent.vue#L22
Without knowing too much about the goal here, IMO this is an anti-pattern (disclaimer: I'm just some guy and not related to the vue team).
A great advantage of component based development is that I know that if I make edits to the template, js or styles of a given component it will not directly affect any other part of the codebase. This gives developers a great amount of confidence to change component specific code however they please.
If you need to share styles between components this should be separated out into a separate file because it isn't component specific. Then when making changes to that file you will have to review what files depend on it.
That's how composition works https://github.com/css-modules/css-modules#composing-from-other-files Otherwise it would be really a lot of code duplication.
Not sure only that it is a good idea to get a styles from another component, I would see it keeping in some *.css files, which can contain such composable selectors.
So your example #2 is how it should really work, only the naming for css file preferrably to have neutral, not keeping a relation to any component.
I agree that composing from another module is not convenient.
Related to this, is there any way to use composes
with non-CSS files like Sass, Stylus, Less, etc?
<style lang="stylus" module>
.foo
composes bar from '@/assets/css/base.styl'
</style>
At the moment it only works with plain CSS files.
It is possible to work around the problem by using inline loaders:
// @/components/base-button.vue
<style lang="less" module>
@import "@/styles/const"; // Add `.less` to `resolve.extensions` in `webpack.config.js`
// @import "@/styles/const.less"; // or specify the extension manually
.button {
...
}
</style>
// @/components/base-link.vue
<style lang="less" module>
.link {
composes: button from "less-loader!vue-loader!@/components/base-button.vue?type=style&index=0";
}
</style>
Also, it is possible to extract the styles into a separate file and import from it:
// @/components/base-button.vue
<style src="./base-button.less" lang="less" module></style>
// @/components/base-link.vue
<style lang="less" module>
.link {
composes: button from "less-loader!@/components/base-button.less";
}
</style>
The drawback of both approaches is that the styles are duplicated in the resulting bundle:
Although this can be fixed with
mini-css-extract-plugin
and css-minimizer-webpack-plugin
.