Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack学习笔记(12)-浏览器的prefetch和webpack的PrefetchPlugin的使用 #29

Closed
sevenCon opened this issue Nov 4, 2019 · 0 comments
Labels

Comments

@sevenCon
Copy link
Owner

sevenCon commented Nov 4, 2019

前言

预加载技术在浏览器端已经有很长的一段时间了, 但是一直都不温不火, 和预加载prefetch的还有几个类似的属性, preload, dns-prefetch,preconnect, 在webpack里面针对预渲染和预加载,有个插件叫PrefetchPlugin, 顺便理一理预渲染的知识点.

dns-prefetch

这是一个dns-prefetch主动寻址的的例子.

<link rel="dns-prefetch" href="//example.com">

IE9 使用 prefetch 属性来进行dns-prefetch.

dns的寻址时间是不确定的, 而且延迟可变的时间从1ms到几秒不等. 所以针对使用dns-prefetch进行提前进行dns寻址得到ip地址, 可能在多数情况下, 收益是不明显的, 但是可以避免极个别的极端情况.

在chrome里面, 针对http域名的href属性, 是会自动进行prefetch的, 但是在script脚本里面,就需要额外的指定域名进行prefetch了,比如

<link rel ="dns-prefetch" href ="//host.com"/>

而https的域名服务器, 是不会提取href属性提前进行分析dns解析的, 如果需要开启可以通过http协议的请求头设置

<meta http-equiv="x-dns-prefetch-control" content ="on"/>
// or set http header
x-dns-prefetch-control:on

可以设置http的meta信息, 或者http请求头设置x-dns-prefetch-control.

兼容性如下:

备注: 兼容性是挺好的,ie9开始支持,注意的是ie用字段名为prefetch.

preconnect

这是一个相对dns-prefetch更加进一步的操作, 可以提前建立socket连接, 如果是https的服务器, 那么还会提前发送加密套件,进行4步ssl的握手通信.
但是, 也有可能只走完部分的步骤,比如http的协议只完成dns的解析, https协议的请求完成dns解析或者dns解析和tcp连接的建立, 这是由浏览器来根据当前计算机的资源使用情况, 决定是否进行完整的握手.

以下例子:

<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>

具体的步骤为:

  • 解析当前的href是否是个有效的链接
  • 设置origin为当前的host
  • 根据crossorigin的属性,设置是否携带cookie等验证的信息, 如果值为Anonymous,且origin不是当前的host,那么不会携带cookie等验证信息.
  • 尝试去用origin和认证信息去建立链接

备注: 只有IE Edge 15初步开始支持.

prerender

预渲染, 即是提前渲染即将会跳转的页面

<link rel="prerender" href="//example.com/next-page.html">

这可能是个非常昂贵的操作, 预渲染一个页面包括下载里面的子资源, 运行脚本, 虽然一些媒体资源会到真正的调转的时候才会去加载.

但是如果用户不调转, 那么对GPU, CPU, 内存的操作等等相当于白给了, 所以是否在一个页面做预渲染是需要三思而后行.

最后关于预渲染需要说的是, 浏览器会根据当前的cpu, gpu, 内存,网络状况去决策是否进行当前的预渲染是否进行, 也就是说可能会预渲染,也有可能不进行, 所以不能完全依赖预渲染给我们带来的收益.

兼容性:
image

preload

preload为预加载, 提前加载本页的一些资源, 这些资源可能是以下的任意一种.

针对preload的资源有几个属性需要提及的

  • crossorigin, 这个属性有2个可选的值,Anonymous, use-credentials.这2个属性, 设置Anonymous的时候, 会带上origin首部请求,use-credentials则会请求同时带上cookie的验证信息.
  • as, 定义资源的类型,设置这个属性是为了在请求资源的时候,设置accept的首部,类型可选项如上图所示.
  • 'nopush', 禁用服务器推送, 这是针对http 2.0的server push功能的一个优化, 收益颇高, 但是需要考虑到, http2.0的server push有可能被客户端弃用的情况,比如可能有该记录的缓存, 那么会发送 RESET帧进行丢弃.

兼容性:

preload的提前获取可以绕过样式的加载和html的解析, 提前的进行资源的加载, 如果浏览器不支持, 那么将会忽略该标签, preload虽然是优先级比较高,并且一定会进行执行, 不想prefetch,preconnect这2个指令, 执行的效果不彻底,没有达到预期.

但是应用程序在实践的过程中, 需要兼容没有支持该指令的情况下.

prefetch

为了响应跳转的页面, 浏览器允许提前获取将来可能用到的资源, 包括图片, xhr,媒体资源等等,使用的属性和preload一致.
使用如下:

<link rel="prefetch" href="//example.com/next-page.html" as="document" crossorigin="use-credentials">
<link rel="prefetch" href="/library.js" as="script">

prefetchpreload的区别

  • preload的加载是对当前页面, 而prefetch是将来某一个可能的页面
  • preload的优先级比prefetch要高, 不会受到计算机的资源使用情况, 比如CPU, 网络带宽, GPU的情况的影响, 而决定是否加载.

兼容性:

<link ref="prefetch" href="https://code.jquery.com/jquery-3.4.1.min.js" as="script"/>

webpack的PrefetchPlugin

webpack里面有个插件叫PrefetchPlugin,是webpack针对prefetch预加载而提供的一个插件.

他的原文介绍是

Prefetch normal module requests, causing them to be resolved and built before the first import or require of that module occurs. Using this plugin can boost performance. Try to profile the build first to determine clever prefetching points.

意思大概是:
提取一个正常模块请求, 这样他们在被请求或者被打包进行构建的时候, 使用这个插件可以提高性能. 请先进行打包构建的文件模块分析,去决定最优的提取模块.

所以这个插件的时候, 首先需要进行必要的模块分析

生成文件:

webpack --config ./build/webpack.prod.conf.js --json > stats.json

登录这个官网提供的分析网站

http://webpack.github.com/analyse

上传stats.json之后

可以选择Hints模块, 进行必要的检查
比如: 当前的代码中, 同一个模块在多个模块中多次引入,

针对以上的情况, 我们可以单独对这个模块进行提取, 或者把vHeader.vue的模块, 在代码层面进行注册成全局组件, 再或者使用PrefetchPlugin组件进行提起引入, 优化的方向有很多, 可以逐一进行测试,再优综合考虑, 选择最佳的方案.

new webpack.PrefetchPlugin([context], request);
  • context, 参数是可选的参数, 指定的时候项目的绝对路径,
  • request, 则是相对路径, 我们需要提取的模块,在哪个位置?
new webpack.PrefetchPlugin('/Users/quanlincong/Projects/xxx', "./src/components/vHeader.vue");

这样, 打包的时候就会针对我们指定的模块,提前进行prefetch,无论在打包或者模块引入的时候,都会提高效率.

总结

饶了一大圈, 其实最前面的浏览器的prefect,preload等等的内容, 和后面的webpack的prefect并没有什么关系, 哈哈哈, 我开始的时候也以为有关.

参考

https://w3c.github.io/resource-hints/#preconnect
https://dev.chromium.org/developers/design-documents/dns-prefetching
http://www.stevesouders.com/blog/2013/11/07/prebrowsing/
https://www.it-swarm.net/zh/optimization/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8prefetchplugin%E5%92%8Canalyze%E5%B7%A5%E5%85%B7%E4%BC%98%E5%8C%96webpack%E7%9A%84%E6%9E%84%E5%BB%BA%E6%97%B6%E9%97%B4%EF%BC%9F/1055067361/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant