Зачем оптимизировать упаковку?
- Чем больше проект, тем больше зависимых пакетов, а файл пакета слишком большой.
- Домашняя страница одностраничного приложения долгое время остается пустой, а пользовательский интерфейс оставляет желать лучшего.
Наша цель
- Уменьшен размер файла после упаковки
- Главная Импорт файлов по запросу
- Оптимизация времени связывания веб-пакетов
Метод оптимизации
1. Загрузка по требованию
1.1 Компоненты маршрутизации загружаются по запросу
const router = [
{
path: '/index',
component: resolve => require.ensure([], () => resolve(require('@/components/index')))
},
{
path: '/about',
component: resolve => require.ensure([], () => resolve(require('@/components/about')))
}
]
1.2 Компоненты и плагины третьих сторон. Загрузка по требованию требует внедрения сторонних компонентов
// 引入全部组件
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
// 按需引入组件
import { Button } from 'element-ui'
Vue.component(Button.name, Button)
1.3 Для некоторых плагинов, если они используются только в отдельных компонентах, можно также не вводить их в main.js, а вводить в компоненты по мере необходимости
// 在main.js引入
import Vue from vue
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
// 按组件按需引入
import { Vuelidate } from 'vuelidate'
2. Оптимизировать конфигурацию загрузчика
- Оптимизируйте регулярное сопоставление
- Включите кеширование с помощью параметра cacheDirectory.
- Уменьшите количество обрабатываемых файлов с помощью включения и исключения.
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
include: [resolve('src')]
}
]
}
3. Оптимизируйте пути к файлам — сэкономьте время на поиске файлов
- После того, как расширение настроено, вам не нужно добавлять расширение файла при запросе или импорте, он попытается добавить расширение, в свою очередь, для соответствия.
- После того, как mainFiles настроен, вам не нужно добавлять имя файла, он по очереди попытается сопоставить добавленное имя файла.
- alias может ускорить поиск модулей Webpack, настроив псевдонимы.
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
4, производство закрыто
- sourceMap — это, по сути, отношение сопоставления. Код в упакованном файле js можно сопоставить с определенным расположением файла кода. Это отношение сопоставления поможет нам напрямую находить ошибки в исходном коде.
- Скорость упаковки замедляется, а производственный файл становится больше, поэтому среда разработки использует sourceMap, а производственная среда закрывается.
5. Сжатие кода
- UglifyJS: метод сжатия кода по умолчанию, используемый vue-cli, он использует однопоточный код сжатия, а время упаковки медленное.
- ParallelUglifyPlugin: откройте несколько подпроцессов и назначьте работу по сжатию нескольких файлов нескольким подпроцессам для завершения.
Оба метода используются следующим образом:
plugins: [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: true,
parallel: true
}),
new ParallelUglifyPlugin({
//缓存压缩后的结果,下次遇到一样的输入时直接从缓存中获取压缩后的结果并返回,
//cacheDir 用于配置缓存存放的目录路径。
cacheDir: '.cache/',
sourceMap: true,
uglifyJS: {
output: {
comments: false
},
compress: {
warnings: false
}
}
})
]
Сравнение скорости упаковки и размера файла после упаковки
метод | Размер файла | Скорость упаковки |
---|---|---|
без плагинов | 14.6M | 32s |
UglifyJsPlugin | 12.9M | 33s |
ParallelUglifyPlugi | 7.98M | 17s |
6. Извлеките общедоступный код
- Одни и те же ресурсы загружаются повторно, что приводит к потере пользовательского трафика и увеличению затрат на сервер.
- Ресурсы, которые необходимо загрузить для каждой страницы, слишком велики, что приводит к медленной загрузке первой страницы веб-страницы и влияет на взаимодействие с пользователем.
webpack3 использует реализацию CommonsChunkPlugin:
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module, count) {
console.log(module.resource, `引用次数${count}`)
//"有正在处理文件" + "这个文件是 .js 后缀" + "这个文件是在 node_modules 中"
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 с использованием splitChunks:
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
priority: 1, //添加权重
test: /node_modules/, //把这个目录下符合下面几个条件的库抽离出来
chunks: 'initial', //刚开始就要抽离
minChunks: 2 //重复2次使用的时候需要抽离出来
},
common: {
//公共的模块
chunks: 'initial',
minChunks: 2
}
}
}
}
}
7. Оптимизация CDN
- По мере того, как проект становится все больше и больше, он зависит от все большего количества сторонних пакетов npm, и файлы после сборки также будут становиться все больше и больше.
- Вкупе с одностраничным приложением это может привести к длительным белым экранам в случае низкой скорости интернета или ограниченной пропускной способности сервера.
1. Измените пять библиотек vue, vue-router, vuex, element-ui и axios, чтобы получить их через ссылки CDN, и вставьте соответствующие ссылки в index.html.
<head>
<link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.0.7/theme-chalk/index.css" />
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.6.1/index.js"></script>
<!-- built files will be auto injected -->
</body>
2. В конфигурационном файле webpack.config.js
module.exports = {
···
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'element-ui': 'ELEMENT',
'Axios':'axios'
}
},
3. Удалите зависимый пакет npm, npm uninstall axios element-ui vue vue-router vuex
4. Измените предыдущий метод импорта пакета в файле main.js.
// import Vue from 'vue'
// import ElementUI from 'element-ui'
// import 'element-ui/lib/theme-chalk/index.css'
// import VueRouter from 'vue-router'
import App from './App.vue'
import routes from './router'
import utils from './utils/Utils'
Vue.use(ELEMENT)
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'hash', //路由的模式
routes
})
new Vue({
router,
el: '#app',
render: h => h(App)
})
8. Разбирайте и обрабатывайте файлы с помощью многопроцессорного режима HappyPack.
- Поскольку Webpack, работающий на Node.js, является однопоточной моделью, вещи, с которыми должен иметь дело Webpack, должны выполняться одна за другой и не могут выполняться одновременно.
- HappyPack позволяет Webpack разбивать задачу на несколько подпроцессов для одновременного выполнения, а затем отправлять результат основному процессу после того, как подпроцессы его обработают.
- HappyPack не поддерживает загрузчик файлов и URL-адресов, поэтому не рекомендуется использовать этот загрузчик.
Способ применения следующий:
- Установка плагина HappyPack: npm i -D happypack
- Файл webpack.base.conf.js настраивает module.rules.
module: {
rules: [
{
test: /\.js$/,
use: ['happypack/loader?id=babel'],
include: [resolve('src'), resolve('test')],
exclude: path.resolve(__dirname, 'node_modules')
},
{
test: /\.vue$/,
use: ['happypack/loader?id=vue']
}
]
}
- Настроить в рабочей среде файл webpack.prod.conf.js
const HappyPack = require('happypack')
// 构造出共享进程池,在进程池中包含5个子进程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 })
plugins: [
new HappyPack({
// 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
id: 'babel',
// 如何处理.js文件,用法和Loader配置中一样
loaders: ['babel-loader?cacheDirectory'],
threadPool: HappyPackThreadPool
}),
new HappyPack({
id: 'vue', // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
loaders: [
{
loader: 'vue-loader',
options: vueLoaderConfig
}
],
threadPool: HappyPackThreadPool
})
]
Суммировать
- Более практичные методы: загрузка по требованию, оптимизация конфигурации загрузчика, закрытие исходной карты производственной среды и оптимизация CDN.
- Оптимизация, которую сделал vue-cli: сжатие кода, извлечение общего кода, и места для оптимизации не так много.
- Метод оптимизации выбирается в соответствии с реальными потребностями проекта и его собственным уровнем развития, и необходимо избегать ошибок, связанных с оптимизацией.