webpack打包文件体积过大,怎么提升速度?

借助webpack visualizer可视化插件,来看构建的情况。
这个问题要具体情况具体分析,看看打包文件有哪些块头比较大,哪些不常改变,最好列一个list,分类优化。下面提供8种方法,仅供参考。

一、区分配置文件,去除不必要的插件。
前端开发环境通常分为两种:开发环境和生产环境,我们可以创建两个配置文件来区分开发环境和生产环境。
webpack.config.dev.js,用于开发环境,需要日志输出,sourcemap,热模块替换,错误报告等。
webpack.config.prod.js,用于生产环境,需要做代码压缩,对文件名进行hash处理等。

  1. //安装webpack-merge
  2. npm install --save-dev webpack-merge
  1. //webpack.config.common.js
  2.  
  3. const path = require('path');
  4. const CleanWebpackPlugin = require('clean-webpack-plugin');
  5. const HtmlWebpackPlugin = require('html-webpack-plugin');
  6.  
  7. module.exports = {
  8. entry: {
  9. app: './src/index.js'
  10. },
  11. plugins: [
  12. new CleanWebpackPlugin(['dist']),
  13. new HtmlWebpackPlugin({
  14. title: 'Production'
  15. })
  16. ],
  17. output: {
  18. filename: '[name].bundle.js',
  19. path: path.resolve(__dirname, 'dist')
  20. }
  21. };
  1. //webpack.config.dev.js
  2.  
  3. const merge = require('webpack-merge');
  4. const common = require('./webpack.config.common.js');
  5.  
  6. module.exports = merge(common, {
  7. devtool: 'inline-source-map',
  8. devServer: {
  9. contentBase: './dist'
  10. }
  11. });
  1. //webpack.config.prod.js
  2.  
  3. const merge = require('webpack-merge');
  4. const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
  5. const common = require('./webpack.config.common.js');
  6.  
  7. module.exports = merge(common, {
  8. devtool: 'source-map',
  9. plugins: [
  10. new UglifyJSPlugin({
  11. sourceMap: true
  12. })
  13. ]
  14. });

在webpack.config.common.js中,我们设置了entry和output配置,并且在其中引入这两个环境公用的全部插件。在webpack.config.dev.js中,我们添加了推荐的devtool(强大的 source map)和简单的devServer配置。在webpack.config.prod.js中,我们引入了UglifyJSPlugin。

修改package.json文件

  1. "scripts": {
  2. "dev": "webpack-dev-server --open --config webpack.config.dev.js",
  3. "prod": "webpack --config webpack.config.prod.js"
  4. }

二、合理使用CommonsChunkPlugin插件,提取公用代码。

该方法适用于开发环境和生产环境,具体用法在下面有介绍。

三、通过externals配置来引用外部文件的方式,提取第三方库。

  1. {
  2. externals: {
  3. 'react': 'React'
  4. }
  5. }
  1. <script src="//cdn.com/vue.min.js"></script>
  2. <script src="/build/bundle.js"></script>

该方法适用于生产环境。

四、利用DllPlugin和DllReferencePlugin预编译资源模块,提取第三方库。

  1. const vendors = [
  2. 'vue','vue-router',
  3. // ...其它库
  4. ];
  5.  
  6. module.exports = {
  7. output: {
  8. path: 'build',
  9. filename: '[name].js',
  10. library: '[name]'
  11. },
  12. entry: {
  13. "lib": vendors
  14. },
  15. plugins: [
  16. new webpack.DllPlugin({
  17. path: 'manifest.json',
  18. name: '[name]',
  19. context: __dirname
  20. })
  21. ]
  22. };

该方法适用于开发环境和生产环境。

五、压缩代码

使用tree shaking,即先用es6语法import,export,再引入删除引用代码的压缩工具UglifyJsPlugin。

  1. new webpack.optimize.UglifyJsPlugin({
  2. // 最紧凑的输出
  3. beautify: false,
  4. // 删除所有的注释
  5. comments: false,
  6. compress: {
  7. //在UglifyJs删除没有用到的代码时不输出警告
  8. warnings: false,
  9. //用于压缩的时候去除log
  10. drop_debugger: true,
  11. drop_console: true,
  12. //内嵌定义了但是只用到一次的变量
  13. collapse_vars: true,
  14. //提取出现多次但是没有定义成变量去引用的静态值
  15. reduce_vars: true
  16. }
  17. })

