javascriptwebpacksasslessextract-text-plugin

Webpack run both .LESS and .SCSS compilation. Extract text plugin not working on one bundle file


I need to run both LESS and SCSS compilation in the same project output to separate CSS files.

The project was LESS based but now adding SCSS during a transition phase.

I don't want to update webpack for the time being. Webpack runs fine but and generates common.bundle.js file but the CSS is not being extracted from this one bundle.

The other chunks and new SCSS it extracts OK but not the core bundle file (common.bundle.js).

I have tried to change the sequence in webpack.config.js but this is not helping. I see this 'Multiple Instances' as well but can't work it out.

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
var ExtractTextPlugin = require("extract-text-webpack-plugin");


module.exports = {
    devtool: "source-map",
    entry: {
        "login.bundle": "./dash/app/login.js",
        "summary.bundle": "./dash/app/summary.js",
        "metrics.bundle": "./dash/app/metrics.js",
        "market_share.bundle": "./dash/app/market_share.js",
        "broker.bundle": "./dash/app/broker.js",
        "event_studies_custom.bundle": "./dash/app/event_studies_custom.js",
        "case_studies.bundle": "./dash/app/case_studies.js",
        "home.bundle": "./dash/app/home.js"
    },
    output: {
        path: __dirname + '/dash/static/js',
        filename: "[name].js"
    },
    module: {
        loaders: [{
            test: require.resolve("jquery"),
            loader: "expose-loader?$!expose-loader?jQuery"
        }, {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract({fallback: "style-loader", use: "css-loader"})
        }, {
            test: /\.less$/,
            loader: ExtractTextPlugin.extract({fallback: "style-loader", use: "css-loader!less-loader"})
        }, {
            test:/\.scss$/,
            use: ExtractTextPlugin.extract({
                fallback: 'style-loader',
                use: ['css-loader?url=false', 'sass-loader']
            })
        }, {
            test: /\.(woff|eot|ttf|svg)(\?\S*)?$/,
            loader: "url-loader?limit=100000"
        }, {
            test: /\.(jpe?g|png|gif|svg)$/i,
            loader: 'url-loader?limit=100000!img-loader'
        }, {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader"
        }]
    },
    plugins: [
        new CommonsChunkPlugin({
            name: ['common'],
            filename: 'common.bundle.js'
        }),
        new ExtractTextPlugin("[name].css")]
};

package.json

{
  "name": "project",
  "version": "1.0.0",
  "description": "project descritption",
  "main": "bundle.js",
  "scripts": {
    "build": "webpack -p",
    "develop": "webpack",
    "watch": "webpack --watch"
  },
  "repository": {
    "type": "git",
    "url": "project.git"
  },
  "author": "me",
  "license": "All Rights Reserved",
  "private": true,
  "devDependencies": {
    "babel-core": "^6.22.1",
    "babel-loader": "^6.2.10",
    "babel-preset-env": "^1.1.8",
    "backbone": "^1.3.3",
    "block-ui": "^2.70.1",
    "css-loader": "^0.28.11",
    "expose-loader": "^0.7.1",
    "extract-text-webpack-plugin": "^2.1.2",
    "file-loader": "^0.9.0",
    "grid-list": "^0.4.1",
    "handlebars": "^4.0.5",
    "highcharts": "5.0.11",
    "img-loader": "^1.3.1",
    "imports-loader": "^0.8.0",
    "jquery": "^3.1.1",
    "jquery-colorbox": "^1.6.4",
    "jquery-ui": "^1.12.1",
    "jquery.mousewheel": "^3.1.9",
    "less": "^2.7.1",
    "less-loader": "^2.2.3",
    "less-plugin-clean-css": "^1.5.1",
    "moment": "^2.17.0",
    "node-sass": "^4.8.3",
    "raven-js": "^3.14.0",
    "sass-loader": "^7.0.1",
    "select2": "^4.0.6-rc.1",
    "style-loader": "^0.20.3",
    "underscore": "^1.8.3",
    "url-loader": "^0.5.7",
    "vis": "4.21.0",
    "webpack": "^2.7.0"
  }
}

Solution

  • Yes, your direction is right. You can use extract-text-webpack-plugin for this one. Just define an extractor for each file in resulting bundle and use it in module.rules for a desired rule.

    Below is an example of usage of 3 of these extractors for css/scss/less files. One per each file.

    (Was created and tested on webpack 4.x)

    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    // Create extract plugin for each file you want to create in resulting bundle
    const extractCSS = new ExtractTextPlugin('output-folder/or/whatever/from-css.css');
    const extractLESS = new ExtractTextPlugin('output-folder/or/whatever/from-less.css');
    const extractSCSS = new ExtractTextPlugin('output-folder/or/whatever/from-scss.css');
    
    module: {
      rules: [
          // ...
          {
            test: /\.less$/,
            use: extractLESS.extract({
              fallback: 'style-loader',
              use: [
                { loader: 'css-loader', options: { importLoaders: 1 } }, // importLoaders equals to number of loaders in array after this one.
                'less-loader'
              ]
            })
          },
          {
            test: /\.scss$/,
            use: extractSCSS.extract({
              fallback: 'style-loader',
              use: [
                { loader: 'css-loader', options: { importLoaders: 1, url: false } }, // importLoaders equals to number of loaders in array after this one.
                'sass-loader'
              ]
            })
          },
          {
            test: /\.css$/,
            use: extractCSS.extract({
              fallback: 'style-loader',
              use: 'css-loader'
            })
          }
      ],
      plugins: [
        // Include each of "extractors" here. Order is not important
        extractLESS,
        extractSCSS,
        extractCSS,
        // ...
      ]
    }
    

    I didn't actually run this example, just took it from my project and updated it to fit your question. So, feel free to leave a comment with a question if something is not working as expected. I'll update my response.