简体   繁体   English

在使用 rails/webpacker 的 vue 应用程序中使用 vuetify 自定义 sass 变量

[英]Using vuetify custom sass variables in a vue app using rails/webpacker

I'm working on a Vue app with Rails backend.我正在开发一个带有 Rails 后端的 Vue 应用程序。 I'm using Vuetify and I want to customize the SCSS variables.我正在使用 Vuetify,我想自定义 SCSS 变量。 Sadly, I can't use Vue-CLI because we're bundling everything with webpacker, the rails implementation for webpack.遗憾的是,我不能使用 Vue-CLI,因为我们将所有东西都与 webpacker 捆绑在一起,这是 webpack 的 rails 实现。 Thus, I try to implement it with the base webpack configuration option.因此,我尝试使用基本 webpack 配置选项来实现它。

I haven't been able to do this directly, as webpacker has their own css/sass/scss loader configurations.我无法直接执行此操作,因为 webpacker 有自己的 css/sass/scss 加载器配置。 But, I can hook into the existing loaders and modify the options in a function that sets them later:但是,我可以连接到现有的加载器并修改 function 中的选项,以便稍后设置它们:

// config/webpack/environment.js

const updateStyleLoaders = (arr) => {
  arr.forEach((item) => {
    const loader = environment.loaders.get(item);

    // Use vue-style-loader instead of default to parse Vue SFCs
    const styleConfig = loader.use.find((el) => el.loader === 'style-loader');
    if (styleConfig !== undefined) {
      styleConfig.loader = 'vue-style-loader';
    }

    // VUETIFY: Use Dart-Sass and Fibers for Sass loaders
    const sassConfig = loader.use.find((el) => el.loader === 'sass-loader');
    if (sassConfig !== undefined) {
      const opts = sassConfig.options;

      opts.implementation = require('sass'); // Use dart-sass instead of node-sass
      opts.fiber = require('fibers'); // improves compilation speed
      opts.data = "@import '@/assets/sass/variables.scss';"; // Import custom variables
    }
  });
};

// Call fuction for all css-related loaders
updateStyleLoaders(['sass', 'css', 'moduleCss', 'moduleSass']);


// @/assets/sass/variables.scss

$body-font-family: "Comic Sans MS", "Comic Sans", cursive; // just wanna have fun
$border-radius-root: 20px;

Now here's the problem:现在问题来了:

The sass-loader rule matches both 'sass' and 'scss'. sass-loader 规则同时匹配“sass”和“scss”。 In vuetify's example the matching for sass and scss is done seperately.vuetify 的示例中,sass 和 scss 的匹配是单独完成的。 When I add the semicolon, I get this error during compilation:当我添加分号时,在编译过程中出现此错误:

./node_modules/vuetify/src/components/VAlert/VAlert.sass
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):

// Imports
                                     ^
      Semicolons aren't allowed in the indented syntax.
  ╷
1 │ @import '@/assets/sass/variables.scss';
  │                                       ^
  ╵
  stdin 1:39  root stylesheet

This tells me the line is in fact correctly added by sass-loader to the vuetify components that are added in. But, when I remove the semicolon from the import statement to support sass' indented syntax, I see no style changes .这告诉我该行实际上是由 sass-loader 正确添加到添加的 vuetify 组件中的。但是,当我从 import 语句中删除分号以支持 sass 的缩进语法时,我没有看到样式更改

How would I customize my vuetify components in this scenario?在这种情况下,我将如何自定义我的 vuetify 组件? Webpacker uses sass-loader v7.3.1. Webpacker 使用 sass-loader v7.3.1。

I just had a very similar problem about 2 days ago while trying to configure Storybook to work in a Vue/Vuetify project.大约 2 天前,我在尝试将 Storybook 配置为在 Vue/Vuetify 项目中工作时遇到了一个非常相似的问题。 Very frustrating.非常令人沮丧。 Here's what my working webpack.config.js file looks like now:这是我工作的webpack.config.js文件现在的样子:

