Webpack 打包之体积优化

谈及现在欣欣向荣的前端圈,不只有各种框架百花齐放,如VueReactAngular等等,就打包工具而言,发展也是如火如荼,百家争鸣;从早期的王者Browserify, Grunt,到后来赢得宝座的 Gulp, 以及独树一帜的 fis3, 以及下一代打包神器 Rollup ;在 browserify,grunt,gulp,rollup,webpack 能够一窥其中部分对比。在本文要探究的是,当前打包工具绝对霸者 Webpackjavascript

舒适提示,如觉此处阅读体验,不尽如人意,可移步首发连接 Webpack 打包优化之体积篇css

Webpack Package optimization

Webpack,当前各大主流框架默认配备的打包方案,对其如何使用,已有较完备中英文文档;而且,各主流框架也有对应 CLI 予以基础配置,故不做为探讨范畴。从产品层来说,如何使得构建的包体积小、运行快,这有必要不断摸索实践,提炼升级,使之臻于最佳。本文将从如下些许方面,对 Webpack 打包体积方面,作下优化探讨(备注Webpack实践版本: 3.3.0):前端

定位 webpack 大的缘由

这里推荐使用 webpack-bundle-analyzer —— Webpack 插件和 CLI 实用程序,她能够将内容束展现为方便交互的直观树状图,让你明白你所构建包中真正引入的内容;咱们能够借助她,发现它大致有哪些模块组成,找到不合时宜的存在,而后优化它。咱们能够在 项目的 package.json 文件中注入以下命令,以方便运行她(npm run analyz),默认会打开 http://127.0.0.1:8888 做为展现。vue

“analyz”: “NODE_ENV=production npm_config_report=true npm run build”java

webpack-bundle-analyzer

固然,同类型的还有 webpack-chart 以及 webpack-analyse,这两个站点也是以可视方式呈现构造的组件,可让你清楚的看到模块的组成部分;不过稍显麻烦的是,你须要运行如下命令,生成工具分析所须要的 json 文件:jquery

webpack --profile --json > stats.json

// 若是,运行指定的 weboack 文件,可用此命令
webpack --config build/webpack.prod.conf.js  --profile --json > stats.json

引入 DllPlugin 和 DllReferencePlugin

DllPlugin 和 DllReferencePlugin 提供了以大幅度提升构建时间性能的方式拆分软件包的方法。其中原理是,将特定的第三方NPM包模块提早构建👌,而后经过页面引入。这不只可以使得 vendor 文件能够大幅度减少,同时,也极大的提升了构件速度。鉴于篇幅,具体用法可参见:webpack.dll.conf.jswebpack

外部引入模块(CDN)

现在前端开发,天然是使用ES6甚至更高版本,撸将起来才更嗨。但因为浏览器兼容问题,仍得使用 babel 转换。而这 babel-polyfill 也得引入以确保兼容;还好比项目开发中经常使用到的 moment, lodash等,都是挺大的存在,若是必须引入的话,即考虑外部引入之,再借助 externals 予以指定, webpack能够处理使之不参与打包,而依旧能够在代码中经过CMD、AMD或者window/global全局的方式访问。git

// webpack 中予以指定
externals: {
  // 'vue': 'Vue',
  // 'lodash': '_',
  'babel-polyfill': 'window'
}

//
<script src="//cdn.bootcss.com/autotrack/2.4.1/autotrack.js"></script>
<script src="//cdn.bootcss.com/babel-polyfill/7.0.0-alpha.15/polyfill.min.js"></script>

须要补充的是 externals 中:key 是 require 的包名,value 是全局的变量。程序员

让每一个第三包“引有所值”

肯定引入的必要性

前端发展到现在时期,假若项目采用了 MVVM模式框架,数据双向绑定,那么像 jQuery 这般类库,不能说没有丝毫引入的必要,至少能够说确实没有引入的必要。对此,若是还有些顾虑,彻底能够参考下 YOU MIGHT NOT NEED JQUERY;用原生写几行代码就能够解决的事儿,实在不易引入这么个庞然大物,平添烦恼。es6

避免类库引而不用

假若这类状况发生,对整个打包体积,不只大并且亏。项目一旦大了,很难人为保证每一个引入的类库,都被有用到,尤为是二次开发。因此工具的利用十分必要,强烈推荐类如 Eslint 这般工具,而且注入对应规则,对声明却未使用的代码,给予强制提醒;这不只能够有效的规避相似情形发生(也适用于普通变量的检测),并且还能使得团队代码风格,尽量地保持类似;要知道代码足够遵照规则,也可以让压缩工具更有效压缩代码,一举多得,何乐不为?

尽可能使用模块化引入

若是说 jQuery 确实没有引入必要,不少人会赞成;但对于 lodash 这类依赖的工具,并非全部人都会去造一发轮子的。然而全包引入 400kb 的体量,能否有让你心肝一颤?幸亏的是,lodash 提供了模块化的引入方式;可按需引入,快哉快哉:

import { debounce } from 'lodash'
import { throttle } from 'lodash'

// 改为以下写法

import debounce from 'lodash/debounce'
import throttle from 'lodash/throttle'

