【译文】使用webpack提高网页性能优化
这篇文章原文来自https://developers.google.com/web/fundamentals/performance/webpack/。
说是译文其实更像是笔者做的笔记,如有错误之处请指正。
减小前端资源大小
使用Production mode(webpack4限定)
webpack提供了mode属性,你可以设置该属性为‘development’或者‘production’。
|
|
更多阅读链接:
压缩资源(webpack3)
可以从bundle-level和loader-specific options两个方面进行。
Bundle-level minification
webpack4:在mode为production时自动进行。
webpack3:使用UglifyJS plugin
Loader-specific options
|
|
定义NODE_ENV=production
这个适用于webpack3,webpack4使用mode=production就行
一些库会判断NODE_ENV的参数然后判断是否打印warnings等。
在webpack4中,你可以这么写:
|
|
在webpack3中,你需要使用DefinePlugin
插件:
|
|
使用这俩种方法都会让webpack在代码中将代码中process.env.NODE_ENV
替换成production
|
|
↓
|
|
而minifier会删除所有的if分支,因为production!==production
总是false,这段代码永远不会执行。
使用ES模块
ES模块就是ES6引入的export和import模块。
当你使用ES modules的时候,webpack可以使用tree-shaking。tree-shaking可以让打包出来的文件在遍历依赖树的时候,移除没有使用的模块。
- 只用导出模块的其中之一的时候:
|
|
- webpack明白commentRestEndpoint没有使用,同时不生成导出模块语句
|
|
- minifier会移除不需要的变量
|
|
Warning:不要不经意将ES modules 编译为 CommonJS 模式
如果用了babel-preset-env或者babel-preset-es2015,请检查presets设置。一半来说ES的import和export会转换为CommonJS的require和module.exports。传入
{modules:false}
来制止这个行为。【译者注】如果需要兼容不支持ES6的浏览器还是不能使用这个特性吧。
优化图片
使用url-lodaer
,svg-url-loader
和image-webpack-loader
优化图片资源。
url-loader的好处是能将根据你配置的小于某个大小的图片,使用Base64 data url的形式将图片嵌入javascript。
|
|
|
|
svg-url-loader和url-loader功能差不多,不过它将文件编码为URL encoding而不是Base64。这点对于SVG图片是比较好的,并且更高效。
|
|
svg-webpack-loader针对IE浏览器呦iesafe:true的选项
优化依赖
JavaScript的有些依赖包的大小比较大,但是我们往往只需要其中的一部分功能。
比如Lodash大概72KB,但是我们只用到了其中的20个方法的话,可能有65KB的代码是浪费的。
另一个例子是Moment.js,它223KB的文件中有大约170KB的文件是多语言本地化库,如果你不需要支持那么多语言的话,那么就需要减负。
优化这些库的方法Google在github开了一个项目,点这里查看。
使用module concatenation(模块连接)
当你打包代码的时候,webpack将import和export的代码包裹在不同函数中。
|
|
↓
|
|
以往是需要从中分离出CommonJS/AMD模块的,但是这个加入了一些多余的代码。
Webpack2加入了ES模块系统,而webpack3使用了module concatenation,看看它是怎么减少代码的:
|
|
↓
|
|
可以看到导出的模块提升到了引入的部分之前,这样之前代码的1部分被移除了。
在webpack4中,我们可以通过optimization.concatenateModules
选项:
|
|
在webpack3中,使用ModuleConcatenationPlugin:
|
|
注意:这个方法虽然好但是没有设置为默认是有原因的,它会增加打包时间并且破坏热更新机制,所以它只能在production模式中使用。
使用externals如果你同时使用webpack和non-webpack的代码
如果项目比较大的话,可能有些代码使用webpack编译而有些没有。比如视频播放页面,视频组件由webpack编译,而别的没有。
这时,如果两部分代码都使用了某个依赖的话,你可以使用externals属性,将webpack编译的代码中这些依赖移除,而使用非webpack部分代码所用依赖。
依赖在window(全局)可用
|
|
|
|
依赖使用AMD模式引入
|
|
|
善用缓存
另一个提升应用性能的方式是使用缓存,缓存可以将部分数据保存在本地,避免重复下载。
使用版本号和缓存http头
1.浏览器对文件采用很长时间的缓存
|
|
如果你不熟悉Cache-Control的话,可以看看这篇文章
2.通过改变文件名(新的版本号)的方式进行重新加载
|
|
通过webpack,你可以使用[chunkhash]
来改变文件名。
|
|
为了在客户端能找到文件名改变了的文件,可以使用HtmlWebpackPlugin
或者WebpackManifestPlugin
。
HtmlWebpackPlugin
用起来比较简单,但是缺乏灵活性。它生成一个包含所有资源的HTML。如果你的服务端逻辑不复杂的话,用它就够了:
|
|
WebpackManifestPlugin
是一个更灵活的方法,在构建过程中它生成一个映射有hash和没hash文件的JSON。可以通过这个JSON文件在服务端找到相应资源。
|
|
Extract dependencies and runtime into a separate file(依赖和运行时代码分开)
针对依赖
应用的依赖通常相较于业务代码改变的频率更低。如果你将它们分开到不同的文件,浏览器会分别对它们进行缓存,这样可以避免每次更新不变的依赖。
在webpack术语中,从应用中分离出的文件称为chunks(块)
1.替换输出文件为[name].[chunkname].js
|
|
2.将entry替换为对象
|
|
3.在webpack中,增加optimization.splitChunks.chunks:'all'
|
|
在webpack3中,使用CommonsChunkPlugin
|
|
这个变量将所有来自于node_modules文件夹的文件打包到vendor.[chunkhash].js
中。
Webpack runtime code
只把vendor代码提出来是不够的,如果在业务代码中改变内容,vendor文件的hash仍然会改变。
这种情况的出现主要是在vendor代码中,有一小块的代码包含了chunk ids和相关文件的映射,这部分代码会改变。
|
|
webpack将这部分运行环境代码放在最后生成的chunk中,在我们的例子里就是vendor,造成了vendor变化。
【译者注】我在vue-cli生成的配置文件里看到了它的解决方案。
1234567 > // extract webpack runtime and module manifest to its own file in order to> // prevent vendor hash from being updated whenever app bundle is updated> new webpack.optimize.CommonsChunkPlugin({> name: 'manifest',> minChunks: Infinity> }),>
>
在webpack4中,可以用optimization.runtimeChunk
选项:
|
|
在webpack中,增加一个空的chunk就可以。(这也是vue-cli的做法)
|
|
将webpack执行环境放在html中减少额外HTTP请求
因为执行环境(runtime)代码很小,将它放在html中可以节省HTTP请求。
将:
|
|
替换为:
|
|
- 如果你使用HtmlWebpackPlugin生成HTML模版
使用InlineSourcePlugin
|
|
- 如果使用服务端逻辑生成HTML模版
在webpck4中:
增加
WebpackManifestPlugin
得到生成的文件名
12345678// webpack.config.js (for webpack 4)const ManifestPlugin = require('webpack-manifest-plugin');module.exports = {plugins: [new ManifestPlugin(),],};这个插件会生成一个这样的文件:
1234// manifest.json{"runtime~main.js": "runtime~main.8e0d62a03.js"}将代码加入HTML中,比如 Node和Express中:
12345678910111213// server.jsconst fs = require('fs');const manifest = require('./manifest.json');const runtimeContent = fs.readFileSync(manifest['runtime~main.js'], 'utf-8');app.get('/', (req, res) => {res.send(`…<script>${runtimeContent}</script>…`);});
或者Webpack3:
将环境代码的文件名固定:
123456789101112// webpack.config.js (for webpack 3)module.exports = {plugins: [new webpack.optimize.CommonsChunkPlugin({name: 'runtime',minChunks: Infinity,filename: 'runtime.js',// → Now the runtime file will be called// “runtime.js”, not “runtime.79f17c27b335abc7aaf4.js”}),],};在服务端中放入内容:
1234567891011// server.jsconst fs = require('fs');const runtimeContent = fs.readFileSync('./runtime.js', 'utf-8');app.get('/', (req, res) => {res.send(`…<script>${runtimeContent}</script>…`);});
懒加载
通过import()
和code-solitting
实现。
|
|
通过import()引入的文件,webpack会将它分离成chunk,当使用到的时候才会加载。
如果使用了Babel,可能会遇上语法错误,你需要使用
syntax-dynamic-import
插件
通过router分割代码
这块现代框架已经做的比较好了,可以参考:
- react-router的code splitting
- vue-router的lazy-loading
监控并分析应用
上几章讲了如何优化,这章主要讲了如何分析应用到底有哪部分过于臃肿,追踪webpack的打包过程。
追踪打包大小
监控应用大小,你可以使用 webpack-dashboard 在开发过程 和 bundlesize 在CI中。
分析为什么bundle过大
你可以用 webpack-bundle-analyzer这个工具分析。
这篇可以在原文中看,这里就不作为重点描述了
【译文】使用webpack提高网页性能优化的更多相关文章
- HTTP/2 服务器推送(Server Push)教程(HTTP/2 协议的主要目的是提高网页性能,配置Nginx和Apache)
HTTP/2 协议的主要目的是提高网页性能. 头信息(header)原来是直接传输文本,现在是压缩后传输.原来是同一个 TCP 连接里面,上一个回应(response)发送完了,服务器才能发送下一个, ...
- 网页性能优化之异步加载js文件
一个网页的有很多地方可以进行性能优化,比较常见的一种方式就是异步加载js脚本文件.在谈异步加载之前,先来看看浏览器加载js文件的原理. 浏览器加载 JavaScript 脚本,主要通过<scri ...
- webpack之前端性能优化(史上最全,不断更新中。。。)
最近在用webpack优化首屏加载性能,通过几种插件之后我们上线前后的速度快了一倍,在此就简单的分享下吧,先上个优化前后首屏渲染的对比图. 可以看到总下载时间从3800ms缩短到1600ms. 我们在 ...
- [转] webpack之前端性能优化(史上最全,不断更新中。。。)
最近在用webpack优化首屏加载性能,通过几种插件之后我们上线前后的速度快了一倍,在此就简单的分享下吧,先上个优化前后首屏渲染的对比图. 可以看到总下载时间从3800ms缩短到1600ms. 我们在 ...
- 网页性能优化:防止JavaScript、CSS阻塞浏览器渲染页面
网页中引用的外部文件: JavaScritp.CSS 等常常会阻塞浏览器渲染页面.假设在 <head> 中引用的某个 JavaScript 文件由于各种不给力需要2秒来加载,那么浏览器渲染 ...
- web前端开发,如何提高页面性能优化?
内容方面: 1.减少 HTTP 请求 (Make Fewer HTTP Requests) 2.减少 DOM 元素数量 (Reduce the Number of DOM Elements) 3.使得 ...
- part8 vue内置标签keep-alive对网页性能优化
我们网页请求时候 我们点击路由切换 可以看network中数据请求 因为每次路由切换都会执行mounted钩子函数 我们这个函数中数据请求 //每次切换路由,页面都会重新渲染 在根组件中使用 路由切换 ...
- 网站性能优化实战——从12.67s到1.06s的故事
文章摘自https://juejin.im/post/5b0b7d74518825158e173a0c 作为互联网项目,最重要的便是用户体验.在举国“互联网+”的热潮中,用户至上也已经被大多数企业所接 ...
- Vue项目性能优化整理
以下方式基于 @vue/cli 快速搭建的交互式项目脚手架 1. 路由懒加载 当打包构建应用时,JavaScript 包会变得非常大,影响页面加载.如果我们能把不同路由对应的组件分割成不同的代码块,然 ...
随机推荐
- 吴裕雄--天生自然 JAVA开发学习:包(package)
package pkg1[.pkg2[.pkg3…]]; package net.java.util; public class Something{ ... } package animals; i ...
- java基本类型和包装类型
int 是基本类型,直接存数值 Integer是类,产生对象时用一个引用指向这个对象 Java把内存划分成两种:一种是栈内存,另一种是堆内存 在函数中定义的一些基本类型的变量和对象的引用变 ...
- selenium 2.x 为什么我录制的脚本回放时几乎必然失败呢?
本人菜鸟一枚,最近自己在自学selenium,录制的脚本回放从未直接成功过! 我打开百度,搜索selenium,然后点击第一个结果——selenium的百度百科,但是提示打开错误! 录制的任何脚本都不 ...
- hm nsis edit请求的操作需要提升
第一次用nsis做安装包,编译运行出现这个问题,解决办法:管理员身份运行即可
- Codeforces Round #573 (Div. 1) 差F
Codeforces Round #573 (Div. 1) E 题意:二维平面上有 n 个点,你可以放至多 m 条直线使得 (0,0) 与每个点的连线至少与一条直线相交.求原点与所有直线的距离最小值 ...
- 手机APP例如抖音,让 people‘s 注意力集中到了 社会进化的 优胜部分 (优胜劣汰,什么是优) + 真善美,的 “美” , 促进了2极分化, 会产生强者俞强,弱者越弱,确实促进了信息的流通,传播了有用的东东 产生了独特的价值 而 如何 能计算出这些价值呢, 需要 数学 金融 财务 货币 量化吗
手机APP例如抖音,让 people‘s 注意力集中到了 社会进化的 优胜部分 (优胜劣汰,什么是优) + 真善美,的 “美” , 促进了2极分化, 会产生 ...
- Python运维中常用的_脚本
前言 file是一个类,使用file('file_name', 'r+')这种方式打开文件,返回一个file对象,以写模式打开文件不存在则会被创建.但是更推荐使用内置函数open()来打开一个文件. ...
- Spring Cloud服务的注册与发现(Eureka)
一.spring cloud简介 spring cloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理.服务发现.断路器.路由.微代理.事件总线.全局锁.决策竞选.分布式会话等等.它运 ...
- C++ sizeof 运算符
sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeof 的语法如下: ...
- [LC] 404. Sum of Left Leaves
Find the sum of all left leaves in a given binary tree. Example: 3 / \ 9 20 / \ 15 7 There are two l ...