加入了这个插件之后,编译的速度会明显变慢,所以一般只在生产环境启用。如果服务器端可以开启gzip压缩,优化的效果更明显。
另外,可以通过webpack-parallel-uglify-plugin来提升压缩速度,原理是采用多核并行压缩的方式提升速度。

  1. let ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
  2. let os = require('os');
  3.  
  4. new ParallelUglifyPlugin({
  5. workerCount: os.cpus().length,
  6. cacheDir: '.cache/',
  7. uglifyJS: {
  8. output: {
  9. comments: false
  10. },
  11. compress: {
  12. warnings: false
  13. }
  14. }
  15. })

该方法适用于生产环境。

六、happyPack多核编译资源(多线程介入

  1. var HappyPack = require('happypack');
  2. const os = require('os');
  3. const HappyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
  4. //启动线程池
  5.  
  6. let happyPackConfig = {
  7. plugins: [
  8. new HappyPack({
  9. id:'jsx',
  10. threadPool: HappyThreadPool,
  11. cache: true,
  12. loaders: ['babel-loader']
  13. })
  14. ]
  15. }
  16.  
  17. {
  18. test: /.jsx?$/,
  19. exclude: /(node_modules|bower_components)/,
  20. use: {
  21. loader: 'HappyPack/loader?id=jsx'
  22. }
  23. }

七、代码分割
分离代码,实现缓存资源和并行加载资源。
对于大型app而言,将所有代码都放在一个文件中是不高效的,尤其是一些代码块只要某些情况下才需要加载。webpack有一个特性,就是能够对项目进行代码分割。代码分割不只是提取通用代码放入可分享的块,更重要的是可以将代码分割成按需加载的块。代码分割可选择,可定义分割点,下面介绍几种分割代码的方法。
1、entry
当项目多入口点时,必须改写默认的output.filename选项,否则每个入口点都会写入相同的文件。
A、多个入口文件,打包在一起;

  1. 'use strict';
  2. const webpack = require("webpack");
  3. module.exports = {
  4. context: __dirname + "/src",
  5. entry: {
  6. app: ["./file1.js", "./file2.js", "./file3.js"]
  7. },
  8. output: {
  9. path: __dirname + "/dist",
  10. filename: "[name].bundle.js"
  11. }
  12. };

打包结果:所有文件会按数组顺序一起打包到dist/app.bundle.js文件中。

B、多个入口文件,分开打包。

  1. const path = require('path');
  2. const HTMLWebpackPlugin = require('html-webpack-plugin');
  3.  
  4. module.exports = {
  5. entry: {
  6. file1: "./file1.js",
  7. file2: "./file2.js",
  8. file3: "./file3.js"
  9. },
  10. plugins: [
  11. new HTMLWebpackPlugin({
  12. title: 'Code Splitting'
  13. })
  14. ],
  15. output: {
  16. filename: '[name].bundle.js',
  17. path: path.resolve(__dirname, 'dist')
  18. }
  19. };

打包结果:dist/file1.bundle.js、dist/file2.bundle.js、dist/file3.bundle.js。

2、CommonsChunkPlugin插件

防止重复,移除重复的依赖模块。

  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const HTMLWebpackPlugin = require('html-webpack-plugin');
  4.  
  5. module.exports = {
  6. entry: {
  7. file1: "./file1.js",
  8. file2: "./file2.js",
  9. file3: "./file3.js"
  10. },
  11. plugins: [
  12. new HTMLWebpackPlugin({
  13. title: 'Code Splitting'
  14. }),
  15. new webpack.optimize.CommonsChunkPlugin({
  16. name: 'common' // 指定公共bundle的名称。
  17. })
  18. ],
  19. output: {
  20. filename: '[name].bundle.js',
  21. path: path.resolve(__dirname, 'dist')
  22. }
  23. };

3、动态import
ES2015模块加载规范定义了import()方法来运行时动态地加载ES2015模块,webpack2将import()作为分割点并将被请求的模块放到一个单独的chunk中,import()接收模块名作为参数,并返回一个Promise。

  1. //webpack.config.js
  2.  
  3. const path = require('path');
  4. const HTMLWebpackPlugin = require('html-webpack-plugin');
  5.  
  6. module.exports = {
  7. entry: {
  8. index: './src/index.js'
  9. },
  10. plugins: [
  11. new HTMLWebpackPlugin({
  12. title: 'Code Splitting'
  13. })
  14. ],
  15. output: {
  16. filename: '[name].bundle.js',
  17. chunkFilename: '[name].bundle.js',
  18. path: path.resolve(__dirname, 'dist')
  19. }
  20. };
  1. // src/index.js
  2.  
  3. function getComponent() {
  4. return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
  5. var element = document.createElement('div');
  6. element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  7. return element;
  8. }).catch(error => 'An error occurred while loading the component');
  9. }
  10.  
  11. getComponent().then(component => {
  12. document.body.appendChild(component);
  13. });

