Webpack 4教程 - 第八部分 使用prefetch和preload进行动态加载

转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
原文出处:https://wanago.io/2018/08/13/webpack-4-course-part-seven-decreasing-the-bundle-size-with-tree-shaking/javascript

 

本系列的第一篇文章中,咱们讨论了导入(import)和导出(export)。此次咱们深刻介绍动态导入(dynamic import),它值得专门用一篇文章来介绍。咱们会介绍动态导入是什么以及如何使用它们。开始吧!html

在过去,ECMAScript模块是彻底静态的。你必须在运行代码以前指明想要导入和导出的东西。随着动态导入提案的出现,咱们有了额外的选择,即动态地导入模块。如今它进行到了TC39流程的第三个阶段。有了它,你就能够添加动态导入模块了。使用它时,你可能会根据用户及其操做行为的作相应处理。好比,你有一个单页应用,只有当用户决定打开它的子页面时才加载特定代码。这样能够大幅节省应用的初始加载时间。java

使用动态导入webpack

动态导入操做符是做为函数使用的。它接受一个字符串参数,返回一个Promise。当模块加载好后,这个Promise被resolve。git

若是你想了解更多关于Promise的内容,可查看以实现一个排序算法为例解释Promise和回调函数github

document.addEventListener("DOMContentLoaded", () => {
  const button = document.querySelector('#divideButton');
  button.addEventListener('click', () => {
    import('./utilities/divide')
      .then(divideModule => {
          console.log(divideModule.divide(6, 3)); // 2
      })
  });
});

在浏览器的开发者工具,若是打开Network标签,你能够看到,模块开始下载的发生在点击按钮以后,而不是在此以前。值得注意的是,若是再次点击按钮,包含了拆分后的模块文件不会再次被下载。web

在Webpack中使用动态导入,会新增一个chunk,咱们视做异步chunk正则表达式

异步chunk在教程的第四部分-使用SplitChunksPlugin分离代码中有介绍。算法

像这样的chunk会被打包进单独的文件。当使用表达式建立指向其文件的路径时,你须要当心。考虑以下例子:promise

let fileName = '';

document.addEventListener("DOMContentLoaded", () => {
  const button = document.querySelector('#divideButton');
  fileName = 'divide';
  button.addEventListener('click', () => {
    import(`./utilities/${fileName}`)
      .then(divideModule => {
        console.log(divideModule.divide(6, 3)); // 2
      })
  });
});

以上代码在你的项目中被打包事后,你会发现Webpack在utilities文件夹下为每一个模块单首创建了异步chunk。这是由于Webpack不能在编译时知道哪些模块须要被导入。

你还须要知道像import(pathToFile)这样的彻底的动态声明是不起做用的,由于Webpack至少须要一部分文件路径信息。这是由于pathToFile能够是你工程中任何文件的路径,而Webpack会为每一个模块在给定的文件夹中建立异步chunk。你能够自定义此行为,咱们下面就会这么作。

使用在Webpack中使用魔法注释

导入模块的规范不容许你在导入时使用除了文件名之外的参数。幸运的是,有了Webpack,你能够利用所谓的**魔法注释(magic comments)**来使用附加参数。

webpackInclude 和 webpackExclude

在以前的小节,咱们提到Webpack会为每一个模块在咱们给定的文件夹中建立异步chunk。虽然这是默认行为,但它能够修改。

其中一种方法是使用webpackExclude,它是一个正则表达式,用以匹配潜在的可被导入的文件。任何匹配到的文件都不会被打包进来。  

import(
  `./utilities/${fileName}`
  /* webpackExclude: /subtract.js$/ */
)

以上代码表示,文件 subtract.js 文件不会被打包进来,即便它在 utilities 目录下。

与之相反的一个参数叫作webpackInclude。使用它时,只有匹配了正则表达式的模块会被打包。

webpackMode

webpackMode属性定义了resolve动态模块时的模式。支持如下模式:

lazy

这是默认模式。它为每一个动态导入的模块建立异步chunk

lazy-once

使用它,会为知足导入条件的全部模块建立单一的异步chunk

import(
  `./utilities/${fileName}`
  /* webpackMode: "lazy-once" */
)
  .then(divideModule => {
    console.log(divideModule.divide(6, 3)); // 2
  })

以上代码表示,Webpack会为全部 utilities 目录下的全部模块共同建立一个异步chunk。它会致使用户以一个文件下载全部的模块。

eager

此模式会阻止Webpack生成额外的chunk。全部导入的模块被包含在当前chunk,因此不须要再发额外的网络请求。它仍然返回一个Promise,但它被自动resolve。使用eager模式的动态导入与静态导入的区别在于,整个模块只有当**import()**掉用以后才执行。

weak

完全阻止额外的网络请求。只有当该模块已在其余地方被加载过了以后,Promise才被resolve,不然直接被reject。

webpackChunkName

它是新chunk的名字,能够和[index]、[request]变量一块儿使用。

[index]在当前动态导入声明中表示文件的索引。另外一方面,[request]表示导入文件的动态部分。

import(
  `./utilities/${fileName}`
  /* webpackChunkName: "utilities-[index]-[request]" */
)

以上代码可能生成例如 utilities-0-divide.js 这样的文件名。

请注意,若是在某些状况下,肯定只有一个异步chunk(好比原本就没有动态生成路径,或者使用了lazy-once模式),[index]和[request]就不会被使用了。

使用预先拉取和预先加载提高性能

Webpack 4.6.0为咱们提供了预先拉取(prefetching)和预先加载(preloading)的功能。使用这些声明能够修改浏览器处理异步chunk的方式。

预先拉取

使用预先拉取,你表示该模块可能之后会用到。浏览器会在空闲时间下载该模块,且下载是发生在父级chunk加载完成以后。  

import(
  `./utilities/divide`
  /* webpackPrefetch: true */
  /* webpackChunkName: "utilities" */
)

以上的导入会让<link rel="prefetch" as="script" href="utilities.js">被添加至页面的头部。所以浏览器会在空闲时间预先拉取该文件。

预先加载

在资源上添加预先加载的注释,你指明该模块须要当即被使用。异步chunk会和父级chunk并行加载。若是父级chunk先下载好,页面就已可显示了,同时等待异步chunk的下载。这能大幅提高性能。  

import(
  `./utilities/divide`
  /* webpackPreload: true */
  /* webpackChunkName: "utilities" */
)

以上代码的效果是让<link rel="preload" as="script" href="utilities.js">起做用。不当地使用wepbackPreload会损害性能,因此使用的时候要当心。

总结

此次咱们学习了如何使用动态导入提高应用的性能。它们能显著减小页面的初次加载时间。使用可传入Webpack的额外参数,你能够更进一步地定制它,而且添加上对预先拉取和预先加载的支持。全部这些,都会优化你的用户体验,让你的网站更加灵动。

相关文章
相关标签/搜索