How to configure webpack to output multiple css files from sass

Hi I have a webpack config that takes multiple scss file based on a glob entry and a main typescript file. The problem is that it bundles the scss file together in one css file while I want them to be individual based on entry.
Webpack is definitely seeing all the files from the glob.
image
And the file produced is a bundle of all 3.
I have spent literally hours and hours googling and trying to configure this and its driving me crazy :rage:

Heres my current config:

import * as webpack from "webpack";
import * as path from "path";
import * as glob from "glob";
import * as MiniCssExtractPlugin from "mini-css-extract-plugin";

const config: webpack.Configuration = {
  mode: "development",
  entry: glob.sync(
    "./src/themes/**/scss/*.main.scss",
    "./src/ts/theme-pack.ts"
  ),
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: "ts-loader",
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
      }
    ]
  },
  resolve: {
    extensions: [".js", ".css", ".ts", ".scss"]
  },
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist")
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[name].css"
    })
  ]

  //   //Dev server
  //   devServer: {
  //     contentBase: __dirname,
  //     compress: true,
  //     port: 8080
  // }
};

export default config;

Can anyone help? This seems like it should be really simple but…
Thanks in advance :smiley:

glob.sync() returns an array of filenames, which again tells webpack to bundle it all in a single file. In order to keep the CSS files separate, you’ll have to specify separate entry points for them:

module.exports = {
  // ...
  entry: {
    'theme-pack': './src/index.js',
    'theme-yellow': './src/themes/theme-yellow.main.scss',
    'theme-blue': './src/themes/theme-blue.main.scss'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, './dist')
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[name].css"
    })
  ]
  // ...
}

Or automatically create the entry points from the glob results:

const mapFilenamesToEntries = pattern => glob
  .sync(pattern)
  .reduce((entries, filename) => {
    const [, name] = filename.match(/([^/]+)\.scss$/)
    return { ...entries, [name]: filename }
  }, {})

module.exports = {
  // ...
  entry: {
    'theme-pack': './src/index.js',
    ...mapFilenamesToEntries('./src/themes/*.main.scss')
  }
  // ...
}

This will however also create JS stubs for each SCSS file – webpack is a JS module bundler after all, and as such doesn’t expect entry points that don’t have any JS at all. I’m not aware of an easy way around this (other than removing undesired JS files afterwards, which is of course rather dirty)… but if your SCSS is not related to your JS anyway, I guess the simplest solution would be to compile the SCSS with node-sass directly.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.