webpack 删除输出文件夹中多余的 js 文件

webpack remove extra js files in output folder

我想编译所有 scss 文件但不生成额外的 js 文件,目前我的代码结构是:

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

我想在我的 dist 文件夹中生成

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

在我的上一篇文章中,我开始了解 webpack-remove-empty-scripts 和我的 webpack.config.js,如下所示。

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'       
        }),    
    ]
}

如果我不使用这个插件,它会在dist中生成三个js文件。如果我使用它,我的index.xxxxxx.jslogin.xxxxxx.js也被删除,根本没有js文件。

有什么问题?我想保留条目 .js 生成的 js 文件,但删除条目 .scss 生成的 js 文件。

问题出在 webpack 条目的使用上:

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

这一行 ...Object.assign({}, ...scssEntries) 生成以下内容:

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

然后两个对象将通过...合并。 但是,这两个对象具有相同的键:indexlogin,因此最后一个对象包含相同的键但具有 .scss 个文件,用 .js 个文件覆盖第一个对象。

合并:

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

有结果:

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

解决方案

使用webpack的高级语法entry-point来定义具有相同basename(不带扩展名的文件名)的文件。

更改 webpack 条目:

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
  }
},

或其他变体:

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'
},

在这种情况下使用

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