I've noticed that if I want to use my _variables.scss I have to import them in every Vue file. My question is, how can I check if I load the same styles multiple times or does Vue saves only once the same scss files on compiling?
This is my code in multiple view files.
<style lang="scss" scoped> #import '~#/abstracts/_variables.scss'; #import '~#/pages/_profile.scss'; </style>
I import _variables.scss in every view where I want to use my scss variables.
This depends on how you have your project setup, for example if you're using webpack you can do something like this where you have your CSS loaders setup:
scss: generateLoaders('sass', {
additionalData: `
#import "#/styles/_variables.scss"
`,
}),
Or if you have a vue.config.js you can do this:
module.exports = {
css: {
loaderOptions: {
sass: {
additionalData: `
#import "#/assets/scss/main.scss"
`
}
}
}
}
Then you will have access to this global SCSS file everywhere in your Vue application.
Side note on the additionalData portion - that will depend on the version of sass loader you're using:
For ^7.x.x use data, and for ^8.0.2 use prependData, finally for 9.0.0+ use additionalData
Related
I'm working on building a webpage using Vue, Typescript, Webpack, and Bulma. I got everything working and building correctly but I noticed that some of my bundles were massive (over 2mb in some cases). After a lot of confusion I figured out it was because I was importing my main SCCS file that included Bulma, Bulma Fluent, and Material Design Icons into my components so that I could use the variables, mixins, and extend some of the classes. From what I understand #import simply copies everything from the import, which would explain my massive bundles.
A close approximation of my working code:
main.scss
/*Color customizations*/
#import "bulma-fluent/bulma.sass";
#import "buefy/src/scss/buefy";
#import "#mdi/font/scss/materialdesignicons";
/*Some custom classes*/
MyComponent.vue
/*Template and Script here*/
<style scoped lang="scss">
#import "./main.scss";
.floating {
#extend .m-1;
position: fixed;
bottom: 0;
right: 0;
}
#include mobile {
.floating {
max-width: unset;
left: 0;
}
}
</style>
I want to be able to reference classes/variables/mixins from my main.scss without it ballooning the size of my modules. I thought about creating a separate variables.sass file but I couldn't get that to work plus it doesn't fix the issue of extending styles. I saw this question but I'm not using Nuxt.
How can I get this working?
P.S. I'm a bit of a noob when it comes to Webpack/Vue/SASS/SCSS so I apologize if I'm just being dumb here.
Edit
In the end I split out the variables to their own file and imported those globally. It doesn't solve the use case of extending styles but I think that's a lost cause. My code is below:
Variables.scss
/*Customization here*/
#import "bulma/sass/utilities/functions.sass";
#import "bulma-fluent/src/sass/color/_all.sass";
#import "bulma/sass/utilities/initial-variables.sass";
#import "bulma/sass/utilities/derived-variables.sass";
#import "bulma/sass/utilities/mixins.sass";
Main.scss
#import "./Variables.scss";
#import "bulma-fluent/bulma.sass";
#import "buefy/src/scss/buefy";
#import "#mdi/font/scss/materialdesignicons";
/*Some custom classes*/
webpack.js
/*Other irrelevant configurations*/
{
test: /\.s[ac]ss$/,
use: [
"vue-style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
additionalData: `
#import "./Variables.scss";
`
}
}
]
},
MyComponent.vue
/*Template and Script here*/
<style scoped lang="scss">
.floating {
margin: $size-1;
position: fixed;
bottom: 0;
right: 0;
}
#include mobile {
.floating {
max-width: unset;
left: 0;
}
}
</style>
I use the same stack. I have variables.scss file with variables and bulma mixins and that variables.scss file is imported only in main.scss .
To make all variables and mixins available in all components without using #import in style section you should add loaderOptions section to vue.config.js file. Here is my vue.config.js file:
module.exports = {
css: {
loaderOptions: {
scss: {
prependData: '#import "~#/assets/scss/_variables.scss";'
}
}
}
}
I would like to use some of the existing Vuetify classes in my own sass file, but I can't seem to figure out how to do it. I have a Vue-CLI3 project with the latest Vue/Vuetify, and have the following code:
main.sass
#import '~vuetify/src/styles/styles.sass'
.myTest
#extend .mr-1
#extend .shrink
I also have the vue.config.js setup to correctly reference the sass/scss files:
export default {
css: {
loaderOptions: {
sass: {
data: `#import "path/to/main.sass"`
},
scss: {
data: `#import "path/to/main.scss";`
},
}
}
}
When I compile, I get The target selector was not found, and it points to .mr-1 and .shrink. Am I doing this incorrectly?
All other CSS in my main.sass file works as expected, so I believe the wiring is correct.
It seems the spacing helper classes (including .mr-1) are only found when importing vuetify/src/styles/main.sass instead of styles.sass. The .shrink class is found in vuetify/src/components/VGrid/_grid.sass.
So your main.sass should look like this:
#import '~vuetify/src/styles/main.sass'
#import '~vuetify/src/components/VGrid/_grid.sass' // for .shrink
.myTest
#extend .mr-1
#extend .shrink
sass-loader config
The original question is probably using an older version of sass-loader, given the sass.data config. If using version 8 or newer, the loader option is sass.additionalData:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
sass: {
// sass-loader >= 8
additionalData: `#import "~#/path/to/main.sass"`
// sass-loader < 8
data: `#import "~#/path/to/main.sass"`
}
}
},
}
Prepending global styles
With the sass-loader config above, importing vuetify/src/styles/main.sass in your project's root main.sass (as done in the original question) causes an error. The workaround is to copy the contents of Vuetify's main.sass into your own. However, if your app uses any Vuetify components, you'll see the same error for _grid.sass, and the same workaround applies:
// #import '~vuetify/src/styles/main.sass' ❌ SassError: This file is already being loaded.
#import '~vuetify/src/styles/tools/_index'
#import '~vuetify/src/styles/settings/_index'
#import '~vuetify/src/styles/generic/_index'
#import '~vuetify/src/styles/elements/_index'
#import '~vuetify/src/styles/utilities/_index'
// #import '~vuetify/src/components/VGrid/_grid.sass' ❌ SassError: This file is already being loaded.
.shrink
flex-grow: 0 !important
flex-shrink: 1 !important
.myTest
#extend .mr-1
#extend .shrink
This approach gets unwieldy the more you need to extend the component-specific styles.
Also, since this prepends the contents of your main.sass to all Sass entry points, you may notice a significant delay in build/dev times (hampering developer experience), and a sizable vendor CSS chunk in your build output.
Better alternatives
You could avoid the caveats above by importing your main.sass in main.js:
import '#/main.sass'
demo 1
On the other hand, if you only need these styles in a specific component, use local styles instead:
<script>
import '#/main.sass'
</script>
demo 2
<!-- or -->
<style lang="sass">
#import '~#/main.sass'
</style>
demo 3
<!-- or -->
<style lang="sass">
#import '~vuetify/src/styles/main.sass'
#import '~vuetify/src/components/VGrid/_grid.sass' // for .shrink
.myTest
#extend .mr-1
#extend .shrink
</style>
demo 4
So, I achieved to do it thanks to Vue CLI and some documentation. Here is my github repo, here is the codesandbox.
Basically, the setting was as follows:
// src/plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'
Vue.use(Vuetify)
export default new Vuetify({
theme: {
options: { customProperties: true }, // interesting part
},
})
I'm not sure about the vue.config.js nor the webpack.config.js configurations since it also depends on your versions of node-sass and sass-loader but you said that you handled it well by yourself, so no big worries I guess.
I made the example in the App.vue file in which I wrote
<div id="priority" class="medium">hello, this is working !</div>
There is a global.sass file that will target it's div tag and apply color: var(--v-warning-base).
There is a global.scss file that will target it's .medium class and apply color: var(--v-accent-base).
Finally, the component itself will target it's #priority id and apply color: var(--v-error-base).
I found the answer thanks to this post, give it a thumbs up too !
I tried to follow this tutorial to get access to a global file called variables.scss in all SFC files:
https://vueschool.io/articles/vuejs-tutorials/globally-load-sass-into-your-vue-js-applications/
My project uses vue cli 3, so I added the following property to vue.config.js:
{
css: {
loaderOptions: {
sass: {
data: `#import "src/assets/scss/variables.scss";`
}
}
},
}
the variables.scss file looks like this:
// variables.scss
$purple: #5D2D8B;
My component style looks like this:
<!-- Datepicker.vue -->
<style lang="scss" scoped>
.picker {
color: $purple!important;
}
</style>
But I got this error when trying to use the $purple variable
color: $purple!important;
^
Undefined variable: "$purple"
I've also tried to add style-resources-loader vue-cli plugin, but got the same error.
(added this when tried to use it):
{
pluginOptions: {
'style-resources-loader': {
preProcessor: 'scss',
patterns: [
path.resolve(__dirname, 'src/assets/scss/variables.scss')
]
}
}
}
It seems that on .vue files the #import statement is not applied, but in .scss files it is.
Anyone has an idea what is that about?
For example, if I have something like this in my component:
<style lang="scss" scoped>
.color-blue {
color: blue;
}
.orange-blue {
#extend .color-blue; // This works!
#extend .bg-orange; // .bg-orange is defined in another css file somewhere. This doens't work
}
</style>
I get an error that says
".orange-blue" failed to #extend ".bg-orange".
The selector ".bg-orange" was not found.
I've read that I can add
#import 'path/to/orange.css'
to my style block, but that doesn't seem to do the trick here. Also, wouldn't that result in the CSS being repeated for every component that imports it?
Import the file with other styles like that
<style lang="scss" scoped>
#import '~styles/mixins';
...
</style>
or use the usual path
#import '../../../styles/mixins';
You can do it the following way:
Create the file containing the class you want to extend:
src/styles/style.scss
.my_class_to_extend {
backgroud-color: aqua;
}
In your vue.config.js file you add the following pointing to your file:
module.exports = {
css: {
loaderOptions: {
sass: {
data: `#import "#/styles/style.scss";`
}
}
}
}
After that you can extend in your vue component without problems:
...
<style lang="scss" scoped>
.my_extended_class {
#extend .my_class_to_extend;
}
Note that to use that you need scss files all along, not css.
In short, you can not extend css class in *.scss file by importing plain *.css file. Scss compiler will throw an error SassError: The target selector was not found.
The easy way is to rename referenced *.css file to *.scss. So outcome would be like #import 'path/to/orange.scss'
I'm searching how to inject a global (THEME_NAME in my example) to all the vue components:
<template>..</template>
<style lang="scss">
#import "bulmaswatch/<%=THEME_NAME=>/bulmaswatch.scss";
.foo {
color: $primary;
}
</style>
Context:
I'm using the darkly theme of bulma css in my vue application (vue Cli 3)
<template>..</template>
<style lang="scss">
#import "bulmaswatch/darkly/bulmaswatch.scss";
.foo {
color: $primary;
}
</style>
In order to switch to the cyborg theme, I will have to replace darkly with cyborg everywhere...
Is there a better way? Something like
<template>..</template>
<style lang="scss">
#import "bulmaswatch/<%=THEME_NAME=>/bulmaswatch.scss";
.foo {
color: $primary;
}
</style>
then somewhere in Webpack or vue.config.js, we can decide what is the theme
configureWebpack: () => {
return {
plugins: [
new webpack.DefinePlugin({
THEME_NAME: "cyborg"
}),
],
}
}
In order to switch to the cyborg theme, I will have to replace darkly with cyborg everywhere...
Not if you use the re-export pattern.
There's no need for any external libraries and codegen magics with webpack.
Basically, you create a file where you import your theme.
Let's call it _my-bulma-theme.scss and let's import darkly for now.
// _my-bulma-theme.scss
#import "bulmaswatch/darkly/bulmaswatch.scss";
In your code, you import this file instead of importing from Bulma directly:
// some-component.vue
<style>
#import "../../my-bulma-theme";
</style>
// some-other-component.vue
<style>
#import "../../my-bulma-theme";
</style>
Now, when you want to change the theme, you just need to change it in one place: the _my-bulma-theme.scss file.
// _my-bulma-theme.scss
#import "bulmaswatch/cyborg/bulmaswatch.scss";