const path = require('path')

module.exports = async ({ config }) => {
  config.module.rules.push({
    test: /\.s(a|c)ss$/,
    use: [
      'style-loader',
      'css-loader',
      // 'sass-loader'
      {
        loader: 'sass-loader',
        options: {
          sassOptions: {
            indentedSyntax: true, // <-- THIS WAS THE KEY!
          },
          // NOTE: NO SEMICOLON USED
          prependData: `@import '${path.resolve(__dirname, '..', 'src', 'scss', 'variables.scss')}'`,
        },
      },
    ],
    include: path.resolve(__dirname, '../'),
  })

  return config
}

I've never used webpacker but based on what you've posted, I would try something like this:我从来没有使用webpacker ,但根据你发布的内容,我会尝试这样的事情:

const updateStyleLoaders = (arr) => {
  arr.forEach((item) => {
    const loader = environment.loaders.get(item);

    // Use vue-style-loader instead of default to parse Vue SFCs
    const styleConfig = loader.use.find((el) => el.loader === 'style-loader');
    if (styleConfig !== undefined) {
      styleConfig.loader = 'vue-style-loader';
    }

    // VUETIFY: Use Dart-Sass and Fibers for Sass loaders
    const sassConfig = loader.use.find((el) => el.loader === 'sass-loader');
    if (sassConfig !== undefined) {
      const opts = sassConfig.options;

      opts.implementation = require('sass'); // Use dart-sass instead of node-sass
      opts.fiber = require('fibers'); // improves compilation speed

      // ADD THIS LINE
      opts.sassOptions.indentedSytax = true;
      // OR MAYBE THIS ONE???
      opts.indentedSyntax = true;

      // THEN REMOVE THE SEMICOLON (or keep the semicolon and set indentedSyntax to false?)
      opts.data = "@import '@/assets/sass/variables.scss'"; // Import custom variables
    }
  });
};

Full docs for all of the options available to sass-loader are here . sass-loader可用的所有选项的完整文档都在这里 FWIW, I find webpack configuration to be one of the most challenging things I face. FWIW,我发现 webpack 配置是我面临的最具挑战性的事情之一。 It's definitely playing programming on hard mode!绝对是在硬模式下玩编程!

I think you're close.我想你很接近。 Would love to know what configuration finally solves it.很想知道什么配置最终解决了它。

Thanks to the help of this GitHub comment , I've got it working.感谢这个 GitHub 评论的帮助,我已经开始工作了。

The default loaders can be removed with environment.loaders.delete('sass') // same for 'moduleSass', 'moduleCss', 'css' .可以使用environment.loaders.delete('sass') // same for 'moduleSass', 'moduleCss', 'css'

Then, they can be replaced by new ones.然后,它们可以被新的替换。 I've separated the scss and sass loaders to their own files:我已将 scss 和 sass 加载程序分离到它们自己的文件中:

// config/webpack/loaders/sass.js
const { config } = require('@rails/webpacker');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  test: /\.sass$/,
  use: [
    config.extract_css === false
      ? 'vue-style-loader'
      : MiniCssExtractPlugin.loader,
    {
      loader: 'css-loader',
      options: {
        sourceMap: true,
        importLoaders: 2,
      },
    },
    {
      loader: 'sass-loader',
      options: {
        sourceMap: true,
        implementation: require('sass'),
        fiber: require('fibers'),
        data: '@import "app/frontend/src/assets/styles/variables.scss"',
      },
    },
  ],
};

// config/webpack/loaders/scss.js

const { config } = require('@rails/webpacker');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  test: /\.scss$/,
  use: [
    config.extract_css === false
      ? 'vue-style-loader'
      : MiniCssExtractPlugin.loader,
    {
      loader: 'css-loader',
      options: {
        sourceMap: true,
        importLoaders: 2,
      },
    },
    {
      loader: 'postcss-loader',
      options: {
        sourceMap: true,
      },
    },
    {
      loader: 'sass-loader',
      options: {
        sourceMap: true,
        implementation: require('sass'),
        fiber: require('fibers'),
        data: '@import "app/frontend/src/assets/styles/variables.scss";',
      },
    },
  ],
};