在注释中使用了webpackChunkName,这样做会导致我们的bundle被命名为lodash.bundle.js,而不是[id].bundle.js 。

4、commonjs的require.ensure
require.ensure(dependencies, callback);
require.ensure方法确保回调时,dependencies里的每个依赖都会被同步的引入,require作为参数传递到回调函数中。require.ensure只加载模块,并不执行。

  1. require.ensure(["module-a", "module-b"], function(require) {
  2. var a = require("module-a");
  3. // ...
  4. });

5、AMD的require
reuqire(dependices, callback);
调用时,所有依赖都被加载,callback函数中能得到依赖暴露出来的对象。AMD的require加载并执行模块,在webpack中,模块由左向右执行,允许省略回调函数。

  1. require(["module-a", "module-b"], function (a, b) {// ...})

6、按需加载

像d3,echarts,lodash,antd,比较大,没必要全部加载。

  1. let d3 = Object.assign({},
  2. require("d3-selection"),
  3. require("d3-transition"),
  4. require("d3-shape")
  5. );
  6.  
  7. //为d3.event加上get方法,获取d3Selection.event
  8. Object.defineProperty(d3,"event", {get: function() { return d3Selection.event; }});
  1. // 引入echarts主模块
  2.  
  3. var echarts = require('echarts/lib/echarts');
  4.  
  5. //引入柱状图
  6. require('echarts/lib/component/bar');
  7.  
  8. //引入提示框和标题组件
  9. require('echarts/lib/component/tooltip');
  10. require('echarts/lib/component/title');
  11.  
  12. //基于准备好的dom,初始化echarts
  13.  
  14. var myChart = echarts.init(document.getElementById('main'));
  15.  
  16. //绘制图表
  17. myChart.setOption({
  18. title: { text:'走向社会'},
  19. tooltip:{},
  20. xAxis:{ data:['2013年','2014年','2015年','2016年','2017年','2018年']},
  21. yAxis: {},
  22. series: [{
  23. name: '技术积累',
  24. type: 'bar',
  25. data: [5,8,11,15,19,23]
  26. }]
  27. })
  1. ## 安装lodash相关插件
  2. cnpm i -S lodash-webpack-plugin babel-plugin-lodash
  1. //配置webpack.config.js
  2.  
  3. var LoashModuleReplacementPlugin = require('lodash-webpack-plugin');
  4.  
  5. {
  6. ...,
  7. plugins: [
  8. ...,
  9. new LodashModuleReplacementPlugin({
  10. 'collections': true,
  11. 'shorthands': true
  12. })
  13. ]
  14. }
  1. //在.babelrc中增加lodash配置
  2. {
  3. "plugins": [..., "lodash"]
  4. }
  1. //引用一次,即可调用任意函数,而不会完全打包
  2.  
  3. import _ from 'lodash';
  4. _.add(1,2); //打包时,只会引入add函数

八、缓存不常修改的库文件
不要在开发环境下使用[chunkhash],因为这会增加编译时间。将开发和生产模式的配置分开,并在开发模式中使用[name].js的文件名,在生产模式中使用[name].[chunkhash].js文件名。

1、output.filename

  1. var path = require("path");
  2. var webpack = require("webpack");
  3. var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin");
  4. var WebpackChunkHash = require("webpack-chunk-hash");
  5.  
  6. module.exports = {
  7. entry: {
  8. vendor: "./src/vendor.js",
  9. main: "./src/index.js"
  10. },
  11. output: {
  12. path: path.join(__dirname, "build"),
  13. filename: "[name].[chunkhash:8].js",
  14. chunkFilename: "[name].[chunkhash:8].js"
  15. },
  16. plugins: [
  17. new webpack.optimize.CommonsChunkPlugin({
  18. name: ["vendor", "manifest"],
  19. minChunks: Infinity
  20. }),
  21. new webpack.HashedModuleIdsPlugin(),
  22. new WebpackChunkHash(),
  23. new ChunkManifestPlugin({
  24. filename: "chunk-manifest.json",
  25. manifestVariable: "webpackManifest"
  26. })
  27. ]
  28. };

提升webpack打包速度的更多相关文章

  1. 优化webpack打包速度方案

    基本原理要么不进行打包:要么缓存文件,不进行打包:要么加快打包速度. 不进行打包方案: 1,能够用CDN处理的用CDN处理,比如项目引入的第三方依赖jquery.js,百度编辑器 先进行打包或者缓存然 ...

  2. webpack打包速度和性能再次优化

    一. 改单dll为双dll 因为上图原因,使用CommonsChunkPlugin时,导致其打包出来的vendors.js内的模块ID会因为其他文件引用模块数量的变化而变化. 所以现利用DllPlug ...

  3. 优化Webpack打包速度

    1. Webpack 可以配置 externals 来将依赖的库指向全局变量,从而不再打包这个库,比如对于这样一个文件:   import React from 'react'; console.lo ...

  4. 解决webpack打包速度慢的解决办法

    技巧1 webpack在打包的时候第一次总是会做很长的准备工作,包括加载插件之类的.在刚接触webpack的时候总是webpack一下-测一下-改一下-再webpack一下,这种方式最后让很多人崩溃了 ...

  5. Webpack 打包优化之速度篇

    在前文 Webpack 打包优化之体积篇中,对如何减小 Webpack 打包体积,做了些探讨:当然,那些法子对于打包速度的提升,也是大有裨益.然而,打包速度之于开发体验和及时构建,相当重要:所以有必要 ...

  6. webpack打包性能分析

    1. 如何定位webpack打包速度慢的原因 首先需要定位webpack打包速度慢的原因,才能因地制宜采取合适的方案,我们可以在终端输入: webpack --profile --json > ...

  7. Webpack 打包太慢? 试试 Dllplugin

    webpack在build包的时候,有时候会遇到打包时间很长的问题,这里提供了一个解决方案,让打包如丝般顺滑~ 1. 介绍 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 rea ...

  8. vuecli中配置webpack加快打包速度

    webpack4中webpack 的DllPlugin插件可以将常见的库文件作为dll文件来,每次打包的时候就不用再次打包库文件了. 但是游鱼西在vuecli中已经去除这个选项,意识到带来的打包速度提 ...

  9. 如何将 iOS 工程打包速度提升十倍以上

    如何将 iOS 工程打包速度提升十倍以上   过慢的编译速度有非常明显的副作用.一方面,程序员在等待打包的过程中可能会分心,比如刷刷朋友圈,看条新闻等等.这种认知上下文的切换会带来很多隐形的时间浪费. ...

随机推荐

  1. 腾讯笔试---小Q的歌单

    链接:https://www.nowcoder.com/questionTerminal/f3ab6fe72af34b71a2fd1d83304cbbb3 来源:牛客网 小Q有X首长度为A的不同的歌和 ...

  2. JavaFile、递归、字节流、字符流整理

    File 1.1                File类的构造函数 当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作. 当把持久设备上的数据读取到内存中的这个动作称为输入 ...

  3. 金融量化分析【day112】:量化平台的使用-第一个策略

    一.策略代码 # 导入函数库 import jqdata #初始化函数,设定基准等等 def initialize(context): set_benchmark('000300.XSHG') g.s ...

  4. SpringBoot系列:Pojo validation

    JSR 303 规范了bean validation, Hibernate validator实现了JSR 303所有的规范, 同时也是最常用的validator 工具包. 使用 Hibernate ...

  5. Linux Socket I/O

    Ref: 一文读懂Socket通信原理 幽默讲解 Linux 的 Socket IO 模型

  6. Vue导出json数据到Excel表格

    一.安装依赖 npm install file-saver --save npm install xlsx --save npm install script-loader --save-dev 二. ...

  7. eclipse快捷键 (包括查找类、方法、变量)

    ♦[Ct rl+T] 搜索当前接口的实现类 1. [ALT +/] 智能提示     此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时 ...

  8. centos7环境下apache2.2.34的编译安装

    .获取apache2..34的源码包 http://archive.apache.org/dist/httpd/httpd-2.2.34.tar.gz .获取apache的编译参数 apache的编译 ...

  9. 【原创】大数据基础之Ambari(3)通过Ambari部署Airflow

    ambari2.7.3(hdp3.1) 安装 airflow1.10 ambari的hdp中原生不支持airflow安装,下面介绍如何通过mpack方式使ambari支持airflow安装: 1 下载 ...

  10. javascript中事件对象注册与删除

    事件对象 注册事件 直接给dom对象设置属性,只能给对象设置一个属性,如果设置多个事件处理函数,则最后的生效: 给html标签设置属性,(若法1和法2同时使用,则法1生效): 事件注册 绑定事件监听函 ...