< Back to frontpage

Extracting CSS files from webpack bundles

By default webpack 2 and 3 serves up CSS, SASS, SCSS, and LESS as javascript (.js files). Regardless of the entry points.

Solution: ExtractTextWebpackPlugin (webpack-contrib/extract-text-webpack-plugin).

To install:

$ npm install --save-dev extract-text-webpack-plugin

While the name of the plugin has nothing to do with file extensions, this is what will give you a proper .css file from your SASS, SCSS, LESS, or CSS entry points/bundles.

The other thing that's strange: how the plugin is applied.

Unlike using Grunt and Gulp, there seems to be no apparent logical correlation of how the heck .CSS files come out of it. For one, how does it make the entry file (which is by default, JS) have less content, while a new file, which materialize as an argument in ExtractTextPlugin('filename.css') more?

Even the commenters in the disqus widget on the page claim it's confusing.

That's it. Here, let me give a full example:

const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

const config = {
  context: path.resolve(__dirname),
  resolve: {
    modules: [path.resolve(__dirname)],
  },
  entry: {
    mystyle: "scss/mystyle.scss",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: "style-loader", // creates style nodes from JS strings
          },
          {
            loader: "css-loader", // translates CSS into CommonJS
          },
        ],
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          // resolve-url-loader may be chained before sass-loader if necessary
          use: ["raw-loader", "sass-loader"],
        }),
      },
    ],
  },
  output: {
    path: path.resolve("./outputdir/"),
    filename: "[name]-[hash].js",
  },
};

module.exports = config;