彻底解决 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 相关文章推荐
javascript 面向对象全新理练之原型继承
Dec 03 Javascript
JS获取地址栏参数的小例子
Aug 23 Javascript
javascript新建标签,判断键盘输入,以及判断焦点(示例代码)
Nov 25 Javascript
JS小功能(操作Table--动态添加删除表格及数据)实现代码
Nov 28 Javascript
javascript十六进制及二进制转化的方法
May 06 Javascript
Node.js Sequelize如何实现数据库的读写分离
Oct 23 Javascript
webpack打包js的方法
Mar 12 Javascript
深入Vue-Router路由嵌套理解
Aug 13 Javascript
通过实践编写优雅的JavaScript代码
May 30 Javascript
vuex 动态注册方法 registerModule的实现
Jul 03 Javascript
解决Echarts 显示隐藏后宽度高度变小的问题
Jul 19 Javascript
vue 解决setTimeOut和setInterval函数无效报错的问题
Jul 30 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与SQL注入攻击[二]
2007/04/17 PHP
PHP实时显示输出
2008/10/02 PHP
Laravel 5 框架入门(三)
2015/04/09 PHP
PHP实现UTF8二进制及明文字符串的转化功能示例
2017/11/20 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
javascript 获取图片尺寸及放大图片
2013/09/04 Javascript
JavaScript中的some()方法使用详解
2015/06/09 Javascript
js console.log打印对像与数组用法详解
2016/01/21 Javascript
Bootstrap富文本组件wysiwyg数据保存到mysql的方法
2016/05/09 Javascript
JavaScript之生成器_动力节点Java学院整理
2017/06/30 Javascript
解决IE7中使用jQuery动态操作name问题
2017/08/28 jQuery
jquery 键盘事件的使用方法详解
2017/09/13 jQuery
微信小程序异步处理详解
2017/11/10 Javascript
Vue利用History记录上一页面的数据方法实例
2018/11/02 Javascript
Webpack4+Babel7+ES6兼容IE8的实现
2019/04/10 Javascript
js实现窗口全屏示例详解
2019/09/17 Javascript
jQuery 动态粒子效果示例代码
2020/07/07 jQuery
[56:29]Secret vs Optic 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python BeautifulSoup中文乱码问题的2种解决方法
2014/04/22 Python
Python匹配中文的正则表达式
2016/05/11 Python
python实现自主查询实时天气
2018/06/22 Python
python利用requests库模拟post请求时json的使用教程
2018/12/07 Python
Python 调用 Outlook 发送邮件过程解析
2019/08/08 Python
对YOLOv3模型调用时候的python接口详解
2019/08/26 Python
python 的numpy库中的mean()函数用法介绍
2020/03/03 Python
Python如何发送与接收大型数组
2020/08/07 Python
python打包多类型文件的操作方法
2020/09/21 Python
Myprotein加拿大官网:欧洲第一的运动营养品牌
2018/01/06 全球购物
怎样从/向数据文件读/写结构
2014/11/23 面试题
领导班子四风问题对照检查材料
2014/09/27 职场文书
迎国庆横幅标语
2014/10/08 职场文书
交通局领导班子群众路线教育实践活动对照检查材料思想汇报
2014/10/09 职场文书
三峡导游词
2015/01/31 职场文书
2015年秋季小学开学典礼主持词
2015/07/16 职场文书
快速学习Oracle触发器和游标
2021/06/30 Oracle
Python find()、rfind()方法及作用
2022/12/24 Python