javascriptcsswebpackpostcsscssnext

How can I configure different customProperties in postcss.config.js for different Webpack entry points?


I am using Webpack 4.

I have two entry points in my webpack.config.js, for each of which I am generating a separate CSS file using mini-css-extract-plugin.

const webpack = require('webpack')
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    mode: 'development',
    entry: {
        foo: './foo.js',
        bar: './bar.js'
    },
    output: {
        path: path.resolve(__dirname, 'src/'),
        filename: 'js/[name].js'
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "css/[name].css"
        })
    ],
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    "css-loader", "postcss-loader"
                ]
            }
        ]
    }
}

I am also using postcss-cssnext.

In my postcss.config.js file in my root folder I am defining a number of CSS variables in customProperties, like this:

module.exports = {
    plugins: {
        'postcss-cssnext': {
            features: {
                customProperties: {
                    variables: {
                        color1: '#333',
                        color2: '#53565A',
                        baseFont: 'Helvetica, sans-serif'
                    }
                }
            }
        }
    }
}

If I wanted my CSS variables to have different values for each of my two entry points, how would I go about doing this?

For instance, let's say in foo.css I want var(--color1) to equal #333, but in bar.css I want it to equal #860000.


Solution

  • I figured this out. Here's how I solved it.

    I switched my webpack.config file to have multiple configurations, one for each entry point. I also configured postcss-loader to pass the entry point as context to postcss.config.js.

    webpack.config.js

    const webpack = require('webpack')
    const path = require('path')
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
    const entryPoints = ['foo', 'bar']
    
    const config = entry => ({
      mode: 'development',
      entry: `./${entry}.js`,
      output: {
        path: path.resolve(__dirname, 'src/'),
        filename: `js/${entry}.js`
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: `css/${entry}.css`
        })
      ],
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader'
            }
          },
          {
            test: /\.css$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader
              },
              'css-loader', 
              {
                loader: 'postcss-loader',
                options: {
                  config: {
                    ctx: { entry }
                  }
                }
              },
            ]
          }
        ]
      }
    })
    
    module.exports = entryPoints.map(entry => config(entry))
    

    My postcss.config.js file can then be conditionally configured based on the entry point. In this example I define styles inline, but these could be pulled in from an external module via a require.

    postcss.config.js

    module.exports = ({ options }) => ({
      plugins: {
        'postcss-cssnext': {
          features: {
            customProperties: {
              variables: 
                options.entry === 'foo' ? 
                  {
                    color1: '#333',
                    color2: '#53565A',
                    baseFont: 'Helvetica, sans-serif'
                  } :
                  {
                    color1: '#860000',
                    color2: '#555',
                    baseFont: 'Arial, sans-serif'
                  }
            }
          }
        }
      }
    })