Webpack 4教程 - 第七部分 减少打包体积与Tree Shaking
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
原文出处:https://wanago.io/2018/08/13/webpack-4-course-part-seven-decreasing-the-bundle-size-with-tree-shaking/
在本次Webpack 4教程中,我们会更进一步讲述项目优化。我们会学习什么是tree shaking以及如何使用它。你会找到让Webpack 4中tree shaking运作起来所需要的东西,并知道怎样从中受益。开始吧!
首先,让我们来回答什么是tree shaking以及它带来什么好处。我们常常在文件中使用具名引入(named imports),这些引入的文件里有其他导出(exports)。在某些情况下,我们并没有引入所有的导出,但Webpack仍会把整个模块都导入进来。这种情况下就需要使用tree shaking了,因为它能帮助我们去除掉用不到的代码。因此打包后的体积能显著下降。
如果你想了解更多关于improts和exports的内容,请查看我们的第一部分-入口、输出和ES6模块。
为了让tree shaking起作用,你需要满足一些配置要求。首先,必须使用ES 6模块,而不是使用诸如CommonJS的模块处理方式。如果你在使用Babel,这一点可能已让你遇到麻烦了。因为Babel的预置默认把任何模块转译成CommonJS模块。你可以简单设置modules: false来解决此问题,在.babalrc或者webpack.config.js中设置都可以。
.babelrc { "presets": [ ["env", { "modules": false } ] ] } // webpack.config.js module: { rules: [ { test: /\.js$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: { presets: ['env', { modules: false }] } } } ] },
如果你想阅读更多babel-loader或常规loaders的内容,可查看教程的第二部分。
你需要使用UglifyJsPlugin。默认情况下,它在mode: "produnction"是被启用。如果你倾向于不使用mode: "produnction",你可以手动添加UglifyJsPlugin。
如果对UglifyJsPlugin不熟,可查看教程的第五部分。
还有一件记得做的事情是,你需要打开optimization.usedExports。它同样在mode: "produnction"时被默认添加上去了。它告诉Webpack去决定每一个模块所用到的导出。有了它,Webpack会在你的打包产出里添加额外的像是/* unused harmony export */之类的注释,UglifyJsPlugin在之后会使用到它们。
Harmony是ES6和ES2015的代号。
让我们来研究有关例子。
// utilities.js export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } // index.js import { add } from './utilities'; console.log(add(1,2)); console.log(add(3,4));
以正常配置运行Webpack,我们得到像下面这样的输出:
/*(...)*/ /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "substract", function() { return substract; }); function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } /***/ }) /******/ ]);
正如你看到的,Webpack没有对我们的打包输出进行tree-shaking。这里同时有add和subtract方法。我们来试验一下,使用下面的配置:
// webpack.config.js const webpack = require('webpack'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const UglifyJS = require('uglify-es'); const DefaultUglifyJsOptions = UglifyJS.default_options(); const compress = DefaultUglifyJsOptions.compress; for(let compressOption in compress) { compress[compressOption] = false; } compress.unused = true; module.exports = { mode: 'none', optimization: { minimize: true, minimizer: [ new UglifyJsPlugin({ uglifyOptions: { compress, mangle: false, output: { beautify: true } }, }) ], } }
我已经关掉了大部分UglifyJsPlugin的配置,以便于我们清楚地看到我们的代码发生了什么。使用上面的配置运行,得到下面输出:
/* (...) */ /* 0 */ /***/ function() { "use strict"; // CONCATENATED MODULE: ./src/utilities.js function add(a, b) { return a + b; } // CONCATENATED MODULE: ./src/index.js console.log(add(1, 2)); console.log(add(3, 4)); /***/} /******/ ]);
由于使用了UglifyJsPlugin的optimization.usedExports和unused选项,不需要的代码被移除了。请注意,那是UglifyJsPlugin的默认行为,所以使用默认配置也能去除无用的代码(当然这样还会进行其他压缩处理)。
Tree shaking函数库
如果你打算对函数库进行tree shaking,你需要记得上一段提到的是事情:使用ES6模块,而它并不是总是被函数库使用。一个绝佳的例子是lodash。如果你去看它提供的产品代码,可以清楚地看到它并没有使用ES6模块。
试想我们打算使用lodash提供的debounce方法。
// index.js import _ from 'lodash'; console.log(_.debounce);
现在你的输出里包含了整个lodash库。当使用import _ from 'lodash'时,这无法避免。但不要担心!有人已经思考过此问题,并创建了一个包叫做lodash-es。它以ES6模块的形式提供了lodash库。
import { debounce } from 'lodash'; console.log(debounce);
不幸的是,Webpack会tree shaking失败。按照ECMAScript规范,所有子模块都需要被评估,因为它们可能包含副作用(side effects)。我推荐阅读一篇Stack Overflow上Sean Larking的好文章(他是Webpack核心团队的成员)。如果一个包的作者想要提供信息以标识它的库没有副作用,他可以在包的package.json文件里做这件事情。如果你查看lodash代码库的package.json文件,你可以看到它有一个"sideEffects: false"。那么问题出在哪儿呢?
Webpac默认会忽略sideEffect标识。如果想改变这种行为,我们需要吧optimization.sideEffects设置成true。你可以手动设置,或者通过mode: "produnction"实现。
// webpack.config.js const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'none', optimization: { minimize: true, minimizer: [ new UglifyJsPlugin() ], usedExports: true, sideEffects: true }, plugins: [ new HtmlWebpackPlugin() ] }
现在lodash库能够被Webpack进行tree shaking了。
总结
为了使tree shaking起作用,需要满足许多条件。它是个很有用的特性,当然也值得学习。希望你通过本文了解如何使用它,让打包后的体积大幅减小。记住你需要使用ES6模块和UglifyJsPlugin。另外,记得配置optimization,把usedExports和sideEffects设为true。
Webpack 4教程 - 第七部分 减少打包体积与Tree Shaking的更多相关文章
- 配置webpack中externals来减少打包后vendor.js的体积
在日常的项目开发中,我们会用到各种第三方库来提高效率,但随之带来的问题就是打包后的vendor.js体积过大,导致加载时空白页时间过长,给用户的体验太差.为此我们需要减少vendor.js的体积,从本 ...
- webpack减少打包后文件体积的几种方法
webpack 把我们所有的文件都打包成一个 JS 文件,这样即使你是小项目,打包后的文件也会非常大.下面就来讲下如何从多个方面进行优化. 去除不必要的插件 刚开始用 webpack 的时候,开发环境 ...
- Webpack 入门教程
Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 本章节基于 Webpack3.0 测试通过. 从图中我们可以看出,W ...
- 全网最贴心webpack系列教程和配套代码
webpack-demos:全网最贴心 webpack 系列教程和配套代码 欢迎关注个人技术博客:godbmw.com.每周 1 篇原创技术分享!开源教程(webpack.设计模式).面试刷题(偏前端 ...
- webpack对多个模块依赖进行打包
[ webpack3.0.0刚刚出来 所以文章是跟着低版本 教程 操作熟悉 结果好多对不上喔] 七:webpack对多个模块依赖进行打包 通过一刚开始我们了解到 webpack支持commonJS ...
- [转]Webpack 入门教程
本文转自:http://www.runoob.com/w3cnote/webpack-tutorial.html Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后 ...
- webpack 使用教程--实时刷新测试
学习webpack,基本始终是围绕: 1.如何安装webpack 2.如何使用webpack 3.如何使用loader 4.如何使用开发服务器 可能我们会在如何使用开发服务器的时候,遇到诸如调试的相关 ...
- webpack使用教程
webpack使用教程 接触webpack也有挺长一段时间了,公司的项目也是一直用着webpack在打包处理,但前几天在教新人的情况下,遇到了一个问题,那就是:尽管网上的webpack教程满天飞,但是 ...
- 配置Tree Shaking来减少JavaScript的打包体积
译者按: 用Tree Shaking技术来减少JavaScript的Payload大小 原文: Reduce JavaScript Payloads with Tree Shaking 译者: Fun ...
随机推荐
- 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析
API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...
- vue学习记录④(路由传参)
通过上篇文章对路由的工作原理有了基本的了解,现在我们一起来学习路由是如何传递参数的,也就是带参数的跳转. 带参数的跳转,一般是两种方式: ①.a标签直接跳转. ②点击按钮,触发函数跳转. 在上篇文章中 ...
- Canvas引入跨域的图片导致toDataURL()报错的问题的解决
本文介绍了Canvas引入跨域的图片导致toDataURL()报错的问题的解决,分享给大家,具体如下: [场景] 用户打开网页,则请求腾讯COS(图片服务器)上的图片js代码.使用canvas绘图. ...
- ArcGIS JS Api 4.x修改三维球背景技巧
通过修改scenceview.js中tileBackground和defaultTileBackground中的png的base64编码就可以达到要求. 4.8中通过修改scenceview. ...
- Android studio无法创建类和接口问题解决办法。提示 Unable to parse template "Class"
重新配置了studio 的工作环境, 没问题,后来加需求要新增java类和接口,这就出现问题了,新建的时候,就会报错: Unable to parse template "Interface ...
- Centos 7 django环境搭建
1.本机网卡配置信息如下: vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE=Ethernet PROXY_METHOD=none BROWSER ...
- 阿里java编码规范考试总结
前几天,考了阿里编码规范刚好80险过,总结出以下例题,答案有错,欢迎评论 1.关于方法的返回值是否可以为null,下列说法正确的是(BCD) A.方法的返回值可以为null,如果是集合,必须返回空集合 ...
- 通过命令行设置Windows 时区
我们在进行自动测试的时候,不同的测试程序对于时区的要求不同,所以在开始的时候需要根据测试程序的要求了设置时区. Windows 提供了一个工具来进行时区设置.tzutil.exe. 目录:C:\Win ...
- Chrome内核浏览器打开网页报 错误代码: ERR_TIMED_OUT
升级win10之后如果出现chrome内核的浏览器网页总是打不开 打开很慢 而ie和edge是可以正常访问的 用这个方法可以 我弄了几天终于 搞好了我直接转载过来了近期,工程师收到大量反馈360浏 ...
- ReactiveSwift源码解析(四) Signal中的静态属性静态方法以及面向协议扩展
上篇博客我们聊了Signal的几种状态.Signal与Observer的关联方式以及Signal是如何向关联的Observer发送事件的.本篇博客继续上篇博客的内容,来聊一下Signal类中静态的ne ...