These re-implement the basic webpacker integrations with CSS extraction.这些重新实现了与 CSS 提取的基本 webpacker 集成。

Then, I add them to the main config like so:然后,我将它们添加到主配置中,如下所示:

// config/webpack/environment.js

const { environment } = require('@rails/webpacker');
const path = require('path');

// Plugins
const { VueLoaderPlugin } = require('vue-loader');
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin');

// Loaders
const erb = require('./loaders/erb');
const sass = require('./loaders/sass');
const scss = require('./loaders/scss');
const vue = require('./loaders/vue');
const yml = require('./loaders/yml');

// Remove webpacker's conflicting loaders
environment.loaders.delete('moduleSass');
environment.loaders.delete('moduleCss');
environment.loaders.delete('sass');

// Modify base css loader to support vue SFC style tags
environment.loaders.get('css').use.find((el) => el.loader === 'style-loader').loader = 'vue-style-loader';

// Apply plugins
environment.plugins.prepend('VuetifyLoaderPlugin', new VuetifyLoaderPlugin());
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin());

// Apply custom loaders
environment.loaders.append('erb', erb);
environment.loaders.append('yml', yml);
environment.loaders.append('vue', vue);
environment.loaders.append('sass', sass);
environment.loaders.append('scss', scss);

// Shorthands for import statements
environment.config.resolve.alias = {
  // Use the same vue package everywhere
  vue: 'vue/dist/vue.esm',
  // use '@' as absolute path from /src
  '@': path.resolve(__dirname, '../../app/frontend/src/'),
};

module.exports = environment;

One important part here as well is where I still modify the default css-loader to use 'vue-style-loader' over 'style-loader'.这里的一个重要部分也是我仍然修改默认 css-loader 以使用 'vue-style-loader' 而不是 'style-loader'。 But for larger changes (like vuetify) I'm able to define my own defined loaders for SASS / SCSS syntax.但是对于较大的更改(例如 vuetify),我可以为 SASS / SCSS 语法定义自己定义的加载器。

Maybe it can be optimized further to remove the duplication, but as long as it's only two configurations, I'm just happy it works:)也许它可以进一步优化以消除重复,但只要它只有两种配置,我很高兴它可以工作:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 webpack 将 Vuetify 集成到 Vue CLI 应用程序中 - Integrating Vuetify into a Vue CLI app using webpack 带Webpacker的Rails 5.1。 使用自定义js类 - Rails 5.1 with Webpacker. Using custom js classes 在 rails 6 中使用 webpacker 的 Javascript (UJS) 错误 - Javascript (UJS) error using webpacker in rails 6 在Rails 5.1中使用Webpacker并加载图像资源 - Using Webpacker in Rails 5.1 and loading image assets Rails 6 应用程序使用 Yarn (webpacker) 安装 Glide.js - 未捕获的 ReferenceError: Glide 未定义 - Rails 6 app install Glide.js using Yarn (webpacker) - Uncaught ReferenceError: Glide is not defined 在CSS(Vue App)中使用JavaScript变量 - Using JavaScript variables in CSS (Vue App) 使用 Vue 3 + Vuetify 3 的 i18n 自定义块的语言环境消息 - Locale messages with using i18n custom block for Vue 3 + Vuetify 3 无法使用 Webpacker 在 Ruby on Rails 6 中调用 Bootstrap4 $(&#39;.carousel&#39;).carousel - Cannot call Bootstrap4 $('.carousel').carousel in Ruby on Rails 6 using Webpacker 从 Coffeescript 到 ES6 使用 Rails webpacker,如何管理类? - From Coffeescript to ES6 using Rails webpacker, how to manage classes? 如何使用 webpacker 在 rails6 中包含cropperjs 库 - how to include cropperjs library in rails6 using the webpacker
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM