vue-loader icon indicating copy to clipboard operation
vue-loader copied to clipboard

css modules "composes: <style> from <file>" does not work with .vue files

Open nemtsov opened this issue 8 years ago • 4 comments

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

nemtsov avatar Nov 28 '16 18:11 nemtsov

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.

trainiac avatar Feb 22 '17 22:02 trainiac

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.

acierto avatar Mar 01 '18 23:03 acierto

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.

srus avatar Aug 31 '18 12:08 srus

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: image Although this can be fixed with mini-css-extract-plugin and css-minimizer-webpack-plugin.

VadymGidulian avatar Aug 04 '21 18:08 VadymGidulian