Reputation: 1363
I'm trying to make use of the @extend
of sass so that I don't mix markup and html together. As explained in this article.
In short, instead of writing
<div class="alert alert-primary>This is an alert!</div>
You'd instead write something like
<div class="banner">This is an alert!</div>
.banner {
@extend .alert;
@extend .alert-primary;
}
Such that styling and content stay nicely separated.
The problem: When using this with webpack (sass-loader) and components (e.g. Vue.js or Angular), I run into a problem where including a bootstrap partial will now result in the complete compilation of the entire bootstrap file into css.
This results into a class .btn[data-v-3614b62c]
and another .btn[data-v-45ac961c]
etc. for every component that uses the partial bootstrap/scss/_buttons.scss
and that for all classes defined in that partial.
Even if I don't use it.
In the long run, this will be detrimental for the application since its size will increase rapidly and I image the browser will slow down with that many css classes to parse.
The question(s): How do I make sure sass doesn't duplicate the entire imported partial? Can I enable some kind of tree shaking where it only includes the classes I use? Do I have to change my file structure so that sass understands I only need certain classes inside the partial rather than everything?
This is a vue component using bootstrap
<template>
<form class="form">
<input type="text" class="input">
<button class="button-submit">Send</button>
<button class="button-cancel">Cancel</button>
</form>
</template>
<style lang="scss" scoped>
@import "node_modules/bootstrap/scss/functions";
@import "node_modules/bootstrap/scss/variables";
@import "node_modules/bootstrap/scss/mixins";
@import "node_modules/bootstrap/scss/root";
@import "node_modules/bootstrap/scss/buttons";
.form {
.button-submit {
@extend .btn;
@extend .btn-primary;
}
.button-cancel {
@extend .btn;
@extend .btn-danger;
}
}
</style>
This will result in the entire partial _buttons.scss
to be compiled into css instead of only .form .button-submit
and .form .button-cancel
.
https://codesandbox.io/embed/musing-feynman-8w2kx.
To see the problem I have:
style
elements[data-v-######]
attribute is different and at the end are my couple of lines code.Note that the same happens for production builds. The css is then simply bundled up in a single file, but duplicates are still around.
Upvotes: 5
Views: 3654
Reputation: 34286
If you are @import
ing the same CSS rules into different components, then you will get the same rules duplicated across all modules. That's just how it works.
You should only be @import
ing modules that define abstract declarations like variables, mixins, functions, etc, not actual styles.
The only way you can de-duplicate the styles globally is if you use something like mini-css-extract-plugin to extract and combine all the CSS into a single file and then run it through something like cssnano which will discard duplicate rules (although with scoped CSS, this probably won't work).
Modules are typically built independently of other modules and there isn't a simple way to know if a rule has been declared already by a previous module. In development you may be using style-loader which operates on a per-module basis and injects styles into the webpage on demand; there's just no way it can work out which styles should be injected in case some particular style has already been injected by another component.
It just gets messy; keep it simple by not duplicating styles in the first place.
If you really want to use @extend
, then make a separate .scss
file which is the only module that @import
s the bootstrap styles, and define all your extensions in there.
Upvotes: 5