tl;dr: How to automatically import some .scss
files with global styles into both other .scss
files as well as into Vue's Single File Components?
I have a Vue project configured to automatically import some global styles:
// vue.config.js
module.exports = {
// Automatically import global styles:
css: {
loaderOptions: {
scss: {
prependData: `
@use "@/global/styles/_Colors.scss";
@use "@/global/styles/_Mixins.scss";
`
}
}
}
}
This works perfectly for automatically importing my global styles with @use into every Single File Component:
<!-- Component.vue -->
<template>...</template>
<style lang="scss">
.hero {
background: Colors.$primary; // _Colors.scss was automatically imported with @use!
}
</style>
But, it doesn't work if I define my component styles in a separate file, and then import that file into the component, like this:
// ComponentStyles.scss
.hero {
background: Colors.$primary; // Error! "There's no module with the namespace "Colors"
}
<!-- Component.vue -->
<template>...</template>
<style lang="scss">
@use "./ComponentStyles";
</style>
I've tried using the style-resources-loader
plugin following the sample configuration in the Vue docs for Automatic Imports, like this:
// vue.config.js
const path = require('path')
module.exports = {
chainWebpack: config => {
const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
types.forEach(type => addStyleResource(config.module.rule('scss').oneOf(type)))
},
}
function addStyleResource (rule) {
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [
path.resolve(__dirname, './src/global/styles/_Colors.scss'),
path.resolve(__dirname, './src/global/styles/_Mixins.scss')
],
})
}
And it worked. Kind of. I now had access to my global styles even inside .scss
files (not just in SFCs). But, a new error emerged. Importing my local component styles with @use
inside a Vue component no longer works.
<!-- Component.vue -->
<template>...</template>
<style lang="scss">
@use "./ComponentStyles";
// Error! @use rules must be written before any other rules.
</style>
I guess that, in the second approach, the style-resources-loader
plugin is using @import
rules or dumping the content of my global styles above my local @use
rules in SFCs. That would result in the error I saw, but I couldn't find any option to control that.
I want to be able to automatically prepend the .scss
files I import into my SFCs with @use
rules that expose my global styles to those files (much like the loaderOptions
property in vue.config.js
from my first approach allowed me to do in SFCs). I want to keep my SFCs as clean as possible, and that's why I prefer to have my component styles broken down into separate files.
So, is there any way to automatically import some .scss
files into both Vue's Single File Components and into other .scss
files with @use
rules?
Thank you in advance for any help.
I managed to:
.scss
or .sass
files.The only slight annoyance is that I have to manually import my global styles into Sass files (they're only automatically imported into Vue components). But, the setup I'm using supports aliases, so I don't need to worry about constructing relative paths or updating my import statements if I move my styling files. Also, unlike my previous setup, the new one has full support for the latest @use
syntax.
Note: I'm now using Vite instead of the Vue Cli.
Note 2: I made a [minimal repo][1] in case you prefer to explore a more detailed demonstration of how to set this up.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// Config Docs: https://vitejs.dev/config/#css-preprocessoroptions
css: {
// make global variables and mixins available in all Vue components:
preprocessorOptions: {
sass: {
additionalData: `
@use './src/global/Index' as GlobalStyles
`
// ...I chose to merge all my GlobalStyles into one single scope here,
// but you can also import them individually.
}
//...you can change the key above from 'sass' to 'scss' if you use scss in
// your Vue components. You could also repeat the same settings for both if
// you alternate between sass and scss in your components. Note that this
// distinction is not needed for the ".sass" or ".scss"" files you import into your
// Vue components. Those are handled by the alias resolver below, which will work
// regardless of the Sass file extension you use.
}
},
resolve: {
alias: [
{
// This will help us use our global styles from regular sass files:
find: '@styles',
replacement: path.resolve(__dirname, 'src/global/Index')
}
]
}
})
// Colors.sass
$aquamarine: hsl(160, 100%, 75%)
$deepSlateGray: hsl(160, 25%, 5%)
$faintAqua: hsla(160, 100%, 95%, 0.25)
// Mixins.sass
@mixin useCenteredFlex($direction)
display: flex
flex-direction: $direction
justify-content: center
align-items: center
Note: This is in the same directory as Colors.sass
and Mixins.sass
, and is the file I'm automatically importing into all Vue components and matching the @style
alias to.
// Index.sass
@forward 'Colors'
@forward 'Mixins'
<template>...</template>
<style lang="sass">
body
@include GlobalStyles.useCenteredFlex(column) // <- using a globally available mixin
background-color: GlobalStyles.$deepSlateGray // <- using a globally available variable
</style>
// Here we need to reference the alias we set up in vite.config.js to access our GlobalStyles
@use '@styles' as GlobalStyles
h1
color: GlobalStyles.$aquamarine // <- using a global variable
[1]: https://github.com/mareszhar/demo-asiivwv-so
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With