Недавно один маленький друг спросил меня, почему фоновый проект их компании Vue загружается в первый раз больше десяти секунд, что можно оптимизировать, поэтому я открыл их сайт и обнаружил, что основное время уходит на загрузку файла vendor.js. До 2M, так что я взглянул на их код и немного подбросил. Наконец-то получил хорошие результаты.
Идеи оптимизации
Для производительности веб-страницы, как улучшить скорость загрузки и другие принципы и операции, висправлятьБосс этой книги«Принципы и практика оптимизации производительности внешнего интерфейса»Книга очень подробная, и заинтересованные друзья могут пойти и прочитать.
В этой статье основное внимание будет уделено
webpack
С точки зрения упаковки оптимизируйте скорость загрузки первого экрана и оптимизируйте скорость упаковки.
Оптимизация производительности
Я выбрал один, построенный с версией vue-cli2.0+.Vue
+ Vuex
+ Vue-router
+ axios
+ elment-ui
Фоновый системный проект для тестирования, там около 20 страниц маршрутизации асинхронной загрузки.
Мы разделяем оптимизацию на3Это основной угол. После оптимизации каждого угла тестируется скорость скорости упаковки. Время, затрачиваемое на упаковку и сборку, указано ниже:
-
Оптимизируйте resolve.modules, настройте включение и исключение загрузчика, используйте плагин webpack-parallel-uglify-plugin для сжатия кода.
-
Настройте внешние файлы для загрузки файлов библиотеки с помощью cdn
-
webpack DllPlugin, webpack DllReferencePlugin отдельные файлы библиотеки фреймворка
Время\Время упаковки (с) | исходное время конфигурации | Шаг оптимизации 1 | Шаг оптимизации 2 | Шаг оптимизации 3 |
---|---|---|---|---|
1 | 24.86 | ==23.86== | 11.22 | 13.92 |
2 | 23.52 | 14.51 | 11.04 | 12.63 |
3 | 25.49 | 14.04 | 11.29 | 13.19 |
4 | 24.84 | 14.56 | 11.25 | 13.14 |
5 | 24.60 | 15.44 | 11.86 | 14 |
Из этого видно, что все еще может быть достигнуто значительное улучшение более чем на 10 с. Конкретное время, конечно, зависит от вашего проекта. Далее мы подробно расскажем, как это сделать.
Шаги оптимизации
1. Ускорьте упаковку с помощью базовых плагинов webpack
Начнем с изменения основного
webpack
Метод конфигурации улучшает скорость упаковки
1. Оптимизируйте разрешение.модули
принцип:
-
Resolve.modules веб-пакета используется для настройки расположения библиотеки модулей (т. е. node_modules). Когда в js появляется import 'vue', который не является относительным или абсолютным путем, он перейдет в каталог node_modules, чтобы найти его.
-
По умолчанию webpack будет искать рекурсивно вверх. Но обычно в каталоге проекта есть только один node_modules, и он находится в корневом каталоге проекта. Чтобы уменьшить область поиска, мы можем напрямую написать полный путь к node_modules.
Так я обычно пишуimport
При импорте модуля, в который импортируется конкретный файл, также имеет определенное влияние на улучшение скорости упаковки.
действовать:
Открытьbuild/webpack.base.conf.js
файл, добавьте следующееmodules
Блок кода:
module.exports = {
resolve: {
...
modules: [
resolve('src'),
resolve('node_modules')
],
...
},
2. Настройте включение и исключение загрузчика
принцип:
-
webpack
изloaders
Каждый подраздел может иметь атрибуты включения и исключения:
- include: импортированные файлы будут преобразованы загрузчиком в путь или массив файлов (включая каталог для обработки)
- исключить: условия, которые не могут быть выполнены (за исключением каталогов, которые не обрабатываются)
- Мы можем использовать include, чтобы более точно указать, какие каталоги обрабатывать, что может уменьшить ненужный обход и, таким образом, снизить потери производительности.
- В то же время используйте exclude для исключения каталогов, которые уже известны и не нуждаются в обработке, тем самым еще больше повышая производительность.
действовать:
Открытьbuild/webpack.base.conf.js
файл, добавьте следующееinclude
,exclude
Конфигурация:
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig,
include: [resolve('src')], // 添加配置
exclude: /node_modules\/(?!(autotrack|dom-utils))|vendor\.dll\.js/ // 添加配置
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')], // 添加配置
exclude: /node_modules/ // 添加配置
},
Кроме того, если мы решим включить кеширование результатов трансляции в файловую систему, мы сможем как минимум удвоить эффективность работы babel-loader. Для этого нам достаточно добавить в загрузчик соответствующие настройки параметров:
loader: 'babel-loader?cacheDirectory=true'
3. Используйте плагин webpack-parallel-uglify-plugin для сжатия кода
принцип:
- по умолчанию
webpack
использоватьUglifyJS
Плагин выполняет сжатие кода, но оно работает медленно из-за однопоточного сжатия. - Мы можем использовать
webpack-parallel-uglify-plugin
плагин, который может работать параллельноUglifyJS
Плагин может более полно и разумно использовать ресурсы процессора, что значительно сокращает время сборки.Плагин может настроить кеш, чтобы значительно сократить время сборки.
действовать:
1. Установкаwebpack-parallel-uglify-plugin
плагин
yarn add webpack-parallel-uglify-plugin -D
// or
npm i webpack-parallel-uglify-plugin -D
2. Открытьbuild/webpack.prod.conf.js
файл со следующими изменениями
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
...
// 删掉webpack提供的UglifyJS插件
//new UglifyJsPlugin({
// uglifyOptions: {
// compress: {
// warnings: false
// }
// },
// sourceMap: config.build.productionSourceMap,
// parallel: true
//}),
// 增加 webpack-parallel-uglify-plugin来替换
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
warnings: false,
drop_debugger: true, // 去除生产环境的 debugger 和 console.log
drop_console: true
}
}
}),
...
Ускорьте сборку кода с HappyPack
принцип:
- Поскольку Webpack, работающий на Node.js, является однопоточной моделью, вещи, с которыми должен иметь дело Webpack, могут выполняться только одна за другой, а не несколько вещей одновременно.
- Идея обработки HappyPack заключается в том, чтобы расширить многопроцессорный режим от формы одного процесса до процесса выполнения исходного веб-пакета до загрузчика, тем самым ускорив построение кода.
действовать:
Для конкретной эксплуатации этого шага нет не указан. Я чувствую, что эффект не очевиден, и время было добавлено немного. Это может быть связано с проектом. Друзья, которые хотят использовать Baidu, попробуют Это в своих собственных проектах.
Посмотреть эффект
Когда вы выполнили все вышеперечисленные оптимизации, при запуске сборки вы обнаружите, что время первой сборки составляет около 23 секунд, что совпадает с началом, которое составляет чуть меньше 2 секунд (в основном для оптимизации эффекта разрешения). , загрузчик и др.)
При повторной сборке время сильно сокращается, т.к. находится в той же директории.cache/
кэшированныйUglify
Есть много связанных js, которые значительно улучшают скорость строительства. Иди попробуй сейчас. Друзья.
2. Настроить внешние так, чтобы файл библиотеки загружался через cdn
Начните с того, что из-за
vendor.js
Домашняя страница загружается медленно из-за большого размера, но из чего сделан упакованный vendor.js vue?
Проект, сгенерированный vue-cli, интегрированwebpack-bundle-analyzerПоложитесь на инструменты визуального анализа
бегать
npm run build --report
Согласно приведенному выше рисункуvendor.js
Разобран 739kb, пакет в основном содержит такие файлы, какVue
,Vue-router
,elment-ui
Например, файлы библиотек, которые необходимо импортировать глобально. Эти библиотечные файлы являются некоторыми нечастыми изменениями, поэтому мы можем рассмотреть их разделение и введение библиотеки фреймворка с помощью cdn.
принцип:
использоватьwebpack
изexternals
Атрибуты.Документация
Официальное объяснение сайта:не допуститьимпортировать некоторые пакетыПакетВ бандл, но во время выполнения (runtime) для получения этих внешних зависимостей извне (внешних зависимостей).
Популярное объяснение: разрешить установку некоторых пакетов ресурсов, даже если они не установлены локально с помощью npm, черезscript
Может также использоваться после введения этикетки
действовать:
- Сначала в файле шаблона
index.html
добавить следующее в
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XXXX平台</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.4.1/theme-chalk/index.css">
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.17.0/axios.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.4.1/index.js"></script>
<!-- built files will be auto injected -->
</body>
</html>
Уведомление! Номер версии должен быть таким же, какpackage.json
Номера версий в
- Исправлять
build/webpack.base.conf.js
module.exports = {
...
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'axios': 'axios',
'element-ui': 'ELEMENT'
}
...
}
Уведомление! здесьaxios
имя переменной для использованияaxios
Уведомление! здесьelement-ui
имя переменной для использованияELEMENT
,потому чтоelement-ui
изumd
имя модуляELEMENT
- Исправлять
src/router/index.js
// import Vue from 'vue'
import VueRouter from 'vue-router'
// 注释掉
// Vue.use(VueRouter)
...
}
- Исправлять
src/store/index.js
...
// 注释掉
// Vue.use(Vuex)
...
}
- Исправлять
src/main.js
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
// 注释掉
// import 'element-ui/lib/theme-chalk/index.css'
// router setup
import router from './router'
// Vuex setup
import store from './store'
Vue.use(ElementUI)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
Сделанный
После того, как выше настроено, запуститеnpm run build
Установлено, что время построения составляет около 11-12 с, почему улучшение по сравнению с этапом 1 не велико, т.к. на этапе 1ParallelUglifyPlugin
В повторных билдах код не меняется, а кеш играет важную роль
vendor
Только после анализа пакета24KB
Слева и справа файл кадра использует ускорение cdn и механизм кэширования браузера, что позволяет значительно повысить скорость доступа к домашней странице. Мы можем развернуть файл на сервере и открыть сеть Chrome, чтобы просмотреть конкретное время загрузки.
недостаток
- Этот метод нельзя использовать
vue-devtools
В конце концов, инструменты отладки Google напрямую используют пакет онлайн-ресурсов. Однако, выделив и изменив часть кода в соответствии со средой, можно реализовать локальный пакет для среды разработки и использовать упакованные ресурсы CDN. За подробностями обращайтесь к практике этого большого человекаПрактика оптимизации загрузки первого экрана Vue SPA, которые могут быть введены в соответствии с окружающей средой. - Стоимость запроса может быть больше, чем стоимость загрузки.В руководстве по веб-оптимизации необходимо максимально интегрировать файлы и уменьшить количество запросов.Не обязательно иметь много ресурсов cdn. .
3.webpack DllPlugin
,webpack DllReferencePlugin
Предварительно скомпилированные файлы сторонних библиотек
Так как у cdn все еще есть свои недостатки, почему бы нам не рассмотреть вопрос о слиянии файлов библиотеки, поэтому мы используем
webpack.DllPlugin
+webpack DllReferencePlugin
+add-asset-html-webpack-plugin
предварительно скомпилировано и импортировано
принцип:
- использовать
webpack DllPlugin
Плагин упаковывает сторонние плагины отдельно дляvendor.dll.js
- использовать
webpack DllReferencePlugin
это ссылка на эти предварительно скомпилированные модули - использовать
add-asset-html-webpack-plugin
Пучокvendor.dll.js
вставка в пакет html
действовать:
Мы по-прежнему продолжаем изменять код после завершения операции 1 (возвращается соответствующий код операции cdn)
- существует
build
новый в папкеwebpack.dll.conf.js
Содержимое файла следующее (в основном библиотека, которую нужно заранее скомпилировать и запаковать под конфигурацию):
var path = require('path')
var webpack = require('webpack')
var context = path.join(__dirname, '..')
module.exports = {
entry: {
vendor: [
'vue/dist/vue.common.js',
'vuex',
'vue-router',
'axios',
'element-ui'
]
},
output: {
path: path.join(context, 'static/js'), // 打包后的 vendor.js放入 static/js 路径下
filename: '[name].dll.js',
library: '[name]'
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
new webpack.DllPlugin({
path: path.join(context, '[name].manifest.json'),
name: '[name]',
context: context
}),
// 压缩js代码
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: { // 删除打包后的注释
comments: false
}
})
]
}
- редактировать
package.json
файл, добавьте команду компиляции:
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --ext .js,.vue src",
"build": "node build/build.js",
"build:dll": "webpack --config build/webpack.dll.conf.js --progress"
},
Затем запускается командная строкаnpm run build:dll
В это время он будет сгенерирован в static/jsvendor.dll.js
, vendor
Связанные файлы библиотеки в свойствах упакованы.
- Открыть
index.html
здесь будетvendor.dll.js
принести.
<body>
<div id="app"></div>
<script src="./static/js/vendor.dll.js"></script>
</body>
- Открыть
build/webpack.base.conf.js
файл, отредактируйте и добавьте следующую конфигурацию, функция заключается в использовании пакета DLL, созданного DllPlugin через DLLReferencePlugin.
const webpack = require('webpack');
module.exports = {
...
plugins: [
new webpack.DllReferencePlugin({
// name参数和dllplugin里面name一致,可以不传
name: 'vendor',
// dllplugin 打包输出的manifest.json
manifest: require('../vendor.manifest.json'),
// 和dllplugin里面的context一致
context: path.join(__dirname, '..')
})
]
...
}
- Исправлять
build/webpack.prod.js
закомментируйтеCommonsChunkPlugin
Соответствующий код, так как файл библиотеки был скомпилирован в предыдущей версии vendor.dll.js и не нуждается в компиляции.
module.exports = {
plugins: [
...
// 去掉这里的CommonsChunkPlugin
// new webpack.optimize.CommonsChunkPlugin({
// name: 'vendor',
// minChunks (module) {
// // any required modules inside node_modules are extracted to vendor
// return (
// module.resource &&
// /\.js$/.test(module.resource) &&
// module.resource.indexOf(
// path.join(__dirname, '../node_modules')
// ) === 0
// )
// }
// }),
// 去掉这里的CommonsChunkPlugin
// new webpack.optimize.CommonsChunkPlugin({
// name: 'manifest',
// minChunks: Infinity
// }),
...
]
}
Сделанный
На этом этапе сохраните код, соберите его и обнаружите, что время сборки составляет около 14 секунд. Почему больше времени, чем cdn, ведь файлы стилей element-ui тоже нужно каждый раз запаковывать, а стиль отдельно запаковывать не рекомендуется, либо тоже способ использовать cdn.
Наконец, мы по-прежнему развертываем на сервере и открываем сеть Chrome, чтобы просмотреть конкретное время загрузки веб-страницы.
Откройте график зависимостей сборки и найдитеvendor
Файл пропал, его не нужно каждый раз запаковывать, просто импортируйте напрямуюvendor.dll.js
Файл хороший, в этом есть еще одно преимущество: когда у вас несколько проектов с одинаковыми зависимостями, ссылайтесь на одну и ту же копиюdll
Вот и все.
Это действительно закончилось?Ты заметилvendor.dll.js
Это фиксированный файл без суффикса хеш, что фатально для кеша.Когда вы обновляете библиотеку или добавляете файлы библиотеки, переупакованный файл по-прежнему называетсяvendor.dll.js
файл, не повредив кеш, у программы могут возникнуть проблемы при доступе пользователя.
Иногда среда разработки и тестовая среда могут представлятьvendor.dll.js
Путь другой и менять его приходится вручную, что тоже проблема. Так что делать? ?
К счастью, естьadd-asset-html-webpack-plugin
Этот плагин впрыскивает зависимые ресурсы.Я думал, что нашел спасительную соломинку, когда практиковался. Но я не знаю, то ли поза неправильная, то ли плагин устарел и не обновляется.При запуске программа сообщает об ошибке и не может быть использована.Я также надеюсь, что большие ребята, которые использовали его может дать мне несколько советов. .
Эпилог
Пока что об оптимизации в проекте Vue SPA, введение почти такое же, но это только для того, чтобы дать представление. Оптимизация не статична. Для некоторых проектов может потребоваться только шаг 1, а некоторые проекты могут ссылаться на небольшие ресурсы. и принять метод cdn, в то время как некоторые проекты могут использовать cdn.Если зависимости нескольких проектов одинаковы, можно рассмотреть dll.Конечно, выбор и оптимизация должны осуществляться в соответствии с конкретным сценарием.
Наконец, после развертывания на сервере очистите доступ к кешу, а затем проанализируйте время загрузки. Ведь время загрузки гораздо важнее времени упаковки
Однако, когда мы обычно пишем код, мы должны больше думать и обращать внимание на некоторые детали при написании кода, что также может значительно повысить эффективность и производительность.
Пример 1. Многие проекты будут использоватьecharts
, я обнаружил, что некоторые друзья ставятecharts
введенный вmain.js
, это явно лишнее увеличение зряvendor.js
размер, его следует вводить только на странице, которую необходимо использовать, и вы должны обратить вниманиеecharts
Компонент карты в зависимости от того, следует ли использовать синхронный или асинхронный рендеринг, а также в зависимости от окна.resize
, Следует ли обратить внимание на анти-дрожание и дросселирование его.
Пример 2: Когда мы используем jssdk карты Baidu, она находится вindex.html
пройти внутрьscript
Вводятся метки или они загружаются асинхронно, когда странице нужно использовать карту? Все эти вопросы достойны нашего внимания.
Поэтому много размышлений над деталями каждого шага написания кода.
На данный момент я закончил писать, и я также придерживаюсь позиции обучения.Если есть какие-либо ошибки, пожалуйста, поправьте меня, и, кстати, попросите совета.add-asset-html-webpack-plugin
правильная осанка.
приложение
Соответствующий код размещен на githubvue-spa-optimization, с 4 ветками на нем
-
master:
: исходная версия без каких-либо оптимизаций -
simple:
Сделайте соответствующую оптимизированную версию на шаге 1 выше. -
cdn:
Выполнена оптимизированная версия (cdn) шагов 1 и 2 выше. -
dll:
Выполните приведенный выше шаг 1 и шаг 3 оптимизированной версии (dll)