Imported CSS still available in child components - vue.js

I imported SCSS files in my root component while using scoped:
<style lang="scss" scoped>
#use "#/styles/_variables";
#use "#/styles/layout/_borders";
#use "#/styles/components/_buttons";
#use "#/styles/components/_customdropdown";
#use "#/styles/base/_typography";
#use "#/styles/base/_backgrounds";
#use "#/styles/_loader.scss";
So I expect the CSS not being available in child components cause styles should be encapsulated and not inherited to these children. But using classes from those files still works and are taking effect. Can someone explain this behavior?

Related

Is there any way to find css in vue.js project?

<nav class="left-side">
this is my HTML tag. But on browse, I am getting
<nav v-d-asd0fd class="left-side">
can anybody tell from where does v-d-asd0fd generates? This same thing is also applied in CSS .plese help to find this
When Webpack processes your project it's "Scoping" the CSS. Basically it means that each component's classes are unique to that component and can't fight with other classes. So you could have left-side in different components with different styles.
Vue CSS Scope documentation.
You can change it by removing the word scoped from your Style tag
<style scoped> to <style>

Dynamic Import Scoped SCSS

I have a VueJS project that has a base component that can be styled differently depending n server config. Right now I am loading CSS from the server but I was wondering if it is possible to import scoped scss in vuejs dynamically. i.e
<style src="{{style_name_or_path}}" lang="scss" scoped/>
I think it's not possible to load dynamic styles that way. I'd suggest you to use CSS Variables to handle different styles.

Including partials in components results in duplicate css

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?
Code example
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.
Live example
https://codesandbox.io/embed/musing-feynman-8w2kx.
To see the problem I have:
Right click on the example to the right and click Inspect
In the Elements tab, navigate to #document > html > head
At the bottom you'll have several style elements
Two of them will contain all the button css where only the [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.
If you are #importing 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 #importing 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 #imports the bootstrap styles, and define all your extensions in there.

"Scoped" make scss files and code not working on single vue component

I'm working on a big Vue project includes a lot of components and my problem is that am trying to include some scss files to make them work in a specific component or specific rout tree (like call it on parent component so it will affect the child's) any way to apply that i use lang="scss" scoped but unfortunately i found that the code not worked and all styles destroyed and when i remove "Scoped", it works fine but the styles affect another components and i don't want this happened so this is my way to include files
<style lang="scss" scoped>
#import "assets/styles/vl.vendor.scss";
#import "assets/styles/vl.scss";
</style>
I've tried all solutions on stackoverflow but no one worked for me.
Thanks
<style lang="scss" src="assets/styles/vl.vendor.scss" scoped></style>
<style lang="scss" src="assets/styles/vl.scss" scoped></style>
If it still doesn't work, it might be because paths don't resolve correctly. You might have to use src="/assets/styles/..." or src="../assets/styles/...", depending on how paths resolve in your app.

How to make vue-loader process the same block multiple times, using different loaders

UPDATE
Additional details can be found in the Nuxt feature request that I created.
ORIGINAL QUESTION:
I'm using Nuxt to build a pattern library app. My goal is to display the uncompiled SASS beside each rendered component, like this:
Public-facing .html page:
<div class="my-component"></div>
<pre>
<code>
#import "assets/stylesheets/colors";
.my-component {
color: $some-color;
}
</code>
</pre>
Following this example, I was able to create a custom <docs> language block:
.vue file:
<docs>
#import "assets/stylesheets/colors";
...
</docs>
<style lang="scss">
#import "assets/stylesheets/colors";
...
</style>
This works, but it forces me to duplicate my code. It would be much better if I could eliminate the <docs> block and process the <style> block twice, using two different loaders. Unfortunately, I haven't found a way to do this.
I tried the following, hoping that vue-loader would process both the <docs> block and the <style> block, but only the <docs> block is being processed (probably because the <style> block is nested?), so my SCSS is no longer being compiled and injected into the page:
.vue file:
<docs>
<style lang="scss">
#import "assets/stylesheets/colors";
...
</style>
</docs>
I'm using Nuxt Edge, which includes Webpack 4 and Vue Loader 15.
After reading though the Vue Loader code and hacking around, I don't think it's possible to run a single block through multiple sets of loaders (please correct me if I'm wrong). Nevertheless, I was able to find an adequate solution to my problem:
I ended up using Copy Webpack Plugin to duplicate my .vue files and save them with a .txt extension. I then request them via Axios (on the client side), or use FS to read them from the file system (on the server side). I then extract the <style> and <script> blocks via regex. This isn't ideal, but it works.
You can try seperate css into seperate files like this:
<docs src="/the/path/component.scss"></docs>
<style src="/the/path/component.scss"></styles>
then write a loader to read the file's content and render it.