I have Vuetify 2.2.11 and I'm trying to override their SASS variables. I'm in a Symfony 3.x project so I didn't install Vuetify with the vue-cli. I followed the Webpack install guide but I can't seem to make it work. The Vuetify styles get dumped to a css file (which is named after my js: app.js
-> app.css
) but my overrides are not taken into account. As for my project styles (company.scss
), they are injected in a <style type="text/css">
tag in the html. There is also a huge bunch of empty <style type="text/css"></style>
tags, which I guess are coming from every Vuetify component but I don't know why they're empty.
This is what my code looks like:
// /assets/js/app.js
import Vue from 'vue';
import vuetify from './plugins/Vuetify';
import FooComponent from './components/FooComponent;
import '../styles/company.scss';
const vmConfig = {
el: '#app',
vuetify,
components: {
FooComponent
},
};
new Vue(vmConfig);
// /assets/js/plugins/Vuetify
import Vue from 'vue';
// We import from "lib" to enable the "a-la-carte" installation.
// But even tough we use vuetify-loader we still need to manually specify VApp because it's used in a twig template and the loader doesn't read it.
import Vuetify, { VApp } from 'vuetify/lib';
Vue.use(Vuetify, {
components: {
VApp
}
});
export default new Vuetify({
icons: { iconfont: 'md' }
});
/* /assets/styles/variables.scss */
$font-size-root: 30px;
$body-font-family: 'Times New Roman';
@import '~vuetify/src/styles/styles.sass';
/*@import '~vuetify/src/styles/settings/variables'; // I tried this one instead and it didn't work either*/
/* /assets/styles/company.scss */
#foo-component {
background-color: pink;
}
{# /app/Resources/views/app.html.twig #}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" media="all" href="{{ asset("build/app.css") }}" />
</head>
<body>
<div id="app">
<v-app>
{% block main %}
<h1>My page</h1>
<foo-component></foo-component>
{% endblock %}
</v-app>
</div>
{% block footer_js %}
<script type="text/javascript" src="{{ asset("build/app.js") }}"></script>
{% endblock %}
</body>
</html>
// webpack.config.js
const Encore = require('@symfony/webpack-encore');
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');
const webpack = require('webpack');
let path = require('path');
Encore
.setOutputPath('web/build/')
.setPublicPath('/build')
.addEntry('app', './assets/js/app.js')
.disableSingleRuntimeChunk()
.enableVueLoader()
.addPlugin(new VuetifyLoaderPlugin())
.enableSassLoader()
.addAliases({
'vue$': 'vue/dist/vue.esm.js'
})
.configureBabel(null, {
includeNodeModules: ['debug', 'vuetify'] // to make it work in IE11
})
.configureLoaderRule('sass', loaderRule => {
loaderRule.test = /\.sass$/;
loaderRule.use = [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
data: "@import '" + path.resolve(__dirname, 'assets/styles/variables.scss') + "'",
implementation: require('sass'),
fiber: require('fibers'),
indentedSyntax: true
}
}
];
})
;
let config = Encore.getWebpackConfig();
config.module.rules.push({
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
data: "@import '" + path.resolve(__dirname, 'assets/styles/variables.scss') + "';",
implementation: require('sass'),
fiber: require('fibers'),
indentedSyntax: false
},
},
]
});
module.exports = config;
Okay, I finally got it to work. Here is how:
webpack.config.js
:All you need to do here is to .enableSassLoader()
. The config options described here where actually loading but variable declaration had no effect.
app.js
Just include your styles as such:
import '../styles/company.scss';
variables.scss
I've created this file and moved all vuetify specific variables there. You can use the official example.
company.scss
This is the trick:
@import './assets/css/variables.scss';
@import '~vuetify/src/styles/main.sass'; // include this after your variables
And thats it.
I've noticed that hot reloading doesn't work with changes to variables. But that's fine as long as these variables work. I got the hint from this page about the color pack
ferdynator's solution is nice and clean, but in my case that would only let me a override a few variables. For me it had no effect on variables used in components.
Utimately you may still need to have your variables.scss
appended like documented in https://vuetifyjs.com/en/features/sass-variables/#webpack-install
Doing this with Webpack Encore can be quite confusing: because of .enableSassLoader()
there's already a rule for /\.s[c|a]ss$/
that you not want to mess with (unless you know what you're doing, unlike me :p). This complicates things, because you need different rules for sass and scss as documented by Vuetify.
If you're using sass only, the following should suffice:
.enableSassLoader(options => {
options.additionalData = "@import '" + path.resolve(__dirname, 'assets/styles/variables.scss') + "'";
})
(Note that additionalData
applies to sass version 9+. You may need prependData
or data
for older versions),
If you're using scss, then you need to split the rule added by enableSassLoader
. I could make it work by adding the following code in webpack.config.js
:
const Encore = require('@symfony/webpack-encore');
const path = require('path');
// .. other dependencies if needed
Encore
// ... other configurations
.enableSassLoader(options => {
options.additionalData = "@import '" + path.resolve(__dirname, 'assets/styles/variables.scss') + "'";
})
;
const config = Encore.getWebpackConfig();
// to override vuetify-variable, some rules need to be modified/added
// reference: https://vuetifyjs.com/en/features/sass-variables/#webpack-install
// enableSassLoader already has added a rule for s[ac]ss$, so we need to split in a separate rule for sass and scss.
const sassRule = config.module.rules.find(rule => rule.test.toString().includes('s[ac]ss$'));
sassRule.test = /\.sass$/; // make the rule explicit for sass only.
const scssRule = JSON.parse(JSON.stringify(sassRule));
scssRule.test = /\.scss$/;
scssRule.oneOf.forEach(oneOfRule => {
if (oneOfRule.resourceQuery) {
oneOfRule.resourceQuery = /module/; // cannot be parsed by json, so this need to be set manually.
}
oneOfRule.use.filter(oneOfUse => oneOfUse.loader.indexOf('sass-loader') !== -1).forEach(oneOfUse => {
oneOfUse.options.additionalData += ";"; //scss requires semicolon at end of line
});
});
config.module.rules.push(scssRule);
module.exports = config;
I find the need for this code horrific and love to see a cleaner solution, but at the very least this allows you to override the variables.
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