Следуйте за Vue-cli, чтобы «изучить» и «изменить» оптимизацию упаковки Webpack.

Webpack
Следуйте за Vue-cli, чтобы «изучить» и «изменить» оптимизацию упаковки Webpack.

Прежде всего, нам нужно знать, что использовать для упаковки с помощью веб-пакета и каковы преимущества этой упаковки. Мы можем просто перечислить следующие пункты:

  • Однофайловые компоненты (файлы .vue)
  • Оптимизация процесса сборки Vue (псевдоним и т. д.)
  • Управление кешем браузера
  • Разделение кода (ленивая загрузка и т. д.)

В этой статье основное внимание уделяется оптимизации упаковки веб-пакетов.Управление кешем браузера, В конфигурации скаффолдинга, генерируемого vue-cli, было сделано много оптимизации обработки для упаковки и кэширования.Эта статья позволит изучить знания и внести изменения в будущем.

Понять, как работает кеширование браузера

Перед этим нам нужно понять, как работает кеш браузера, сначала скопируйте картинку.

  • Браузер: мне нужен test.js
  • Сервер: Нашел для вас, и не заходите ко мне 259200 секунд (один месяц)
  • Браузер: ок, тогда я кеширую на диск

Через неделю снова посетите эту страницу

  • Браузер: мне нужен test.js, истечение срока действия кеша все еще существует, чтение напрямую с диска
  • Сервер: Ничего общего со мной
  • Пользователь: Вау, так быстро открывается страница

Изменена иконка по просьбе продакт-менеджера

  • Браузер: мне нужен test.js, истечение срока действия кеша все еще существует, чтение напрямую с диска
  • Менеджер продукта: Он выпущен? Уверен? Почему это не работает?
  • Сервер: есть дыню

После того, как мы разобрались с принципом, мы знаем, как разрушить механизм кеша и позволить браузеру запрашивать новые файлы.

технология очистки кеша

ctrl+F5 Принудительно обновить страницу

Вручную принудительно обновить страницу, но пользователи не программисты, откуда им знать, что требуется принудительное обновление, поэтому для пользователей это решение однозначно невыполнимо.

изменить файл

  1. Измените имя файла: test.js -> test.v2.js
  2. Измените путь к файлу: /static/test.js -> /static/v2/test.js
  3. Добавить строку запроса: test.js -> test.js?v=qwer

После того, как мы поняли, как очистить кеш, давайте посмотрим, как настроить шаблон Vue-cli.

Разделение кода

Что такое разделение кода

Мы напрямую создаем новый проект Vue-cli, запускаем команду сборки npm run сразу после установки зависимостей и открываем каталог файлов /dist/js.

Выяснилось, что файлов js 3, из-за чего webpack разделил код.

Почему разделение кода

  1. Отдельный бизнес-код и сторонние библиотеки (вендор)
  2. Загрузка по запросу (с использованием синтаксиса import())

Причина, по которой бизнес-код и код сторонней библиотеки разделены, заключается в том, что требования менеджера по продукту непрерывны, поэтому бизнес-код часто обновляется.Наоборот, итерация обновления кода сторонней библиотеки относительно медленная, и версия может быть заблокирована, поэтому ее можно полностью использовать.Кэш браузера для загрузки этих сторонних библиотек.

В применимом сценарии загрузки по требованию, таком как «загрузка соответствующего компонента при доступе к определенному маршруту», пользователь может не получить доступ ко всем маршрутам, поэтому нет необходимости загружать компоненты, соответствующие всем маршрутам в начале . ; Более типичный пример: «некоторые пользователи имеют доступ только к определенным страницам», поэтому нет необходимости загружать код для страниц, к которым у них нет доступа.

Разделение кода веб-пакета vue-cli

Отдельный бизнес-код и сторонние библиотеки (вендор)

используется в vue-cliCommonsChunkPluginЭтот плагин веб-пакета для извлечения кода фреймворка. Откройте файл webpack.prod.conf.js и найдите следующий код.

new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function (module, count) {
    // 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
    )
  }
}),

Когда этот код упакован,node_modules ниже, а зовут.js заканчивается,а такжене дублирующий модульизвлечь вvenderв.

Поэтому после упаковки должны быть сгенерированы два файла: app.js (бизнес-код) и vendor.js (код фреймворка).Внимательные студенты могут обнаружить, что существует еще и manifest.js, о котором мы расскажем позже.

Загрузка по запросу (с использованием синтаксиса import())

Если мы изменим метод загрузки компонента hello, чтобы маршрутизировать ленивую загрузку (синтаксис import()), мы упаковываем

// import Hello from '@/components/Hello'

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

Очевидно, что после упаковки файлов js 4. Внимательные студенты также обнаружили, что размер файла app.js плюс размер нового дополнительного файла в точности равен размеру приложения без разделенной упаковки. Это эквивалентно асинхронно загружаемому компоненту, который запакован в js отдельно, его не нужно загружать при первой загрузке страницы, когда запрашивается соответствующая страница, она отправляется на сервер для ее запроса, что снижает время загрузки первого экрана страницы.

