Принцип асинхронной загрузки Webpack
Эта статья включена в githubGitHub.com/Майкл-Ли Чжиган…
webpack ensure
Кто-то называет это асинхронной загрузкой, а кто-то код-обрезкой, по сути, это экспортировать js-модуль в .js-файл самостоятельно, а затем уже при использовании этого модуля создавать другойscript
объект, добавленный вdocument.head
В объекте браузер автоматически инициирует запрос на запрос js-файла, а затем напишет функцию обратного вызова, позволяющую запрошенному 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
На данный момент мы работаем над проектомnpm run build
, запакованы только два файла
- index.html
- index.js
Отсюда видно, что в это времяwebpack
Пучокmain.js
依赖的两个文件都同时打包到同一个 js 文件,并在 index.html 中引入。 ноA.js
а такжеB.js
Это логика, которая будет выполняться только при нажатии соответствующей кнопки.Если пользователь не нажимает соответствующую кнопку, а два файла относительно велики, это приведет к тому, что файл js, загруженный по умолчанию на домашней странице, будет слишком большой, что приводит к замедлению рендеринга домашней страницы Шерстяная ткань? Итак, можно ли загрузить соответствующий файл зависимостей, когда пользователь нажимает кнопку?
webpack.ensure
Это решило проблему.
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
Файл, который импортируется только при нажатии кнопки A1.index.js
файл, который импортируется только при нажатии кнопки B2.index.js
документ. Это удовлетворяет наш спрос на загрузку по требованию.
require.ensure
Эта функция представляет собой разделенную кодом разделительную линию, представляющуюrequire
это то, что мы хотим разделить, то естьrequire('./A.js')
, разделите A.js, чтобы сформироватьwebpack
Упакованные отдельные файлы js. Его синтаксис следующий
require.ensure(dependencies: String[], callback: function(require), chunkName: String)
мы открыты1.index.js
файл, нашел его код следующим образом
;(window.webpackJsonp = window.webpackJsonp || []).push([
[1],
[
,
function (o, n) {
o.exports = 'hello A'
},
],
])
Как видно из кода выше:
- Асинхронно загружаемый код будет сохранен в глобальном
webpackJsonp
середина. -
webpackJsonp.push
Значение двух параметров — это идентификатор, соответствующий модулю, который должен быть установлен, сохраненный в асинхронно загруженном файле, и список модулей, которые должны быть установлены, сохраненный в асинхронно загруженном файле. - При определенных условиях будет выполняться код в конкретном модуле.
import() загружается по запросу
Официальная документация webpack4 обеспечивает вырезание и загрузку модулей по требованию в сочетании с загрузкой по требованию es6.import()
Этот метод может уменьшить объем пакета домашней страницы и ускорить скорость запросов домашней страницы, только другие модули будут загружать соответствующие js только при необходимости.
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, будет очень большим, что приведет к загрузке слишком большого количества контента при входе на домашнюю страницу, и появится длинный белый экран. могут быть разделены, а страницы загружаются только при необходимости, что может эффективно распределить давление загрузки домашней страницы и сократить время, необходимое для загрузки домашней страницы.
Ленивая загрузка маршрутизации Vue имеет следующие три способа:
- vue асинхронный компонент
- ES6
import()
- веб-пакет
require.ensure()
vue асинхронный компонент
Этот метод используется в основномresolve
асинхронный механизм, использующийrequire
вместоimport
Реализовать загрузку по требованию
export default new Router({
routes: [
{
path: '/home',',
component: (resolve) => require(['@/components/home'], resolve),
},
{
path: '/about',',
component: (resolve) => require(['@/components/about'], resolve),
},
],
})
require.ensure
Этот режим можно передать в параметре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
изresolve
механизм. потому что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
Когда один файл большой, это первый файл, загружаемый на веб-страницу, что делает время загрузки слишком долгим, что делает время белого экрана слишком долгим и влияет на работу пользователя. Поэтому нам нужна разумная стратегия субподряда.
CommonsChunkPlugin
До версии 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,
}),
]
Извлекаем и упаковываем отдельно следующие файлы
-
node_modules
под папку, модуль - по 3 входа
chunk
общий модуль
optimization.splitChunks
Самое большое изменение в webpack 4 заключается в том, что он упразднен.CommonsChunkPlugin
представилoptimization.splitChunks
. если вашmode
даproduction
, то автоматически запустится webpack4Code Splitting
.
Его встроенная стратегия разделения кода выглядит следующим образом:
- Является ли новый фрагмент общим или получен из
node_modules
модуль - Размер нового фрагмента больше 30 КБ перед сжатием.
- Количество одновременных запросов на загрузку чанков по запросу меньше или равно 5
- Количество одновременных запросов при первоначальной загрузке страницы меньше или равно 3
Хотя он автоматически откроется в WebPack4Code Splitting
, но при самом крупном проектировании это часто не может удовлетворить наши потребности, и нам необходимо проводить персонифицированную оптимизацию.
Приложения
Сначала мы находим проект с большим пространством для оптимизации. Это фоновый проект системы управления.Большая часть контента разрабатывается 3-4 фронтендами.Цикл разработки обычно короткий, и большинство людей не осведомлены об оптимизации.Они просто пишут бизнес-код для удовлетворения требований.Как время идет, упакованные файлы генерируются больших размеров, что сильно влияет на производительность.
мы сначала используемwebpack-bundle-analyzer
Проанализируйте зависимости упакованного модуля и размер файла, чтобы определить направление оптимизации.
Тогда давайте посмотрим на упакованный файл js.
Смотрите две карты времени, мое сердце рухнуло, следующая точка канавки
- После упаковки создается несколько js-файлов размером около 1 М, многие из которых
vendor.js
Большие файлы, которые должны быть загружены на главной странице -
xlsx.js
Нет необходимости использовать такой плагин, лучший способ экспортировать Excel должен состоять в том, чтобы вернуть формат файлового потока из бэкэнда во внешний интерфейс для обработки. -
echart
а такжеiview
Файл слишком большой, следует использовать метод, представленный cdn
После того, как мы закончили разглагольствовать, мы собираемся перейти к делу. Именно потому, что есть так много слотов, мы можем лучше использовать его для проверки осуществимости нашего метода оптимизации.
оторваться от echart и iview
Из вышеприведенного анализа видно, чтоechart
а такжеiview
Файл слишком большой, в данный момент мы используем webpack4optimization.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 путь
Хотя сторонний модуль извлекается отдельно, все равно не способствует оптимизации производительности загрузка такого файла в несколько сотен кб при загрузке домашней страницы или соответствующего маршрута. В настоящее время мы можем использовать CDN для внедрения таких плагинов или библиотек компонентов пользовательского интерфейса.
- существует
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
настроитьexternals
configureWebpack: (config) => {
config.externals = {
vue: 'Vue',
xlsx: 'XLSX',
iview: 'iView',
iView: 'ViewUI',
}
}
- Удалите предыдущий метод импорта и удалите соответствующие зависимости npm.
npm uninstall vue iview echarts xlsx --save
На этом этапе давайте посмотрим на ситуацию после упаковки.
Упакованный файл js
молодец!В это время в основном не упакован большой файл, а домашняя страница подгружает нужныйvendor.js
Это всего несколько десятков килобайт, и мы можем оптимизировать его, внедрив некоторые модули семейства vue через метод cdn, такие какvue-router
,vuex
,axios
Ждать. В настоящее время производительность страницы, особенно загрузка домашней страницы, была значительно оптимизирована.