彻底解决 webpack 打包文件体积过大问题


Posted in Javascript onJuly 07, 2017

webpack 把我们所有的文件都打包成一个 JS 文件,这样即使你是小项目,打包后的文件也会非常大。下面就来讲下如何从多个方面进行优化。

去除不必要的插件

刚开始用 webpack 的时候,开发环境和生产环境用的是同一个 webpack 配置文件,导致生产环境打包的 JS 文件包含了一大堆没必要的插件,比如 HotModuleReplacementPlugin, NoErrorsPlugin... 这时候不管用什么优化方式,都没多大效果。所以,如果你打包后的文件非常大的话,先检查下是不是包含了这些插件。

提取第三方库

像 react 这个库的核心代码就有 627 KB,这样和我们的源代码放在一起打包,体积肯定会很大。所以可以在 webpack 中设置

{
 entry: {
  bundle: 'app'
  vendor: ['react']
 }

 plugins: {
  new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js')
 }
}

这样打包之后就会多出一个 vendor.js 文件,之后在引入我们自己的代码之前,都要先引入这个文件。比如在 index.html 中

<script src="/build/vendor.js"></script>
 <script src="/build/bundle.js"></script>

除了这种方式之外,还可以通过引用外部文件的方式引入第三方库,比如像下面的配置

{
 externals: {
   'react': 'React'
 }
}

externals 对象的 key 是给 require 时用的,比如 require('react'),对象的 value 表示的是如何在 global 中访问到该对象,这里是 window.React。这时候 index.html 就变成下面这样

<script src="//cdn.bootcss.com/react/0.14.7/react.min.js"></script>
<script src="/build/bundle.js"></script>

当然,个人更推荐第一种方式。

目前推荐用 DLL 的方式提取第三方库。

代码压缩

webpack 自带了一个压缩插件UglifyJsPlugin,只需要在配置文件中引入即可。

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

加入了这个插件之后,编译的速度会明显变慢,所以一般只在生产环境启用。

另外,服务器端还可以开启 gzip 压缩,优化的效果更明显。

代码分割

什么是代码分割呢?我们知道,一般加载一个网页都会把全部的 js 代码都加载下来。但是对于 web app 来说,我们更想要的是只加载当前 UI 的代码,没有点击的部分不加载。

看起来好像挺麻烦,但是通过 webpack 的 code split 以及配合react router 就可以方便实现。具体的例子可以看下 react router 的官方示例huge apps。不过这里还是讲下之前配置踩过的坑。

code split 是不支持 ES6 的模块系统的,所以在导入和导出的时候千万要注意,特别是导出。如果你导出组件的时候用 ES6 的方式,这时候不管导入是用 CommomJs 还是 AMD,都会失败,而且还不会报错!

当然会踩到这个坑也是因为我刚刚才用 NodeJS,而且一入门就是用 ES6 的风格。除了这个之外,还有一点也要注意,在生产环境的 webpack 配置文件中,要加上 publicPath

output: {
  path: xxx,
  publicPath: yyy,
  filename: 'bundle.js'
}

不然的话,webpack 在加载 chunk 的时候,路径会出错。

设置缓存

开始这个小节之前,可以先看下大神的一篇文章:大公司里怎样开发和部署前端代码。

对于静态文件,第一次获取之后,文件内容没改变的话,浏览器直接读取缓存文件即可。那如果缓存设置过长,文件要更新怎么办呢?嗯,以文件内容的 MD5 作为文件名就是一个不错的解决方案。来看下用 webpack 应该怎样实现

output: {
  path: xxx,
  publicPath: yyy,
  filename: '[name]-[chunkhash:6].js'
}

打包后的文件名加入了 hash 值

const bundler = webpack(config)

bundler.run((err, stats) => {
 let assets = stats.toJson().assets
 let name

 for (let i = 0; i < assets.length; i++) {
  if (assets[i].name.startsWith('main')) {
   name = assets[i].name
   break
  }
 }

 fs.stat(config.buildTemplatePath, (err, stats) => {
  if (err) {
   fs.mkdirSync(config.buildTemplatePath)
  }

  writeTemplate(name)
 })
})

手动调用 webpack 的 API,获取打包后的文件名,通过 writeTemplate 更新 html 代码。完整代码猛戳 gitst。