擅懒如你的优秀程序员,是否也发现这样写颇为麻烦?那么恭喜你,这个问题已经被解决;lodash-webpack-pluginbabel-plugin-lodash 的存在(组合使用),便是解决这问题的。它可将全路径引用的 lodash, 自动转变为模块化按使用引入(以下例示);而且所需配置也十分简单,就不在此赘述(舒适提示:当涉及些特殊方法时,尚需些留意)。

// 引入组件,自动转换
import _ from 'lodash'
_.debounce()
_.throttle()

额外补充的是,即使采用如上写法,仍是不够快捷,每一个用到的文件,都写一遍 import,实在多有不便。更可取的是,将项目所需的方法,统一引入,按需添加,组建出本地 lodash 类库,而后 export 给框架层(好比 Vue.prototype),以便全局使用;详情可参见:vue-modular-import-lodash

// helper 文件夹下 lodash,统一引入你须要的方法
import _ from 'lodash'

export default {
  cloneDeep: _.cloneDeep,
  debounce: _.debounce,
  throttle: _.throttle,
  size: _.size,
  pick: _.pick,
  isEmpty: _.isEmpty
}

// 注入到全局
import _ from '@helper/lodash.js'
Vue.prototype.$_ = _

// vue 组件内运用
this.$_.debounce()

尽量引入更合适的包

做为前端开发的你,想必知道有 momentjs 的存在(Parse, validate, manipulate, and display dates in javascript.);更多的是,你想必知道它很好用,然而它的体态却十分丰满(丰盈),没念及此,是否有从新造轮子的冲动?SpaceTime: A lightweight way to manipulate, traverse, compare, and format dates and times across planet Earth。 具备与 monent 类似 api 的新类库,其体积又相对小不少(固然,据观察其灵活度略逊一筹);date-fns:现代JavaScript日期实用程序库( Modern JavaScript date utility library ),如 lodash 同样,可支持模块化;知道这些或者更多的你,会如何选择?

按需异步加载模块

关于前端开发优化,重要的一条是,尽量合并请求及资源,如经常使用的请求数据合并,压缩合并 js,构造雪碧图诸此等等(固然得适当,注意体积,过大不宜);但,同时也当因需制宜,根据须要去异步加载,避免无故就引入早成的浪费。webpack 也是内置对这方面的支持; 假如,你使用的是 Vue,将一个组件(以及其全部依赖)改成异步加载,所须要的只是把:

import Foo from './Foo.vue'

改成以下写法:

const Foo = () => import('./Foo.vue')

如此分割之时,该组件所依赖的其余组件或其余模块,都会自动被分割进对应的 chunk 里,实现异步加载,固然也支持把组件按组分块,将同组中组件,打包在同个异步 chunk 中。如此可以很是有效的抑制 Javascript 包过大,同时也使得资源的利用更加合理化。

生产环境,压缩混淆并移除console

现代化中等规模以上的开发中,区分开发环境测试环境生产环境,并根据须要予以区别对待,已然成为行业共识;可能的话,还会有预发布环境。对待生产环境,压缩混淆能够颇有效的减少包的体积;同时,若是可以移除使用比较频繁的 console,而不是简单的替换为空方法,也是精彩的一笔小优化。若是使用 UglifyJsPlugin 插件来压缩代码,加入以下配置,便可移除掉代码中的 console

new webpack.optimize.UglifyJsPlugin({
  compress: {
    warnings: false,
    drop_console: true,
    pure_funcs: ['console.log']
  },
  sourceMap: false
})

Webpack3 新功能: Scope Hoisting

截止目前(17-08-06), Webpack 最新版本是 3.4.1;Webpack在 3.0 版本,提供了一个新的功能:Scope Hoisting,又译做“做用域提高”。只需在配置文件中添加一个新的插件,就可让 Webpack 打包出来的代码文件更小、运行的更快:

module.exports = {
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
}

据悉这个 Scope HoistingTree Shaking,最初都是由 Rollup 实现的。在我的中实践中,这个功能的注入,对打包体积虽有影响,却不甚明显,有兴趣的盆友能够试下;更对关于此功能讯息,可参见 Webpack 3 的新功能:Scope Hoisting

本文自本月(08)四号开始陆陆续续写,本来的内容意图是,涉及 Webpack 打包优化的体积和速度两个方面;岂料,临近写完的时候(06号晚),已记不得多久没关机的 Mac,居然被重启了下;屋漏多半会偏逢连夜雨,那一贯会自动同步保存(30min)的做业部落,居然没给同步,WTF!整个周末的敲敲打打,皆付之东流,泪崩泪目😂。无奈之下,只得从新写过,直到夜深,才补齐关于体积优化那部分;毕竟涉及内容较多,干脆,就分红两部分来完成😪。也在此提醒广大笔友,及时备份数据并确认,这很重要😂。在此也预告下一篇 《Webpack 打包优化之速度篇》,固然,此文也扔在完善中。

深圳.南山 @17-08-04. Last Modify 17-08-07

原文出处: 晚晴幽草轩
原文连接: Webpack 打包优化之体积篇


猜你喜欢(/对你有用)的文章

『引』最全前端资源聚集
所历前端“姿式”更替记(其一)
Vue ES6 Jade Scss Webpack Gulp
Vue Webpack 组件化开发实践

相关文章
相关标签/搜索