webpack影响路由-Webpack异步加载原理及包传递策略

2023-08-29 0 4,061 百度已收录

原来的:

Webpack异步加载原理

有人称之为webpack保证异步加载,也有人称之为代码切割。 看起来它是将js模块独立导入到.js文件中,然后在使用该模块时创建一个脚本对象并将其添加到document.head对象中。 浏览器会手动发起请求让我们请求js文件,然后编写一个bounce函数让请求的js文件做一些业务操作。

举个例子

需求:main.js依赖两个js文件:A.js是点击aBtn按钮后执行的逻辑,B.js是点击bBtn按钮后执行的逻辑。

webpack.config.js,我们先写webpack打包的配置代码

const path = require('path') // 路径处理模块
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin') // 引入CleanWebpackPlugin插件

module.exports = {
entry: {
index: path.join(__dirname, '/src/main.js'),
},
output: {
path: path.join(__dirname, '/dist'),
filename: 'index.js',
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/index.html'),
}),
new CleanWebpackPlugin(), // 所要清理的文件夹名称
],
}

index.html代码如下

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webpack</title>
</head>
<body>
<div id="app">
<button id="aBtn">按钮A</button>
<button id="bBtn">按钮B</button>
</div>
</body>
</html>

入口文件main.js如下

import A from './A'
import B from './B'

document.getElementById('aBtn').onclick = function () {
alert(A)
}

document.getElementById('bBtn').onclick = function () {
alert(B)
}

A.js和B.js的代码如下

// A.js
const A = 'hello A'
module.exports = A

// B.js
const B = 'hello B'
module.exports = B

此时我们在项目上运行npmrunbuild,只打包了两个文件

可以看到,此时webpack将main.js依赖的两个文件同时打包到同一个js文件中,并导入到index.html中。 而且,A.js和B.js都是需要点击相应按钮才能执行的逻辑。 如果用户没有点击对应的按钮,但是这两个文件都比较大,会不会导致首页默认加载的js文件过大呢? ,导致主页渲染速度变慢? 那么用户点击按钮的时候是否可以加载相应的依赖文件呢?

webpack.ensure 解决了这个问题。

webpack影响路由-Webpack异步加载原理及包传递策略

require.ensure 异步加载

接下来我们将main.js改为异步加载方式

document.getElementById('aBtn').onclick = function () {
//异步加载A
require.ensure([], function () {
let A = require('./A.js')
alert(A)
})
}

document.getElementById('bBtn').onclick = function () {
//异步加载b
require.ensure([], function () {
let B = require('./B.js')
alert(B)
})
}

此时我们再次打包,发现多了两个文件,1.index.js和2.index.js。 当我们打开页面时,我们只导入index.js文件。 当点击按钮A时,会导入1.index.js文件,当点击按钮B时,会导入2.index.js文件。 这满足了我们按需加载的要求。

require.ensure函数是代码分离的分割线,表示弹跳上面的require就是我们要分割的,即require('./A.js'),分割A.js,生成webpack包一个单独的js文件,其句型如下

require.ensure(dependencies: String[], callbackfunction(require), chunkNameString)

我们打开1.index.js文件,发现其代码如下

(window.webpackJsonp = window.webpackJsonp || []).push([
[1],
[
,
function (o, n) {
o.exports = 'hello A'
},
],
])

从前面的代码可以看出:

异步加载的代码会保存在一个全局的webpackJsonp中。

webpackJsonp.push的值,两个参数分别是异步加载文件中存储的待安装模块对应的id和异步加载文件中存储的待安装模块列表。

当满足一定条件时,将执行特定模块中的代码。

import() 按需加载

webpack4官方文档提供了可以按需剪切和加载的模块。 借助es6的按需加载import()方法,可以减少首页的体积,提高首页的请求率。 只有需要时才会加载其他模块。 js.

webpack影响路由-Webpack异步加载原理及包传递策略

import() 的语法非常简单。 该函数只接受一个参数,即引用包的地址,但使用 Promise 风格的反弹来获取加载的包。 代码中import()的所有模块都会被打包成一个单独的包,并放置在存储chunk的目录中。 当浏览器运行到这行代码时,会手动请求这个资源,实现异步加载。

下面我们将上面的代码改为import()方法。

document.getElementById('aBtn').onclick = function () {
//异步加载A
import('./A').then((data) => {
alert(data.A)
})
}

document.getElementById('bBtn').onclick = function () {
//异步加载b
import('./B').then((data) => {
alert(data.B)
})
}

此时打包出来的文件和webpack.ensure的方式是一样的。

路由延迟加载

为什么需要延迟加载?

对于vue这样的单页面应用,如果没有路由的延迟加载,webpack打包的文件会很大,导致进入首页时加载的内容过多webpack影响路由,出现长期蓝屏。 可以使用路由的延迟加载。 定义页面,只在需要的时候才加载页面,可以有效分担首页的加载压力,减少首页的加载时间。

Vue路由延迟加载有以下三种形式

vue 异步组件

