webpack 4 打包后bundle.js过大,处理过程

最近做公司项目,用webpack 打包发现输出的bundle.js文件体积超大,9M多。查阅相关博客,最后处理得到的bundle.js压缩到202k。由于目前用的webpack是4.10.2, 在处理过程中,也遇到了关于webpack版本的一些坑。根据webpack version 4+, 整理优化思路如下:

1. 去除devtool(罪魁祸首)

  •  bundle.js达到9M,明显是在webpack.config.js中设置了devtool选项,比如 devtool: 'cheap-module-eval-source-map',解决方法是去除devtool。最后解决方案,分别配置生产环境和开发环境的webpack.config.js,只在webpack.prod.config.js中去除此配置。去除devtool(关闭sourcemap)后,bundle.js从9.6M降低到1.2M,还是远超limitation 244KB。

webpack.base.config.js :

const path = require('path');
const autoprefixer = require('autoprefixer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
    entry: './src/index.js', 
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: ''
    },
    resolve: {
        extensions: ['.js']
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            .......
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html',
            filename: 'index.html',
            inject: 'body'
        }),
        new CopyWebpackPlugin([{
            from: __dirname + '/src/assets/js',
            to: __dirname + '/dist/js'
        }])
    ]
};

webpack.dev.config.js :

 

const path = require("path");
const merge = require("webpack-merge");
const webpackConfigBase = require("./webpack.base.config");

const webpackConfigDev = {
    devtool: 'cheap-module-eval-source-map',
    mode:'development',
    plugins:[
        new BundleAnalyzerPlugin()
    ],
    devServer:{
        contentBase: path.join(__dirname,"../public"),
        hot: true,
        host:'0.0.0.0',
        inline: true,
        port: 8080,
    }
}
module.exports = merge(webpackConfigBase, webpackConfigDev);

webpack.prod.config.js :

 

const path = require("path");
const webpackConfigBase = require("./webpack.base.config");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const merge = require("webpack-merge");
const webpackConfigProd = {
    mode: "production",
    plugins:[
        new  CleanWebpackPlugin(["build"],{
        root: path.join(__dirname,"../")
        })
    ]
};
module.exports = merge(webpackConfigBase, webpackConfigProd);

在package.json中修改scripts:

"scripts": {
    "start": "webpack-dev-server --mode development --config ./webpack.dev.config.js",
    "build": "rimraf dist && webpack --mode production --config ./webpack.prod.config.js"
  }

 

2. 代码压缩

 

 

  • 2.1 使用UglifyJsPlugin 

        这边遇到一个坑,查阅相关博客,看到都会有这样一段代码:

plugins:[
        ...
        
        new webpack.optimize.UglifyJsPlugin({
            compress:{  
               warnings:false
            }
        })
    ...
     ]

webpack.optimize.UglifyJsPlugin是webpack自带的压缩工具,不需要import,但是在运行时确报了如下错误:

webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.

        查阅相关资料后发现,笔者使用的webpack版本时4.10.2,而在webpack4.0版本中已经废弃了之前 UglifyJsPlugin的用法。若要使用此功能,需要使用uglifyjs-webpack-plugin插件。

步骤如下:

 

  •   npm install uglifyjs-webpack-plugin --save-dev
  •  在webpack.config.js中添加如下代码:
const UglifyJsPlugin=require('uglifyjs-webpack-plugin');
...
 //压缩js
  optimization: {
        minimizer: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    compress: false
                }
            })
        ]
    }
...

注意:删除以前的写法,将optimization的JS压缩与plugins并排写在一起,而不是像以前一样写在plugins里面。

 

 

  • 2.2 使用webpack -p
...
"build": "webpack -p"
...

这是一个自动化的方法来构建生产环境下的项目,自动使用UglifyJsPlugin进行最小化 ,还会运行使用LoaderOptionsPlugin。

等价于:webpack --optimize-minimize --define process.env.NODE_ENV="'production'"

关于webpack-p的具体用法,没有做具体研究,笔者使用webpack -p后bundle.js减少了5KB。

参考资料:解决webpack打包文件过大的问题

3. 分离CSS

安装插件:

npm install extract-text-webpack-plugin --save-dev

在webpack.config.js中添加如下代码:

const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    ...
    module: {
        rules: [
           ...
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: [{
                        loader: "css-loader",
                        options: {
                            importLoaders: 1,
                            modules: true,
                            localIdentName: '[name]__[local]__[hash:base64:5]'
                        }
                    },
                    { 
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            plugins: () => [
                                autoprefixer({
                                    browsers: [
                                       "> 1%",
                                       "last 2 versions"
                                    ]
                                })
                            ]
                        }
                     }],
                publicPath: "../"
                })
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("bundle.css"),
        ...
    ]
...
};

然后运行打包程序,也遇到了一个版本问题造成的坑,在打包运行时出现如下错误:

Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead

