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

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

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

使用动态导入

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

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

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

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

在Webpack中使用动态导入,会新增一个chunk,我们视作异步chunk

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

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

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的额外参数,你可以更进一步地定制它,并且添加上对预先拉取和预先加载的支持。所有这些,都会优化你的用户体验,让你的网站更加灵动。

Webpack 4教程 - 第八部分 使用prefetch和preload进行动态加载的更多相关文章

  1. 【Silverlight】Bing Maps学习系列(八):使用Bing Maps Silverlight Control加载自己部署的Google Maps

    [Silverlight]Bing Maps学习系列(八):使用Bing Maps Silverlight Control加载自己部署的Google Maps 上个月微软必应地图(Bing Maps) ...

  2. webpack动态加载打包chunk命名

    最近,遇到复杂h5页面开发,为了优化H5首屏加载速度,想到使用按需加载的方式,减少首次加载的JavaScript文件体积,于是将处理过程在这里记录一下,涉及到的主要是以下三点: 使用Webpack如何 ...

  3. webpack分包:vue单页面解决分包【减少首屏加载时间】--按需加载[路由懒加载]

    1.使用webpack中的syntax-dynamic-import 插件 npm install --save-dev babel-plugin-syntax-dynamic-import 2.配置 ...

  4. [ionic开源项目教程] - 第7讲 实现下拉刷新上拉加载ion-refresher和ion-infinite-scroll

    第7讲 实现下拉刷新上拉加载ion-refresher和ion-infinite-scroll 1.将tab1.html的代码改为如下: <ion-content> <ion-ref ...

  5. Android简易实战教程--第三十二话《使用Lrucache和NetworkImageView加载图片》

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客    http://blog.csdn.net/qq_32059827/article/details/5279131 ...

  6. 安卓TV开发(八) 移动智能终端多媒体爬虫技术 获取加载网页视频源

    转载请标明出处:http://blog.csdn.net/sk719887916/article/details/40049137,作者:skay 从上一篇学习中,学习了多媒体技术中的怎么去用josu ...

  7. Vue(二十八)el-cascader 动态加载 - 省市区组件

    1.后台接口为点击加载下一级 ,传省市区id <template> <el-cascader v-model="selectedOptions" placehol ...

  8. vue问题八:动态加载loading、浏览器图标

    全局动态加载loading: 参考文档:https://blog.csdn.net/qq_34825875/article/details/79570301 在main.js或者index.js引用  ...

  9. webpack散记---代码分割 和 懒加载

    webpack methods ES 2015 Loader spec (1)webpack methods方法 require.ensure //可以动态加载依赖 []:dependencies / ...

随机推荐

  1. 从HTTP请求中获取客户IP地址

    /**     * 从HTTP请求中获取客户IP地址     *     * @param request http请求     * @return 客户IP地址     */    public s ...

  2. java:安装Runtime Environment,设置Tomcat Server 的方法

    Eclipse 中开发Webapp, 一般需要配置Tomcat Server, 以便在Eclipse 中进行Debug.具体的步骤如下: 1. Windows ==>Preference ==& ...

  3. 数学建模--matlab基础知识

    虽然python也能做数据分析,不过参加数学建模,咱还是用专业的 1. Matlab-入门篇:Hello world! 程序员入门第一式: disp(‘hello world!’) 2. 基本运算 先 ...

  4. NYOJ--42--dfs水过||并查集+欧拉通路--一笔画问题

    dfs水过: /* Name: NYOJ--42--一笔画问题 Author: shen_渊 Date: 18/04/17 15:22 Description: 这个题用并查集做,更好.在练搜索,试试 ...

  5. python中的单引号,双引号和三双引号的区别

    1.单引号和双引号没有区别.都可以用就是为了方便,减少写太多的转义字符. 比如: str='Let\'s go!' str="Let's go!" 两种等价,但是第二种写法显然更优 ...

  6. Gym 101142G : Gangsters in Central City(DFS序+LCA+set)

    题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...

  7. 2017-2018-1 20179215《Linux内核原理与分析》第三周作业

    本次作业分为两部分:第一部分为实验.主要目的是进行基于MYKERNEL的一个简单的时间片轮转多道程序内核代码分析.第二部分为阅读教材,了解LINUX进程调度等. 一.实验部分 实验过程如过程所述:使用 ...

  8. Netty,Netty

    Windows防火墙会自动关闭空闲的TCP链接,所以Netty需要心跳,如果发现链接断开需要进行关闭Session: 怎么来理解TCP的流式传输呢? int blocksize = buffer.re ...

  9. MongoDB优化之二:常见优化方法

    四个方面进行 cpu/io 方面的优化处理: 1.集群架构上进行读写分离.所有查询优先考虑在从库上读取,写操作在主库上执行.避免主库混合读写压力过大,也减少主库上读写记录的锁冲突. connectio ...

  10. Design:目录

    ylbtech-Design:目录 1.返回顶部 1. http://idesign.qq.com/#!index/feed 2. https://www.behance.net/ 3. 2.返回顶部 ...