webpack拷贝模块-一文看懂webpack的延迟加载机制——webpack系列

2023-08-29 0 6,037 百度已收录

webpack 是现代 JavaScript 应用程序的静态模块捆绑器(modulebundler)。 当 webpack 处理一个应用程序时,它会递归地创建一个包含应用程序所需的每个模块的依赖图(dependency graph),然后将所有这些模块打包到一个或多个包中。

后端工程已经发展到明天,webpack 做出了巨大的贡献。 项目工程带来了很多便利。 我们不再需要自动处理依赖关系,我们可以更方便地使用更有用的框架。 我们可以更加关注业务本身,专心塑造我们的产品。

在 webpack 中,使用延迟加载或按需加载是优化网页或应用程序的好方法。 这些形式实际上是在一些逻辑断点处将你的代码分开,然后在完成某些代码块中的单独操作后,立即引用或正式引用其他新的代码块。 这提高了应用程序的初始加载率并减少了其整体大小,因为单个代码块可能永远不会被加载。

那么,我们来看看webpack对于延迟加载模块做了什么~

实施背景

我们首先假设我们正在完成一个真实的项目,该项目具有上传和下载功能。

下载功能通常是打开链接,所以我们直接在主包中实现。 上传功能可能会使用第三方sdk,我们采用延迟加载的方式进行加载。 只有当用户点击上传时,我们才会加载带有上传功能的包进行上传。

上传下载功能可能会用到一些第三方的sdk,而这个第三方sdk的体积往往很大,这个功能进行懒加载也是情理之中的。

为了演示区别,这里我们区分“下载”和“上传”两个功能。

项目基本配置

我们先构建一个基本的webpack配置来支持延迟加载配置,然后我们就可以直接使用打包后的代码来看看延迟加载的效果了。 我们需要一个基本的目录配置。 项目Demo目录结构如下:

文件/目录说明

源代码

入口文件、下载模块、上传模块

索引.html

html 模板文件

webpack拷贝模块-一文看懂webpack的延迟加载机制——webpack系列

webpack.config.js

webpack 配置文件

包.json

项目文件

功能代码实现

我们看一下我们的功能代码实现,分别是download.js、upload.js、index.js。

// ./src/download.js
const download = () => {
  console.log("download start");
  console.log("schedule download sdk");
  
  console.log("download");
}
export default download;

// ./src/upload.js
const upload = () => {
  console.log("upload start");
  console.log("schedule upload sdk");
  
  console.log("upload");
}
export default upload;

// ./src/index.js
import download from "./download";
console.log("initial page");
async function handlerUploadClick() {
  // 动态加载 upload 模块,该模块的 default 属性就是 upload 方法
  const { default: upload } = await import("./upload");
  // 调用 upload 方法
  upload();
}
async function handlerDownloadClick() {
  download();
}
// 点击 upload 按钮时,调用上传方法
document.querySelector("#upload").addEventListener("click", handlerUploadClick, false)
// 点击 download 按钮时,调用下载方法
document.querySelector("#download").addEventListener("click", handlerDownloadClick, false)


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Webpack LazyLoad</title>
</head>
<body>
  <section>
    <h1>Home</h1>
    <button id="upload">Upload</button>
    <button id="download">Download</button>
  </section>
</body>
</html>

在我们的功能代码实现中,我们实现了一个html网页,该网页有两个按钮,一个是上传按钮,另一个是下载按钮。

配置实现

功能实现后,我们需要配置webpack,然后打包生成一个可以直接运行的项目。

我们新建文件webpack.config.js进行配置,代码实现如下:

// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackChain = require("webpack-chain");
// 使用 webpack chain 组装配置
const chain = new WebpackChain();
// 设置入口文件为 src/index.js
chain.entry("main").add("./src/index.js").end();
// 将构建生成的文件输出到 dist 目录
chain.output.path(path.resolve(__dirname, "./dist")).end();
// 添加 html-webpack-plugin 插件,设置 HTML 模板文件
chain.plugin("html-webpack-plugin").use(HtmlWebpackPlugin, [{
  template: path.resolve(__dirname, "./index.html")
}]);
// 设置 source map 生成规则
chain.devtool("cheap-source-map").end();
// 将配置转成 webpack 可识别的配置对象
const config = chain.toConfig();
module.exports = config;

从代码实现可以看出,我们的webpack配置只是配置了入口、出口、html模板文件。

webpack拷贝模块-一文看懂webpack的延迟加载机制——webpack系列