查阅相关资料发现,extract-text-webpack-plugin还不能支持webpack4.0.0以上的版本。

解决办法

npm install --save-dev extract-text-webpack-plugin@next

会下载到+ [email protected] ,然后就可以正常打包了。

 

通过分离CSS,从原bundle.js中分离出了15KB的bundle.css。

 

参考文章:webpack使用extract-text-webpack-plugin打包时提示错误Use Chunks.groupsIterable and filter by instanceof Entryp

 

4. 使用CDN引入资源

通过以上3种操作,bundle.js已经减少到1190KB,还是远超与limitation的224KB。通过可视化工具webpack-bundle-analyzer分析发现,bundle.js之所以这么大,主要是由于打包时加入了echarts、moment和jQuery,所以考虑把他们提取出来,改用cdn版本的echarts、moment和jQuery。

bootcdn链接:https://www.bootcdn.cn/

以echarts为例,操作步骤如下:

  • 在index.html中引入echarts的CDN资源
  • 在webpack.base.config.js中配置externals选项,externals与entry平级。
  • ...
    externals: {
       "echarts": "echarts"
     }
    ...
    externals中的key是给import的时候用的,value表示的是如何在global中访问到该对象,这里是window.echarts;

 

echarts和moment都使用了CDN资源后,bundle.js减少到了202KB,基本达到了低于244KB的要求,但是相对还是很大,后面还可以进行其他的相关处理,比如:提取第三方库...参考文章:webpack打包优化解决方案

 

 

 

 

5. 提取第三方库

new webpack.optimize.CommonsChunkPlugin({
    filename:"common.js",
    name:"commons"
});

待补充

 

6. DLL方式

待补充

 

7.使用compresion-webpack-plugin插件将静态资源压缩,并生成.gz文件。

在webpack.prod.config.js中加入如下代码:

const CompressionPlugin = require('compression-webpack-plugin');

plugins: [
   ...
    new CompressionPlugin({
            asset:  '[path].gz[query]',
            algorithm:  'gzip',
            test:  /\.js$|\.css$|\.html$/
    })
   ...
]

但是关于是否使用gzip,目前还存在争议,如果bundle.js并不是太大,建议无需进行gzip压缩。

相关参考文章:

1. webpack打包优化并开启gzip

2. 要不要用gzip优化前端项目

 

最后,在这里,安利一下我使用的可视化分析bundle.js 资源的webpack插件,webpack-bundle-analyzer,可以清晰的看到项目中一共有多少个包,包的体积是多少,里面加载了哪些东西,大小是多少。

作用 : 将bundle.js中捆绑的资源大小及关系,用交互式可缩放树形图直观的表示出来,从而有助于知道各资源的大小及关系,并进行优化。

效果图如下:

webpack 4 打包后bundle.js过大,处理过程_第1张图片

另外,webpack-bundle-analyzer还支持缩小捆绑,并支持gzipped显示。详细功能可查看官网

webpack-bundle-analyzer安装和使用

npm install --save-dev webpack-bundle-analyzer

在webpack.config.js中:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
    plugins: [new BundleAnalyzerPlugin()]
}

BundleAnalyzerPlugin构造函数中可配置的对象:

new BundleAnalyzerPlugin({
  //  可以是`server`,`static`或`disabled`。
  //  在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
  //  在“静态”模式下,会生成带有报告的单个HTML文件。
  //  在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
  analyzerMode: 'server',
  //  将在“服务器”模式下使用的主机启动HTTP服务器。
  analyzerHost: '127.0.0.1',
  //  将在“服务器”模式下使用的端口启动HTTP服务器。
  analyzerPort: 8888, 
  //  路径捆绑,将在`static`模式下生成的报告文件。
  //  相对于捆绑输出目录。
  reportFilename: 'report.html',
  //  模块大小默认显示在报告中。
  //  应该是`stat`,`parsed`或者`gzip`中的一个。
  //  有关更多信息,请参见“定义”一节。
  defaultSizes: 'parsed',
  //  在默认浏览器中自动打开报告
  openAnalyzer: true,
  //  如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
  generateStatsFile: false, 
  //  如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
  //  相对于捆绑输出目录。
  statsFilename: 'stats.json',
  //  stats.toJson()方法的选项。
  //  例如,您可以使用`source:false`选项排除统计文件中模块的来源。
  //  在这里查看更多选项:https:  //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
  statsOptions: null,
  logLevel: 'info' 日志级别。可以是'信息','警告','错误'或'沉默'。
})

参考文章:

性能优化 - 查看 webpack 打包后所有的依赖关系(webpack 可视化工具)

官网:https://www.npmjs.com/package/webpack-bundle-analyzer

你可能感兴趣的:(前端自动化构建,webpack,前端打包,bundle.js过大)