Использование пользовательских переменных vuetify sass в приложении vue с использованием rails / webpacker

Я работаю над приложением Vue с бэкэндом Rails. Я использую Vuetify и хочу настроить переменные SCSS. К сожалению, я не могу использовать Vue-CLI, потому что мы все связываем с webpacker, реализацией rails для webpack. Таким образом, я пытаюсь реализовать его с опцией конфигурации базового веб-пакета.

Я не смог сделать это напрямую, так как у webpacker есть собственные конфигурации загрузчика css / sass / scss. Но я могу подключиться к существующим загрузчикам и изменить параметры в функции, которая устанавливает их позже:

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

Теперь вот в чем проблема:

Правило sass-loader соответствует как sass, так и scss. В примере vuetify сопоставление для sass и scss выполняется отдельно. Когда я добавляю точку с запятой, я получаю эту ошибку во время компиляции:

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

Это говорит мне, что строка на самом деле правильно добавлена ​​sass-loader к добавляемым компонентам vuetify. Но, когда я удаляю точку с запятой из оператора импорта для поддержки синтаксиса sass с отступом, Я не вижу изменений стиля.

Как мне настроить компоненты vuetify в этом сценарии? Webpacker использует sass-loader v7.3.1.


person Excalibaard    schedule 23.04.2020    source источник
comment
Сразу после того, как я наконец задал вопрос, я наткнулся на это обсуждение на github: github.com/rails/webpacker/ issues / 2235 Будем обновлять с новыми выводами.   -  person Excalibaard    schedule 23.04.2020


Ответы (2)


У меня была очень похожая проблема около 2 дней назад, когда я пытался настроить Storybook для работы в проекте Vue / Vuetify. Очень неприятно. Вот как сейчас выглядит мой рабочий 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
}

Я никогда не использовал 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
    }
  });
};

Полная документация по всем параметрам, доступным для sass-loader, находится здесь. FWIW, я считаю настройку веб-пакетов одной из самых сложных задач, с которыми я сталкиваюсь. Это определенно игра в программирование в сложном режиме! ????

Думаю, ты близок. Хотелось бы знать, какая конфигурация, наконец, решает эту проблему.

person morphatic    schedule 23.04.2020
comment
У меня все заработало, но спасибо за ответ! Принуждение загрузчика преобразовывать файлы scss в синтаксис с отступом, вероятно, также сработает, чтобы избежать махинаций с точкой с запятой! opts.indentedSyntax можно было бы использовать с sass-loader 7 :) - person Excalibaard; 23.04.2020

Благодаря помощи этого комментария GitHub, я понял работающий.

Загрузчики по умолчанию можно удалить с помощью environment.loaders.delete('sass') // same for 'moduleSass', 'moduleCss', 'css'.

Затем их можно будет заменить новыми. Я разделил загрузчики 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";',
      },
    },
  ],
};

Они повторно реализуют базовую интеграцию веб-пакетов с извлечением CSS.

Затем я добавляю их в основную конфигурацию вот так:

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

Еще одна важная часть здесь заключается в том, что я все еще модифицирую css-loader по умолчанию, чтобы использовать «vue-style-loader» вместо «style-loader». Но для более крупных изменений (например, vuetify) я могу определить свои собственные определенные загрузчики для синтаксиса SASS / SCSS.

Возможно, его можно оптимизировать дальше, чтобы удалить дублирование, но пока это всего две конфигурации, я просто рад, что он работает :)

person Excalibaard    schedule 23.04.2020
comment
Вы знаете, как этого можно достичь в проекте, не использующем webpacker? У меня нет файла environment.js, пожалуйста, посмотрите stackoverflow.com/questions/64143692/ - person Faizan Shakeel; 01.10.2020