这样子,我们就可以把文件的缓存设置得很长,而不用担心更新问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法
May 17 Javascript
JavaScript表单焦点自动切换代码
Jul 24 Javascript
Javascript中常用的检测方法小结
Oct 08 Javascript
值得分享的JavaScript实现图片轮播组件
Nov 21 Javascript
JS实现的DIV块来回滚动效果示例
Feb 07 Javascript
jQuery中 bind的用法简单介绍
Feb 13 Javascript
基于JavaScript实现的顺序查找算法示例
Apr 14 Javascript
JavaScript代码执行的先后顺序问题
Oct 29 Javascript
微信小程序实现星级评分和展示
Jul 05 Javascript
小试SVG之新手小白入门教程
Jan 08 Javascript
vue实现手机号码的校验实例代码(防抖函数的应用场景)
Sep 05 Javascript
vuex state中的数组变化监听实例
Nov 06 Javascript
JS仿QQ好友列表展开、收缩功能(第一篇)
Jul 07 #Javascript
JS仿QQ好友列表展开、收缩功能(第二篇)
Jul 07 #Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
Jul 07 #Javascript
详解vue.js+UEditor集成 [前后端分离项目]
Jul 07 #Javascript
JS实现搜索关键词的智能提示功能
Jul 07 #Javascript
vue.js国际化 vue-i18n插件的使用详解
Jul 07 #Javascript
javascript ES6 新增了let命令使用介绍
Jul 07 #Javascript
You might like
PHP设置一边执行一边输出结果的代码
2013/09/30 PHP
php生成二维码
2015/08/10 PHP
php实现xml转换数组的方法示例
2017/02/03 PHP
PHP实现类似题库抽题效果
2018/08/16 PHP
JQuery 插件制作实践 xMarquee插件V1.0
2010/04/02 Javascript
js 获取子节点函数 (兼容FF与IE)
2010/04/18 Javascript
禁用Enter键表单自动提交实现代码
2014/05/22 Javascript
jQuery学习笔记之jQuery原型属性和方法
2014/06/09 Javascript
下拉框select的绑定示例
2014/09/04 Javascript
JavaScript定义类和对象的方法
2014/11/26 Javascript
浅谈JavaScript function函数种类
2014/12/29 Javascript
深入理解JavaScript系列(30):设计模式之外观模式详解
2015/03/03 Javascript
Bootstrap实现input控件失去焦点时验证
2016/08/04 Javascript
jQuery EasyUI ProgressBar进度条组件
2017/02/28 Javascript
vue中如何实现变量和字符串拼接
2017/06/19 Javascript
Bootstrap 3多级下拉菜单实例
2017/11/23 Javascript
vue cli使用绝对路径引用图片问题的解决
2017/12/06 Javascript
从零开始搭建webpack+react开发环境的详细步骤
2018/05/18 Javascript
JS中比较两个Object数组是否相等方法实例
2019/11/11 Javascript
Vue 解决父组件跳转子路由后当前导航active样式消失问题
2020/07/21 Javascript
vue祖孙组件之间的数据传递案例
2020/12/07 Vue.js
[01:15:18]2014 DOTA2国际邀请赛中国区预选赛 LGD VS Speed Gaming.cn
2014/05/22 DOTA
[01:13:51]TNC vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
实用自动化运维Python脚本分享
2018/06/04 Python
Python人脸识别第三方库face_recognition接口说明文档
2019/05/03 Python
python pytest进阶之conftest.py详解
2019/06/27 Python
pymysql之cur.fetchall() 和cur.fetchone()用法详解
2020/05/15 Python
python代码如何注释
2020/06/01 Python
Python列表嵌套常见坑点及解决方案
2020/09/30 Python
HTML5之SVG 2D入门6—视窗坐标系与用户坐标系及变换概述
2013/01/30 HTML / CSS
新学期家长寄语
2014/01/19 职场文书
消防宣传口号
2014/06/16 职场文书
陈安之励志演讲稿
2014/08/21 职场文书
你对自己的信用报告有过了解吗?
2019/07/09 职场文书
mybatis3中@SelectProvider传递参数方式
2021/08/04 Java/Android
CSS使用SVG实现动态分布的圆环发散路径动画
2022/12/24 HTML / CSS