这些方法主要利用了resolve的异步机制webpack影响路由,用require代替import来实现按需加载

export default new Router({
routes: [
{
path: '/home',',
component: (resolve) => require(['
@/components/home'], resolve),
},
{
path: '
/about',',
component: (resolve) => require(['@/components/about'], resolve),
},
],
})

要求.确保

这些模式可以通过参数中的webpackChunkName来单独打包js。

export default new Router({
routes: [
{
path: '/home',
component: (resolve) => require.ensure([], () => resolve(require('@/components/home')), 'home'),
},
{
path: '/about',
component: (resolve) => require.ensure([], () => resolve(require('@/components/about')), 'about'),
},
],
})

ES6 导入()

Vue-router在官网提供了一种方式,可以理解为通过Promise的解析机制。 由于Promise函数返回的Promise是resolve组件本身,因此我们可以使用import来导出该组件。

export default new Router({
routes: [
{
path: '/home',
component: () => import('@/components/home'),
},
{
path: '/about',
component: () => import('@/components/home'),
},
],
})

webpack 交付策略

在webpack打包的过程中,经常会出现vendor.js和app.js单个文件很大的情况,而这个文件又恰好是网页第一个加载的文件,会导致加载时间过长,从而导致崩溃时间过长,影响用户体验。 所以我们需要有一个合理的总承包策略。

共享块插件

在Webapck4.x之前,我们使用CommonsChunkPlugin进行分离

plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
return (
module.resource &&
/.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, './node_modules')) === 0
)
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
chunks: 'initial',
minChunks: 2,
}),
]

我们将以下文件分别解压并打包

优化。 分割块

webpack4最大的变化是不仅CommonsChunkPlugin引入了optimization.splitChunks。 如果您的模式是生产模式,那么 webpack4 将手动启用 CodeSplitting。

其外部代码拆分策略如下:

事实上,CodeSplitting 在 webpack4 中会被手动启用。 但在项目规模最大的情况下,这往往不能满足我们的需求,需要进行个性化优化。

应用领域

我们首先找一个优化空间大的项目来运营。 这是一个后台管理系统项目。 大部分内容是由3-4个后端开发的。 通常,开发周期较短,大多数人没有优化的意识。 他们只是编写业务代码来完成需求。 时间一长,就会导致打包下载的文件变大,极大影响性能。

我们首先使用 webpack-bundle-analyzer 来分析打包后的模块依赖关系和文件大小,以确定优化方向在哪里。

然后我们看一下打包好的js文件

看到这两张照片,我的心都碎了。 插槽如下

投诉结束后,我们就开始正事。 正是因为槽位太多,我们才能更好地利用它来验证我们的优化方法的可行性。

提取echart和iview

从前面的分析可以看出,echart和iview文件太大。 这时我们使用webpack4的optimization.splitChunks来分割代码,将它们分开并打包成文件。 (为了更好的呈现优化效果,我们先去掉xlsx.js)

更改 vue.config.js 如下:

chainWebpack: config => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[/]node_modules[/]/,
priority: 10,
chunks: 'initial'
},
iview: {
name: 'chunk-iview',
priority: 20,
test: /[/]node_modules[/]_?iview(.*)/
},
echarts: {
name: 'chunk-echarts',
priority: 20,
test: /[/]node_modules[/]_?echarts(.*)/
},
commons: {
name: 'chunk-commons',
minChunks: 2,
priority: 5,
chunks: 'initial',
reuseExistingChunk: true
}
}
})
},

此时我们用 webpack-bundle-analyzer 来分析一下

打包后的js文件

从这里可以看出,我们已经成功分别提取了echart和iview,vendor.js也相应减小了体积。 据悉,我们还可以继续提取其他更多的第三方模块。

CDN形式

虽然单独提取了第三方模块,但是在加载首页或者对应的路由时,必须要加载这样一个几百kb的文件,不利于性能优化。 这时候我们就可以以CDN的形式引入这样的插件或者UI组件库。

在index.html中引入对应的CDN链接

<head>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/iview/3.5.4/styles/iview.css" />
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.6.8/vue.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/iview/3.5.4/iview.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.8/xlsx.mini.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.8/cpexcel.min.js"></script>
</body>

vue.config.js 配置外部

configureWebpack: (config) => {
config.externals = {
vue: 'Vue',
xlsx: 'XLSX',
iview: 'iView',
iView: 'ViewUI',
}
}

删除之前的导入形式并卸载对应的npm依赖包

npm uninstall vue iview echarts xlsx --save

此时我们看一下打包后的情况

打包后的js文件

做得好! 此时基本没有打包大文件,加载首页所需的vendor.js也只有几十kb,但是我们还可以进一步优化,即通过导入vue全家桶的一些模块cdn,比如vue-router、vuex、axios等。此时加载页面尤其是首页的性能得到很大的优化。

终于

收藏 (0) 打赏

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

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

悟空资源网 webpack webpack影响路由-Webpack异步加载原理及包传递策略 https://www.wkzy.net/game/183943.html

常见问题

相关文章

官方客服团队

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