这样我们就需要配置package.json,并在脚本中添加启动命令。 代码实现如下:

"scripts": {
  "build": "NODE_ENV=development webpack --config webpack.config.js && cd dist && anywhere"
}

Anywhere是一个快速启动http服务的插件,可以使用npmianywhere-g全局安装。

配置完成后,我们需要运行以下命令来安装一些依赖项

npm i webpack webpack-cli webpack-chain html-webpack-plugin anywhere -D

安装完依赖项后,我们就可以计划启动项目了!

运行项目

我们运行npmbuild开始项目编译webpack拷贝模块,命令行输出如下(如右图)

我们的项目通过webpack打包后,输出到dist目录下,但是在8000端口的任意位置运行一个服务。

当我们打开浏览器时,我们可以看到下面的页面。 (如右图)

当我们打开控制台时,我们会听到我们设置的对应输出(如右图)

页面操作

我们来做一些页面操作,首先点击Download按钮,你会发现控制台的输出如下(如右图)

webpack拷贝模块-一文看懂webpack的延迟加载机制——webpack系列

从上图可以看出,调用了download方法,此时进行了一次下载操作(mock操作)。

然后我们此时再次点击Upload按钮,然后观察控制台输出(如右图)

从控制台我们可以看到我们的上传操作已经被调用了,虽然和下载操作没有什么区别。

此时webpack拷贝模块,我们需要切换到网络控制面板来查看网络请求。 (如右图)

从上图我们可以看到,当调用upload方法时,会加载upload方法对应的文件,从而实现延迟加载。

这样做的好处是可以根据需求有效减小主包体积,提升首屏渲染速率,减轻服务器带宽压力。 同时也减少了JS解析时间,提高了页面渲染速度。

延迟加载的实现是后端性能优化的一门专门选修课。 可以说,项目越复杂,这种延迟加载的好处就越大。

实施分析

接下来我们可以看一下webpack编译后的代码,看看webpack是如何实现延迟加载的。

首先,我们看一下主包文件,即dist/main.js。 在此文件中找到我们在 src/index.js 中实现的初始化页面操作。 (如右图)

从上图可以看出,这个操作是直接打包到生成的bundle文件中的。

下载分析

然后我们看一下src/download.js中实现的download方法调用(如右图)

从上图可以看出,handlerDownloadClick最终调用了_download__WEBPACK_IMPORTED_MODULE_0__.default方法。

这个 _download__WEBPACK_IMPORTED_MODULE_0__.default 是什么?

在建立后的代码中,发现了对该对象的形参操作(如右图)

虽然__webpack_require__函数是加载__webpack_modules__中对应的模块,但这里加载的对应模块是“./src/download.js”模块。

最后,我们在dist/main.js中找到了这个模块的定义。 (如右图)

从上图可以看出,虽然这个模块的定义是src/download.js的实现,但它被打包到dist/main.js中,成为__webpack_modules__对象的一部分。

上传分析

看完了download方法的封装实现,我们再来看看惰性上传是如何实现的?

我们首先找到upload对应的函数调用(如右图)

从上图可以看出,当点击上传按钮时,首先使用__webpack_require__.e方法进行加载操作。 我们来看看这个方法做了什么。

该方法首先拼接本模块对应的绝对路径(如右图)

该路径下的文件可能是我们打包后在dist目录下生成的文件(如右图)

然后采用动态插入脚本标签的形式,将相应的脚本文件插入到文档中。 (如右图)

当插入上传对应的文件时,会手动执行。 webpackJsonpCallback 方法将在 src_upload_js.js 脚本文件上执行。 执行完毕后,刚刚延迟加载的模块会被插入到窗口的webpackChunklazyload链表中。 (如右图)

执行该函数后,upload模块会被注册到__webpack_modules__中,之前的调用过程和调用download是一样的~(如右图)

概括

从一个简单的案例,我们了解了webpack的延迟加载实现。

webpack的延迟加载实现在打包的时候会切掉延迟加载的代码单独打包,然后在主包中按需加载,最后执行调用。

最后我们用一张图来梳理一下延迟加载的加载执行过程。 (如右图)

最后一件事

如果你已经听过这个,希望你在离开之前仍然喜欢它~

您的点赞是对作者最大的鼓励,也让更多的人看到这篇文章!

如果您觉得这篇文章对您有帮助,请帮忙在github上点star鼓励一下!

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 webpack webpack拷贝模块-一文看懂webpack的延迟加载机制——webpack系列 https://www.wkzy.net/game/175971.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务