Search code examples
webpackwebpack-5

webpack remove extra js files in output folder


I would like to compile all scss file but without generating the extra js file,currently my code structure is:

-public
 -index.html
 -login.html
-src
 -index.js
 -index.scss
 -login.js
 -login.scss
 -test.scss

I want to generate in my dist folder like

-dist
 -css
   -login.xxxxxx.css
   -index.xxxxxx.css
   -test.xxxxxx.css
 -index.xxxxxx.js
 -index.html
 -login.xxxxxx.js
 -login.html

In my last thread, I get to know webpack-remove-empty-scripts and my webpack.config.js like below.

npm install webpack-remove-empty-scripts --save-dev

'use strict';
const path = require('path');

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');

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

const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];

module.exports = {

    devtool: 'eval-cheap-module-source-map',
    mode: isDev ? 'development' : 'production',
    entry: {
        index: './src/index.js',
        login: './src/login.js',
       ...Object.assign({}, ...scssEntries)
      },
    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')]
                // exclude: /node_modules/
            },
            
            {
                test: /.html$/,
                use: 'html-withimg-loader'
            }
        ]
    },
    plugins: [
       new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html', 
            config: config.template,
            minify: {
                removeAttributeQuotes: false, 
                collapseWhitespace: false, 
            },
            chunks: ['index']
           
        }),
        new RemoveEmptyScriptsPlugin(),      
        new MiniCssExtractPlugin({
            filename: 'css/[name].[contenthash:6].css'       
        }),    
    ]
}

If I do not use this plugin, it will generate three js file in dist. If I use it, my index.xxxxxx.js and login.xxxxxx.js are also be removed and there is no js file at all.

What is the problem?I want to keep js file generated by .js of entry but remove js file generated by .scss of entry.


Solution

  • the problem is with the usage of the webpack entry:

    entry: {
      index: './src/index.js',
      login: './src/login.js',
      ...Object.assign({}, ...scssEntries) // <== HERE IS THE PROBLEM
    },
    

    This line ...Object.assign({}, ...scssEntries) generate following:

    { 
      index: './src/index.scss', 
      login: './src/login.scss' 
    }
    

    Then two object will be merged via .... But, this both objects have same keys: index and login, therefore last object, contained same keys but with .scss files, override first object with .js files.

    The merging of:

    entry: {
      index: './src/index.js',
      login: './src/login.js',
      ... { index: './src/index.scss', login: './src/login.scss' }
    },
    

    has the result:

    entry: {
      index: './src/index.scss', 
      login: './src/login.scss' 
    },
    

    Solution

    Use advanced syntax of webpack entry-point to define files with same basename (filename without extention).

    Change the webpack entry:

    entry: {
      index: './src/index.js', // => dist/index.xxxxxx.js
      login: './src/login.js', // => dist/login.xxxxxx.js
      // use uniq key in entry
      indexCss: {
        import: './src/index.scss',
        filename: 'css/index.[contenthash:6].css' // => dist/css/index.xxxxxx.css
      },
      // use uniq key in entry
      loginCss: {
        import: './src/login.scss',
        filename: 'css/login.[contenthash:6].css' // => dist/css/login.xxxxxx.css
      }
    },
    

    Or other variant:

    entry: {
      index: './src/index.js', // => dist/index.xxxxxx.js
      login: './src/login.js', // => dist/login.xxxxxx.js
      // use uniq key in entry
      'css/index': './src/index.scss',
      // use uniq key in entry
      'css/login': './src/login.scss'
    },
    

    In this case use

    plugin: [
      new MiniCssExtractPlugin({
        filename: '[name].[contenthash:6].css', // <= remove `css/` from filename
      }),
      //...
    ]