本文介绍了如何配置 webpack 生成单独的 css 主题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 React 应用,现在扩展了几个主题.

I am developing a react app, that is now extended by several themes.

这些主题在我的主题文件夹中的 .scss 文件中定义:

These themes are defined in .scss files in my themes folder:

- themes
- - theme-base.scss
- - theme.dark.scss
- - theme.light.scss

它们包含带有一些变量的基本配色方案,例如:

they contain basic color schemes with some variables, eg:

[theme-dark.scss]
$color-primary: #100534;
$color-primary-accent: #231454;

所有组件都只是使用这些颜色变量来为它们设置主题.

All components just use these color variables to theme them.

现在我想让 webpack 编译并连接我的 scss 代码,以便为每个主题分隔静态 css 文件.

Now I want webpack to compile and concat my scss code to separate static css files for each theme.

我通过使用 extractWebpackTextPlugin 和一些像这样的文件加载器来实现它:

I got this to work by using extractWebpackTextPlugin and some file loaders like this:

module.exports = env => {
  const config = require('./webpack.common')(env);
  const project = env.project;

  const postcss = {
    loader: 'postcss-loader',
    options: postcssConfig(settings.browsers),
  };

  config.watch = true;
  config.devtool = 'eval';

  const themes = ['theme-base'];

  themes.forEach(themeKey => {
    const themeInstance = new ExtractTextPlugin('css/' + themeKey + '.css');
    const themePath = path.resolve(__dirname, '../../react/app/css/_' + themeKey + '.scss');

    config.module.rules.push({
      test: /\.s?css$/,
      exclude: /node_modules/,
      use: themeInstance.extract({
        fallback: 'style-loader',
        use: [
          {
            loader: 'css-loader',
            options: {
              localIdentName: '[hash:base64:5]',
              modules: true,
              importLoaders: 1,
            }
          },
          postcss,
          {
            loader: 'sass-loader',
            options: {
              data: `@import "${themePath}";`,
            }
          }
        ]
      }),
    });

    config.plugins.push(themeInstance);
  });
}

但是:我不能向我的数组 themes 添加多个主题!一旦它包含多个项目,css 和 sass 加载器就会在读取 scss 文件时抛出错误.

But:I can not add more than one theme to my array themes! As soon as it contains more than one item, the css and sass loaders throw errors while reading the scss files.

...加载样式"后的 CSS 无效:预期为 1 选择器或规则,为var content = requi"

如何设置 webpack 为每个主题编译一个静态 css 文件?

How would I setup webpack to compile one static css file for each theme?

推荐答案

我遇到了类似的问题,并意识到错误的发生是因为您不能拥有多个具有相同 test:/\.s? 的 Webpack 规则?css$/ 条件.第一个之后的任何内容都会出错.

I had a similar issue and realized that the error occurs because you can't have multiple Webpack rules with the same test: /\.s?css$/ condition. Anything after the first will error out.

为了解决这个问题,而是为所有 SCSS 创建 1 个规则,并将额外的 ExtractTextPlugin 实例推送到规则的 oneOf 数组....

To solve this instead create 1 rule for all of the SCSS, and the push the additional ExtractTextPlugin instances to the rules' oneOf array....

/SASS 文件夹

-- app.scss
-- custom/
---- /blue/theme.scss
---- /red/theme.scss
---- /default/theme.scss
---- ...

./src/sass/app.scss?theme 条目是默认/第一个主题.

The ./src/sass/app.scss?theme entry is the default/first theme.

var themeDefault = "default";
module.exports = {
  entry: ['./src/app.js','./src/sass/app.scss?theme'],
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'app.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ],
      },
      {
        test: /\.scss$/,
        oneOf: [ // use oneOf since we'll need diff rules/handlers for each .scss
          {
            resourceQuery: /theme/, 
            use: extractSass.extract({
                use: [
                  {
                    loader: "css-loader"
                  },
                  {
                    loader: "sass-loader",
                    options: {
                      allChunks: true,
                      sourceMap: true,
                      includePaths: [
                        './src/sass/custom/'+themeDefault
                      ]
                    }
                }]
            })
          }
        ],
      },

      ...
    ]
  },
  plugins: [
    extractSass
  ],
  ...
}

迭代/custom 文件夹中的每个主题.

Iterate each theme in the /custom folder.

  // iterate themes to add an entry point, rule and plugin instance for each
  fs.readdirSync('./src/sass/custom').filter(f => fs.statSync("./src/sass/custom/"+f).isDirectory()).forEach(themeKey => {
    const themeInstance = new ExtractTextPlugin('css/' + themeKey + '.css');

    module.exports.entry.push('./src/sass/app.scss?'+themeKey);

    // the SCSS rule is at index 1 in the rules array
    module.exports.module.rules[1].oneOf.push( 
    {
      resourceQuery: new RegExp(themeKey),  
      use: themeInstance.extract({
          use: [
            {
              loader: "css-loader"
            },
            {
              loader: "sass-loader",
              options: {
                allChunks: true,
                includePaths: [
                  './src/sass/custom/'+themeKey
                ]
              }
          }]
      })
    });

    module.exports.plugins.push(themeInstance);

  });

然后在app.scss中,从Webpack sass-loader指定的includePaths中加载相应的主题文件夹...

And then in the app.scss, the appropriate theme folder is loaded from the includePaths specified in Webpack sass-loader...

// load theme.scss from included path
@import "theme";
...

因此,每次上面的 forEach 命中下一个 themeKey 时,app.scss 中的 @import "theme" 指向不同的子文件夹(蓝色、红色等)导致每个主题"产生不同的 CSS 文件.

Therefore, each time the forEach above hits the next themeKey the @import "theme" in app.scss point to a different sub folder (blue,red,etc) resulting in different CSS files for each "theme".

这篇关于如何配置 webpack 生成单独的 css 主题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 20:55