vue-cli /webpack.prod.conf.jsКонфигурация в output.chunkFilename указывает формат упаковки асинхронных файлов.

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 
  },

Как воспользоваться кешированием браузера

Цель

Предположим, что у нас сейчас много статических файлов, и тогда нам нужно каждый раз обновлять много файлов, нужно ли вручную изменять имена файлов по одному? Наш идеал, конечно: какой файл обновляется, автоматически генерируется новое имя файла.

Кроме того, если статический файл, который мы упаковали, имеет только один файл JavaScript app.js, то каждый раз, когда мы немного меняем код, имя файла app.js обязательно будет меняться. Но на самом деле я только изменил код определенного модуля (другие модули не изменились), что уничтожило кеш других модулей, которые явно не использовали кеш в полной мере. наша цель:

Какой модуль обновляется, разрушает его кеш, и модуль, который не обновляется, продолжает использовать кэш.

Шаг 1: Увеличьте значение HASH

Выше мы упомянули три способа очистки кеша: изменить имя файла, изменить путь и добавить параметры в URL-адрес Подход Webpack заключается в изменении имени файла. vue-кли/webpack.prod.conf.jsВ output.chunkFilename указывается формат упакованного асинхронного файла.

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),   
    // 规定文件名为 js文件夹下 Chunk.name . hash值 .js 的文件
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
    // 规定文件名为 js文件夹下 module id. hash值 .js 的文件
  },

В этом случае к каждому файлу добавляется хеш-значение, и хеш-значение будет меняться при изменении этого файла.

Шаг 2. Извлеките файл манифеста

Зачем извлекать файл манифеста?

Причина в том, что чанк поставщика содержит исполняемый код веб-пакета (используется для анализа и загрузки исполняемого кода, например модулей).

Это приведет к: даже если вы не измените импортированный модуль (если модуль поставщика не изменился, вы только измените другой код) приведет кvendorМеняется значение chunkhash, что разрушает кеш и не дает ожидаемого эффекта

vue-cli /webpack.prod.conf.jsИзвлечь манифест

    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),

Шаг 3: Создайте четырехзначный хэш в качестве идентификатора модуля в соответствии с относительным путем модуля.

У каждого модуля в веб-пакете есть идентификатор модуля. Идентификатор модуля — это серийный номер, присвоенный модулю в графе зависимостей модуля. Если идентификатор модуля изменится, его хэш также изменится.

Это приведет к тому, что: если вы введете новый модуль, это приведет к изменению идентификатора модуля в целом, что может привести к изменению хеш-функции всех файлов, что явно не то, что нам нужно.

Его следует использоватьHashedModuleIdsPluginСоздайте четырехзначный HASH в качестве идентификатора модуля в соответствии с относительным путем модуля, чтобы новый модуль был введен, он не влиял на значение идентификатора модуля, пока путь модуля не изменяется.

vue-cli /webpack.prod.conf.js

    new webpack.HashedModuleIdsPlugin()

для достижения целей

Пока что, если мы изменим код модуля, это не уничтожит кеш других модулей.Это постоянный кеш, которого мы хотим добиться.

Превратите веб-пакет в vue-cli, чтобы улучшить скорость загрузки домашней страницы.

анализировать

Давайте сначала посмотрим на реальный проект

Запустите npm run build --report, чтобы увидеть карту распространения пакетов.Мы обнаружили, что самый большой файл — это вендор, где упакована большая часть кода фреймворка, и эти коды фреймворка меняются не очень часто и их не нужно каждый раз упаковывать. Таким образом, мы можем найти способ извлечь их и повесить на CDN.

Конкретные шаги

Возьмем в качестве примеров vue, vue-router, element-ui.

Шаг 1. Инфраструктура импорта cdn index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>demo-vue-project</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.0.8/theme-chalk/index.css">
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.min.js"></script>
    <script src="https://cdn.bootcss.com/element-ui/2.0.7/index.js"></script>
  </body>
</html>

Шаг 2. Измените build/webpack.base.conf.js.

module.exports = {
  ...
  externals: {
    'vue': 'Vue',
    'vue-router': 'VueRouter',
    'element-ui': 'ELEMENT'
  },
  ...
}

Шаг 3. Измените метод регистрации фреймворка

Изменить src/router/index.js

// import Vue from 'vue'
import VueRouter from 'vue-router'
// 注释掉
// Vue.use(VueRouter)
...

Изменить src/main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import ELEMENT from 'element-ui'
// import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false

Vue.use(ELEMENT)
Vue.prototype.$http = axios

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  template: '<App/>',
  components: { App }
})

Пакет

После упаковки мы обнаружили, что размер вендора сильно уменьшился, потому что код библиотеки грузился с cdn. Однако это приведет к увеличению ресурсов запроса и стоимости ответа, что можно расценивать только как идею. Окончательное решение проблемы «выше сгиба» — SSR.

Суммировать

Пока у меня есть некоторое представление о конфигурации упаковки в vue-cli. Лично для меня webpack действительно сложен. ждать и смотретьparcelМожет принести другой опыт.