【问题标题】:Override Vuetify SASS variables with webpack and twig使用 webpack 和 twig 覆盖 Vuetify SASS 变量
【发布时间】:2020-02-14 15:03:45
【问题描述】:

我有 Vuetify 2.2.11,我正在尝试覆盖他们的 SASS 变量。我在一个 Symfony 3.x 项目中,所以我没有使用 vue-cli 安装 Vuetify。我关注了Webpack install guide,但我似乎无法让它发挥作用。 Vuetify 样式被转储到一个 css 文件(以我的 js 命名:app.js -> app.css),但我的覆盖没有考虑在内。至于我的项目样式(company.scss),它们被注入到 html 中的 <style type="text/css"> 标记中。还有一大堆空的 <style type="text/css"></style> 标签,我猜它们来自每个 Vuetify 组件,但我不知道为什么它们是空的。

这是我的代码的样子:

// /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;

【问题讨论】:

  • 嗨,Emilie,您找到解决方案了吗?
  • @ferdynator 不,我放弃了这个:(

标签: webpack sass vuetify.js webpack-encore


【解决方案1】:

好的,我终于让它工作了。方法如下:

webpack.config.js:

您只需发送电子邮件至.enableSassLoader()。实际加载但变量声明无效的config options described here

app.js

只需包含您的样式:

import '../styles/company.scss';

variables.scss

我已经创建了这个文件并将所有 vuetify 特定变量移到那里。你可以使用the official example

company.scss

这就是诀窍:

@import './assets/css/variables.scss';
@import '~vuetify/src/styles/main.sass'; // include this after your variables

就是这样。

我注意到热重载不适用于对变量的更改。但只要这些变量有效,那就没问题了。我从this page about the color pack得到了提示

【讨论】:

    【解决方案2】:

    ferdynator 的解决方案既好又干净,但在我的情况下,这只会让我覆盖一些变量。对我来说,它对组件中使用的变量没有影响。 最终,您可能仍需要像 https://vuetifyjs.com/en/features/sass-variables/#webpack-install 中记录的那样附加您的 variables.scss

    使用 Webpack Encore 执行此操作可能会非常令人困惑:因为 .enableSassLoader() 已经有一条您不想乱用的 /\.s[c|a]ss$/ 规则(除非您知道自己在做什么,不像我:p)。这使事情变得复杂,因为您需要 Vuetify 记录的不同的 sass 和 scss 规则。

    如果您只使用 sass,以下内容就足够了:

    .enableSassLoader(options => {
        options.additionalData = "@import '" + path.resolve(__dirname, 'assets/styles/variables.scss') + "'";
    })
    

    (请注意,additionalData 适用于 sass 版本 9+。对于旧版本,您可能需要 prependDatadata),

    如果你使用的是scss,那么你需要拆分enableSassLoader添加的规则。我可以通过在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;
    

    我发现对这段代码的需求太可怕了,我希望看到一个更干净的解决方案,但至少这允许你覆盖变量。

    【讨论】:

      【解决方案3】:

      经过许多问题,我在 Laravel 8 上解决了这个问题。

      // resources/js/vuetify.js
      import Vue from 'vue'
      import Vuetify from 'vuetify/lib'
      
      Vue.use(Vuetify)
      
      const opts = {}
      
      export default new Vuetify(opts)
      
      // resources/js/app.js
      window.Vue = require('vue').default
      
      import vuetify from './vuetify'
      import store from './store/store'
      
      Vue.component('g-home', require('./components/pages/GHome.vue').default)
      
      const app = new Vue({
          store,
          vuetify,
          el: '#app',
      });
      
      // Dependencies
      {
              "laravel-mix": "^6.0.6",
              "sass": "^1.20.1",
              "sass-loader": "^8.0.0",
              "vue": "^2.5.17",
              "vue-loader": "^15.9.5",
              "vue-template-compiler": "^2.6.10",
              "vuetify": "^2.4.3",
              "vuetify-loader": "^1.7.1",
      }
      
      // webpack.mix.js
      const mix = require('laravel-mix');
      const webpack = require('./webpack.config');
      Mix.listen('configReady', webpackConfig => {
          // scss
          const scssRule = webpackConfig.module.rules.find(
              rule =>
                  String(rule.test) ===
                  String(/\.scss$/)
          );
          scssRule.oneOf.forEach(o => {
              const scssOptions = o.use.find(l => l.loader === 'sass-loader').options
              scssOptions.prependData = '@import "./resources/sass/_variables.scss";'
          })
      
          // sass
          const sassRule = webpackConfig.module.rules.find(
              rule =>
                  String(rule.test) ===
                  String(/\.sass$/)
          );
      
          sassRule.oneOf.forEach(o => {
              const scssOptions = o.use.find(l => l.loader === 'sass-loader').options
              scssOptions.prependData = '@import "./resources/sass/_variables.scss"'
          })
      })
      mix.js('resources/js/app.js', 'public/js')
          .js('resources/js/gift.js', 'public/js')
          .vue()
          .sass('resources/sass/pages/home.scss', 'public/css')
          .sass('resources/sass/pages/gift.scss', 'public/css')
          .webpackConfig(Object.assign(webpack))
          .copyDirectory('resources/images/', 'public/images');
      
      if (mix.inProduction()) {
          mix.version();
      };
      
      // webpack.config.js
      const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');
      module.exports = {
          plugins: [
              new VuetifyLoaderPlugin(),
          ]
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-12
        • 1970-01-01
        • 2020-09-30
        • 2013-06-06
        • 1970-01-01
        • 1970-01-01
        • 2020-06-14
        • 2021-01-01
        相关资源
        最近更新 更多