彻底解决 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 相关文章推荐
为jQuery添加Webkit的触摸的方法分享
Feb 02 Javascript
跟我学Node.js(四)---Node.js的模块载入方式与机制
Jun 04 Javascript
node.js中的http.createClient方法使用说明
Dec 15 Javascript
IE8利用自带的setCapture和releaseCapture解决iframe的拖拽事件方法
Oct 25 Javascript
详解Javascript数据类型的转换规则
Dec 12 Javascript
微信小程序 天气预报开发实例代码源码
Jan 20 Javascript
使用jQuery,Angular实现登录界面验证码详解
Apr 27 jQuery
修改UA在PC中访问只能在微信中打开的链接方法
Nov 27 Javascript
利用原生js实现html5小游戏之打砖块(附源码)
Jan 03 Javascript
Vue项目数据动态过滤实践及实现思路
Sep 11 Javascript
vue axios基于常见业务场景的二次封装的实现
Sep 21 Javascript
微信小程序实现简单文字跑马灯
May 26 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入门源程序
2006/10/09 PHP
PHP下通过file_get_contents的代理使用方法
2011/02/16 PHP
php隐藏IP地址后两位显示为星号的方法
2014/11/21 PHP
php结合ajax实现手机发红包的案例
2016/10/13 PHP
PDO::setAttribute讲解
2019/01/29 PHP
让iframe框架网页在任何浏览器下自动伸缩
2006/08/18 Javascript
JS写的数字拼图小游戏代码[学习参考]
2008/10/29 Javascript
W3C Group的JavaScript1.8 新特性介绍
2009/05/19 Javascript
jquery中animate动画积累的解决方法
2013/10/05 Javascript
javascript避免数字计算精度误差的方法详解
2014/03/05 Javascript
JavaScript学习笔记(三):JavaScript也有入口Main函数
2015/09/12 Javascript
JS实现获取键盘按下的按键并显示在页面上的方法
2015/11/04 Javascript
Node.js开发者必须了解的4个JS要点
2016/02/21 Javascript
Node.js实现文件上传
2016/07/05 Javascript
jQuery实现根据生日计算年龄 星座 生肖
2016/11/23 Javascript
微信小程序 PHP后端form表单提交实例详解
2017/01/12 Javascript
JS失效 提示HTML1114: (UNICODE 字节顺序标记)的代码页 utf-8 覆盖(META 标记)的冲突的代码页 utf-8
2017/06/23 Javascript
React Native第三方平台分享的实例(Android,IOS双平台)
2017/08/04 Javascript
js实现轮播图的两种方式(构造函数、面向对象)
2017/09/30 Javascript
详解React Native 屏幕适配(炒鸡简单的方法)
2018/06/11 Javascript
VUE使用axios调用后台API接口的方法
2020/08/03 Javascript
测试、预发布后用python检测网页是否有日常链接
2014/06/03 Python
python 创建弹出式菜单的实现代码
2017/07/11 Python
基于Python对象引用、可变性和垃圾回收详解
2017/08/21 Python
python画图——实现在图上标注上具体数值的方法
2019/07/08 Python
python pip安装包出现:Failed building wheel for xxx错误的解决
2019/12/25 Python
使用 Python 在京东上抢口罩的思路详解
2020/02/27 Python
解析pip安装第三方库但PyCharm中却无法识别的问题及PyCharm安装第三方库的方法教程
2020/03/10 Python
解决django接口无法通过ip进行访问的问题
2020/03/27 Python
python装饰器代码深入讲解
2021/03/01 Python
美国乡村商店:Plow & Hearth
2016/09/12 全球购物
计算机科学与技术应届生求职信
2013/11/07 职场文书
遗产继承公证书
2014/04/09 职场文书
酒店员工培训方案
2014/06/02 职场文书
学校党员对照检查材料
2014/08/28 职场文书
Mysql数据库事务的脏读幻读及不可重复读详解
2022/05/30 MySQL