Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack 4. Compile scss to separate css file

Im trying to compile scss into a separate css file with no luck. As it is now the css gets into the bundle.js together with all js code. How can i separate my css into its own file?

This is how my config looks:

var path = require("path");

module.exports = {
    entry: "./js/main.js",
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.js",
        publicPath: "/dist"
    },
    watch:true,
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: "babel-loader",
                    options: { presets: ["es2015"] }
                }
            },
            {
                test: /\.scss$/,
                use: [
                    {
                        loader: "style-loader"
                    },
                    {
                        loader: "css-loader"
                    },
                    {
                        loader: "sass-loader"
                    }
                ]
            }
        ]
    }
};
like image 408
fortyfiveknots Avatar asked May 17 '18 15:05

fortyfiveknots


People also ask

Is SCSS compiled to CSS?

scss. The example below shows how Page. scss is compiled into CSS when you save your project manually or automatically and how the changes to _grid. scss are reflected in the generated CSS file.

How do I import a SCSS file into CSS?

It is now possible to import css files directly into your sass file. The following PR in github solves the issue. The syntax is the same as now - @import "your/path/to/the/file" , without an extension after the file name. This will import your file directly.

Does webpack compile CSS?

Loaders are the node-based utilities built for webpack to help webpack to compile and/or transform a given type of resource that can be bundled as a javascript module. css-loader is the npm module that would help webpack to collect CSS from all the css files referenced in your application and put it into a string.


3 Answers

Other answers gave me just headache as they were not working. I did a lot of googling and I realized you can compile scss into separate css file without using any additional plugins

webpack.config.js

const path = require('path');

module.exports = {
    entry: [
        __dirname + '/src/js/app.js',
        __dirname + '/src/scss/app.scss'
    ],
    output: {
        path: path.resolve(__dirname, 'dist'), 
        filename: 'js/app.min.js',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: [],
            }, {
                test: /\.scss$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'file-loader',
                        options: { outputPath: 'css/', name: '[name].min.css'}
                    },
                    'sass-loader'
                ]
            }
        ]
    }
};

package.json

{
  "name": "...",
  "version": "1.0.0",
  "description": "...",
  "private": true,
  "dependencies": {},
  "devDependencies": {
    "file-loader": "^5.0.2",
    "node-sass": "^4.13.1",
    "sass-loader": "^8.0.2",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10"
  },
  "scripts": {
    "build": "webpack --config webpack.config.js --mode='production'"
  },
  "keywords": [],
  "author": "...",
  "license": "ISC"
}

Dependencies:

npm install --save-dev webpack webpack-cli file-loader node-sass sass-loader

How to run JS and SCSS compilation

npm run build
like image 182
Fusion Avatar answered Oct 02 '22 03:10

Fusion


You can use the MiniCssExtractPlugin. This will extract your css into a separate file.

There are a few parts of your webpack.config.js file you'll need to add to, or change.

You'll need to require the plugin at the top of the file:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

A plugins property is also required in the modules object:

plugins: [
  new MiniCssExtractPlugin({
    filename: "[name].css",
    chunkFilename: "[id].css"
  })
]

And you'll need to change your scss rule. Note the test is slightly different to include .scss files (probably best to name you scss files .scss) and the addition of the sass-loader which you'll need to install with npm. The loaders in the 'use' array operate in reverse order, so sass-loaded goes first, converting scss to css, then the css-loader and then extract plugin extracts the css out again to a separate file:

{
    test: /\.s?css$/,
    use: [
      MiniCssExtractPlugin.loader,
      "css-loader",
      "sass-loader"
    ]
}

So I think your config file will change to this:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var path = require("path");

module.exports = {
    entry: "./js/main.js",
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.js",
        publicPath: "/dist"
    },
    watch:true,
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: "babel-loader",
                    options: { presets: ["es2015"] }
                }
            },
            {
                test: /\.s?css$/,
                use: [
                  MiniCssExtractPlugin.loader,
                  "css-loader",
                  "sass-loader"
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
          filename: "[name].css",
          chunkFilename: "[id].css"
        })
    ]
}

Hope that helps.

like image 20
Bryan Avatar answered Oct 02 '22 04:10

Bryan


to update @Fusion 's anwser:

from https://github.com/webpack-contrib/file-loader:

DEPRECATED for v5: please consider migrating to asset modules.

the official docs (https://webpack.js.org/guides/asset-modules/) mention that clearly: as of webpack v5, raw-loader, url-loader, file-loader loaders are now depricated and replaced with Asset Modules, and new 4 module types: asset/resource (which replace file-loader), asset/inline, asset/source, asset are introduced.

so, the new way to compile scss to separate css file:


const path = require('path');

module.exports = {
  entry: [
    __dirname + '/src/js/app.js',
    __dirname + '/src/scss/app.scss'
  ],
  output: {
    path: path.resolve(__dirname, 'dist'), 
    filename: 'js/app.min.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [],
      }, {
        test: /\.scss$/,
        exclude: /node_modules/,

        type: 'asset/resource',
        generator: {
          filename: 'css/[name].min.css'
        },

        use: [

          {
            loader: 'file-loader',
            options: { outputPath: 'css/', name: '[name].min.css'}
          },

          'sass-loader'
        ]
      }
    ]
  }
};

the big advantage is that Asset Modules is a webpack built-in and you won't even need to install any 3rd module.

refer to:

  • https://webpack.js.org/guides/asset-modules/#resource-assets
  • https://webpack.js.org/guides/asset-modules/#custom-output-filename

Update:

you may realise that webpack generates an extra/unwanted/unexpected js file for non-js files (css, scss ...) despite the methode you use file-loader or asset modules, in this case, https://www.npmjs.com/package/webpack-fix-style-only-entries comes handy to solve this limitation.


const path = require('path');

const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");

module.exports = {
  entry: [
    __dirname + '/src/js/app.js',
    __dirname + '/src/scss/app.scss'
  ],
  output: {
    path: path.resolve(__dirname, 'dist'), 
    filename: 'js/app.min.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [],
      }, {
        test: /\.scss$/,
        exclude: /node_modules/,

        type: 'asset/resource',
        generator: {
          filename: 'css/[name].min.css'
        },

        use: [
          'sass-loader'
        ]
      }
    ]
  },
  plugins: [
    new FixStyleOnlyEntriesPlugin({ extensions:['scss'] }),
  ],
};
like image 30
cizario Avatar answered Oct 02 '22 02:10

cizario