Home > Enterprise >  Webpack how to compile all my scss file without using import in my entry js file
Webpack how to compile all my scss file without using import in my entry js file

Time:01-30

I use webpack ^5.65.0.

I want to compile all my scss file into css but I have to use multiple import in my entry index.js like

import './index.scss';
import './test.scss'
...

I do not want to use import in the index.js file and think it can be done by webpack settings(I am not sure).

My webpack.config.js

module.exports = {

    devtool: 'eval-cheap-module-source-map',
    mode: isDev ? 'development' : 'production',
    entry: {
        index: './src/index.js',
        login: './src/login.js',
        test:'./test.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[chunkhash:6].js',
        publicPath: '/'
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                use: ['cache-loader','babel-loader'],
                include: [path.resolve(__dirname, 'src')]
                
            },
            {
                test: /\.(sc|sa|c)ss/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
                include: [path.resolve(__dirname, 'src')]
        
            }
         ]
     }
  }

I have no idea, then add a test.js to put all the scss import in it and add it to the entry.But the output will also has a test.xxxxxx.js file in the dist folder and I do not want it though.

So,what is the right way to meet my requirement.

Is it possible to just compile all scss file without import in the entry js file?

CodePudding user response:

  1. add style files in webpack entry

    Note: if already exists an entry with same name, then use advanced entry-point syntax:

    'uniqEntryName': {
      import: './path/to/source/file.scss',
      filename: 'output-name.css'
    }
    
  2. add new MiniCssExtractPlugin() in webpack plugins

Change your webpack.config.js

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

module.exports = {
  devtool: 'eval-cheap-module-source-map',
  mode: isDev ? 'development' : 'production',
  entry: {
    index: './src/index.js',
    login: './src/login.js',
    test:'./test.js',
    styles: './index.scss', // => dist/styles.css
    testCss: {
      import: './test.scss',
      filename: 'test.css' // => dist/test.css
    }
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash:6].js',
    publicPath: '/'
  },
  plugins: [
    new MiniCssExtractPlugin(), // <= extract css from webpack entry
  ],
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: ['cache-loader','babel-loader'],
        include: [path.resolve(__dirname, 'src')]

      },
      {
        test: /\.(sc|sa|c)ss/,
        use: [
          MiniCssExtractPlugin.loader, // <= its right
          'css-loader', 
          'sass-loader'
        ],
        include: [path.resolve(__dirname, 'src')]

      }
    ]
  }
}
  1. add in head-tag of your template the compiled css files:
<link rel="stylesheet" href="/dist/styles.css">
<link rel="stylesheet" href="/dist/test.css">

Note: webpack generate a JS file for each entry-point and for styles will be generated empty JS files. To fix it you should use the webpack-remove-empty-scripts to remove unexpected empty JavaScript files.

CodePudding user response:

I assume that you want to automatically build all *.scss files that are in ./src is that right?

Thankfully webpack.config.js is a js file so you can generate the config programmatically.

Expanding @biodiscus answer to automatically fetch the files:

// => webpack.config.js

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

const scssFiles = fs.readdirSync("./src").filter(function (file) {
  return file.match(/.*\.scss$/);
});
const scssEntries = scssFiles.map((filename) => {
  const filenameWithoutExtension = filename.replace(/\.[^/.] $/, "");
  const entryName = `style_`   filenameWithoutExtension;
  return { [entryName]: "./src/"   filename };
});

module.exports = {
  entry: {
    index: "./src/index.js",
    login: './src/login.js',
    test:'./test.js'
    ...Object.assign({}, ...scssEntries),
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      { // a loader loads file with matching extension no matter
        // if it is listed in entry: or imported inside js
        test: /\.(sc|sa|c)ss/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
        include: [path.resolve(__dirname, "src")],
      },
    ],
  },
};

So the changes are: First, get names of all scss files:

const scssFiles = fs.readdirSync("./src").filter(function (file) {
  return file.match(/.*\.scss$/);
});
const scssEntries = scssFiles.map((filename) => {
  const filenameWithoutExtension = filename.replace(/\.[^/.] $/, "");
  const entryName = `style_`   filenameWithoutExtension;
  return { [entryName]: "./src/"   filename };
});

Second, append them to the list of entries:

entry: {
  index: "./src/index.js",
  login: './src/login.js',
  test:'./test.js'
  ...Object.assign({}, ...scssEntries),
},

and third, this is important:

output: {
  filename: "[name].js", // <-- use template for named output
  path: path.resolve(__dirname, "dist"),
},

Also, notice how I prepended the entry names with style_. Otherwise index.js and index.scss would have both same entry name resulting in only one being built.

  •  Tags:  
  • Related