webpack插件,实现h5接口预请求,提升页面秒开率~
先有问题再有答案
webpack有哪些必知必会的概念
webpack的插件到底是什么
webpack打包流程是怎样的
实现一个接口预请求插件用来提升页面秒来率
基础概念
-
Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
-
Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
-
Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
-
Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
-
Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
-
Output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。
-
Tapable:是一种实现了发布订阅模式的库,通过 tapable 我们可以注册自定义事件,在合适的时机去触发注册的事件。
-
Compilation 对象: 当 Webpack 以开发模式运行时,每当检测到文件变化,一次新的 Compilation 将被创建。一个 Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。Compilation 对象也提供了很多事件回调供插件做扩展。
-
Compiler 对象: Compiler 对象在 webpack 启动时就已经被实例化,它和 compilation 实例不同,它是全局唯一的,在它的实例对象中,可以得到所有的配置信息,包括所有注册的 plugins 和 loaders。
Compiler 和 Compilation 的区别在于: Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译。
打包流程概括
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
实现插件的流程:
- 一个 JavaScript 命名函数或 JavaScript 类。
- 在插件函数的 prototype 上定义一个
apply
方法。 - 指定一个绑定到 webpack 自身的 事件钩子。
- 处理 webpack 内部实例的特定数据。
- 功能完成后调用 webpack 提供的回调。
一个H5的接口预请求webpack插件
可以应用在首屏接口上 和 js 并行发送请求 减少网络耗时 提升页面秒开率。
原理
插件会在 html 的 head 里面插入一段 code 从 query 上面获取参数 提前进行请求接口,插件会在 window 上挂载 usePreFetchApiService 方法,业务方可以使用此方法来获取结果数据。
功能
- 可以配置一个页面 并行请求多个接口
- 可以配置多个页面 请求一个接口
- 可以配置多个页面请求多个接口
- 多个页面数据通过 hash||path 标识 防止数据互串
- 数据获取 支持静态参数,query 参数,cookie 参数
使用
在vue.config.js文件配置
const PreFetchApiPlugin = require('pre-fetch-api-webpack-plugin');
chainWebpack: config => {
config
.plugin('PreFetchApiPlugin')
.use(PreFetchApiPlugin, [[{
method: 'post',
params: { name: 'username' },
hashList: ['all'],
urls: [
{ url: `/aaa` }
],
}]]);
}
接口获取数据:
const usePreFetchApiService = window.usePreFetchApiService?.();
export const getPageData = async () => {
const { preFetchService } = usePreFetchApiService?.() || {};
if (preFetchService) {
try {
const res = await preFetchService;
//可能设置多个接口 所以返回的是一个数组
return res[0];
} catch (error) {
// 接口请求报错 这里可以再次发送请求
}
} else {
// 因为异常原因 预请求运行报错导致 方法缺失
}
};
关键代码目录
babel-plugin:babel相关插件 build:编译源码ES6->ES5 script: 这里的文件会被自动收集 经过编译后插入到html的header中 src: webpack插件先关逻辑 test: 做一些函数测试
其中在src/index里面的关键代码
// 通过compiler注册插件 通过alterAssetTagsCallback修改html的内容
apply(compiler) {
compiler.hooks.compilation.tap(PluginName, compilation => {
const alterAssetTags = this.alterAssetTagsCallback.bind(this, compilation);
const alterAssetTagGroups
= compilation.hooks.htmlWebpackPluginAlterAssetTags
|| HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups;
alterAssetTagGroups.tapAsync(PluginName, alterAssetTags);
});
}
完整代码
npm_pre-fetch-api-webpack-plugin
github_pre-fetch-api-webpack-plugin
参考
转载自:https://juejin.cn/post/7340236465844731958