Предположительно, как front-end босс, вы должны были использовать в своей работе webpack и иметь представление об особенностях горячих обновлений. Если нет, конечно, это не имеет значения.
Ниже я хочу рассказать о некоторых своих знаниях и понимании механизма горячего обновления Webpack.Если есть какие-либо недостатки, пожалуйста, поправьте меня.
первый:
Что такое горячее обновление?
Горячее обновление означаетHot Module Replacement,сокращенноHMR.
Судя по названию, он предназначен для замены «горячего» модуля. Горячий означает, что модуль уже запущен.
Не знаю, слышали ли вы или видели фразу: «Переключите двигатель вашего автомобиля на двигатель Боинга 747 на шоссе».
Это немного надуманно, но с некоторых точек зрения все же уместно.
Идя немного дальше, позвольте мне рассказать о ситуации, с которой я столкнулся в своей текущей работе, и я думаю, что многие люди также сталкивались с ней.
Инструмент разработки апплета WeChat не предоставляет механизма, аналогичного горячему обновлению Webpack, поэтому во время локальной разработки каждый раз при изменении кода страница предварительного просмотра будет обновляться, поэтому предыдущий статус перехода маршрутизации и данные, заполненные в форме, недоступен. .
Даже если это всего лишь модификация копирайтинга или конфигурации атрибутов, это приведет к обновлению, а повторный вход на конкретную страницу и состояние иногда бывает очень проблематичным. Это пустая трата времени, когда вам нужно часто изменять код во время разработки.
При наличии механизма, аналогичного горячему обновлению Webpack, модифицируется код, который не вызывает обновления, а сохраняет существующее состояние данных, а только обновляет и заменяет модуль. Другими словами, существующее состояние данных сохраняется, и можно увидеть изменения после модификации кода.
Это красиво, но если подумать, это определенно не так просто.
Итак, что такое горячее обновление?
Цитируя официальную документацию, горячее обновление:
Механизм, который позволяет приложению обновлять, добавлять и удалять модули без перезагрузки обновления во время работы приложения.
Проблемы, решенные горячим обновлением
Тогда проблема, которую нужно решить с помощью горячего обновления, также описана выше. С моих слов этоВ среде разработки приложения разработчикам удобно модифицировать код без перезагрузки страницы, и интуитивно видеть механизм изменений на странице.
Проще говоря, дляПовышение эффективности разработки.
Вспоминая свой опыт разработки мини-программ WeChat, я действительно чувствую, что при наличии механизма горячего обновления эффективность разработки будет намного выше.
Если вы знаете, что апплет WeChat имеет или планирует поддержку горячих обновлений, или что некоторые крупные ребята проделали аналогичную работу, сообщите мне об этом, спасибо!
Прежде чем идти дальше, давайте посмотрим, как настраиваются горячие обновления Webpack.
Конфигурация горячего обновления
Если ваш предыдущий проект был собран и настроен другими людьми с помощью Webpack и горячего обновления, вы можете узнать, как настраивается горячее обновление, здесь.
В моем примере используется Webpack 4, если вы хотите увидеть код напрямую, здесь:
Помимо Webpack, вам также понадобитсяwebpack-dev-server
(илиwebpack-dev-middleware
).
Чтобы включить горячие обновления для среды разработки Webpack, вам нужно сделать две вещи:
- использовать
HotModuleReplacementPlugin
плагин - Открыть
webpack-dev-server
Переключатель горячего обновления для
HotModuleReplacementPlugin
Плагины включены в Webpack, вwebpack.config.js
Просто присоединяйтесь:
// webpack.config.js
module.exports = {
// ...
plugins: [
webpack.HotModuleReplacementPlugin(),
// ...
]
}
Если вы запускаете среду разработки Webpack напрямую через webpack-dev-server, вы можете включить переключатель горячего обновления webpack-dev-server следующим образом:
// webpack.config.js
module.exports = {
// ...
devServer: {
hot: true,
// ...
}
}
Тоже очень просто.
Пример горячего обновления
Механизм горячего обновления поясняется на примере ниже. Если ваш предыдущий опыт работы с горячим обновлением Webpack предоставляется вам Vue через vue-loader, то есть вы никогда не писали и не видели ничего подобного в своем собственном коде:
if (module.hot) {
module.hot.accept(/* ... */)
// ...
}
Такой код, то следующий пример в самый раз, чтобы посмотреть.
Примеры вышеwebpack-hmr-demo, если вы более знакомы с кодом, просто перейдите к нему, в документе на главной странице есть простые инструкции.
Пример 1: Случай без горячего обновления
Этот пример лишь кратко знакомит с функциями страницы-образца и позволяет вам испытать боль обновления страницы каждый раз, когда вы изменяете код.
На странице есть только один элемент для отображения значения:
<div id="root" class="number"></div>
Модуль ввода (index.js) ссылается на два модуля:
- timer.js: предоставляет только начальный интерфейс, передает функцию обратного вызова, а затем таймер будет вызывать функцию обратного вызова через определенные промежутки времени и передавать значение, которое увеличивается каждый раз
- foo.js: функции нет, она просто выводит сообщение. Введение этого просто для того, чтобы различать timer.js и показывать разные методы обработки обновления модуля.
Функция входного модуля очень проста, вызовtimer.start()
, а затем передать функцию обратного вызова, каждый раз обновляя полученное значение на странице:
import { start } from './timer'
import { message } from './foo'
var current = 0
var root = document.getElementById('root')
start(onUpdate, current)
console.log(message)
function onUpdate(i) {
current = i
root.textContent = '#' + i
}
Запустите этот проект, и открытая страница просто продолжит обновляться и отображать увеличенное значение, например:
После изменения кода любого модуля, например, изменения интервала времени таймера в таймере (например, изменение с 1 секунды на 3 секунды) или содержимого, отображаемого в onUpdate (например,'#' + i
изменить на'*' + i
), страница будет обновлена, существующий статус будет очищен, и счет снова начнется с 0.
Пример 2. Обработка горячих обновлений зависимых модулей
В следующем примере показано, как обрабатывать обновления других модулей в index.js.
При обновлении зависимого модуля изменение либо принимается (страница не требует обновления, модуль заменяется), либо не принимается (обновляется).
Webpack будет оперативно обновлять соответствующие интерфейсы, чтобыmodule.hot
Выставленный модулю перед использованием лучше всего оценить, поддерживает ли текущая среда горячее обновление, то есть код, показанный выше:
if (module.hot) {
// ...
}
Продолжая предыдущий пример, выберите принимать и обрабатывать обновления для timer, но не для модуля foo:
if (module.hot) {
module.hot.accept('timer', () => {
// ...
})
module.hot.decline('./foo')
}
Таким образом, в механизме горячего обновления Webpack фактически информируется таким способом «декларации», какие обновления модулей обрабатываются, а какие обновления модулей не обрабатываются. Разумеется, чтобы обновление модуля обрабатывалось, оно обрабатывается во втором параметре module.hot.accept(), то есть callback-функции, которая будет выполняться после замены объявленного модуля.
Давайте посмотрим на обработку обновления модуля таймера.
После вызова функции запуска модуля таймера она возвращает функцию остановки, которая может остановить таймер.Благодаря этому мы можем очистить старый модуль таймера и повторно вызвать функцию запуска нового модуля таймера на основе текущего состояния. :
var stop = start(onUpdate, current) // 先记录下返回的 stop 函数
// ...
if (module.hot) {
module.hot.accept('timer', () => {
stop()
stop = start(onUpdate, current)
})
// ...
}
Логика обработки такая же, как описано выше, сначала остановите таймер старого модуля через ранее записанную остановку, затем вызовите запуск нового модуля, чтобы продолжить подсчет, и передайте текущее значение, чтобы ему не пришлось снова начинать подсчет. от 0.
Это кажется относительно простым. Эффект запуска заключается в том, что если вы измените интервал таймера в таймере, вы сразу увидите эффект на странице, и страница не будет обновляться и снова начнет отсчет с 0:
После запуска в течение нескольких секунд измените интервал таймера в модуле таймера на 100 мс.
Измените сообщение в foo, и страница все равно будет обновляться.
Несколько дополнительных замечаний:
- Если модуль таймера не вернет начальный интерфейс после модификации, вышеприведенный механизм обработки, очевидно, выйдет из строя, поэтому обработка здесь основана на неизмененном интерфейсе модуля.
- Очевидно, что стоп-функция должна быть возвращена после стартового вызова модуля таймера, иначе таймеры, открытые в модуле таймера, не могут быть очищены в index.js, что тоже очень важно
- Возможно, вы также заметили, что ссылка на функцию запуска модуля таймера вроде бы не изменилась, так почему же запуск в функции обратного вызова — это новый модуль? На самом деле это обрабатывается Webpack во время компиляции.Скомпилированный код не соответствует текущему стилю, и начало будет заменено, так что начало в обратном вызове должно ссылаться на начало нового модуля таймера. Если вам интересно, вы можете увидеть соответствующее описание в документации Webpack.
Кроме того, помимо объявления обработки обновлений других модулей, модуль также может объявить обработку своего собственного обновления, что также является тем же интерфейсом, без передачи параметров:
-
module.hot.accept()
Сообщите Webpack, что текущее обновление модуля не нужно обновлять. -
module.hot.decline()
Скажите Webpack, чтобы он обновлялся при обновлении текущего модуля.
Более того, разные модули, которые зависят от одного и того же модуля, могут иметь разные объявления.Эти объявления могут конфликтовать.Например, одни позволяют обновлять зависимые модули, а другие нет.Как Webpack координирует их?
Механизм реализации Webpack чем-то похож на всплывающий механизм событий DOM.Событие обновления сначала обрабатывается самим модулем.Если сам модуль не имеет никакого объявления, он всплывет, чтобы проверить, есть ли у пользователя объявление для обновить модуль и так далее. Если в финальном модуле ввода нет объявлений, обновите страницу. Вот почему в предыдущем примере, несмотря на то, что горячее обновление включено, страница все равно обновляется после изменения модуля, потому что ни один модуль не обрабатывает обновление.
Пример 3: Обработка горячих обновлений собственных модулей
Обработка обновления собственного модуля аналогична обработке зависимых модулей, и он также объявляется Webpack через интерфейс module.hot. Однако обновление самого модуля может потребовать некоторой обработки перед заменой модуля на Webpack.Обновляемую обработку не нужно делать через специальный интерфейс, достаточно прописать ее прямо в коде нового модуля.
module.hot.dispose()
Он используется для регистрации функции обработки перед заменой текущего модуля, а функция обратного вызова получает объект данных, в который могут быть записаны сохраняемые данные, чтобы при выполнении нового модуля их можно было передать черезmodule.hot.data
Получать:
var current = 0
if (module.hot && module.hot.data) {
current = module.hot.data.current
}
Во-первых, когда модуль выполняется, он сначала проверяет, остались ли какие-либо данные от старого модуля, и если да, то восстанавливает их.
Затем обработка выполнения перед заменой модуля, здесь для записи данных и остановки существующего таймера:
if (module.hot)
module.hot.accept()
module.hot.dispose(data => {
data.current = current
stop()
})
}
После этого измените onUpdate index.js, чтобы значение, отображаемое на странице, изменилось, что также может быть отражено без обновления:
После запуска в течение нескольких секунд измените onUpdate() в
'#' + i
для'*' + i
Суммировать
Посмотрев на приведенный выше пример, давайте подведем итоги.
Горячее обновление Webpack фактически предоставляет только набор интерфейсов и реализацию замены базовых модулей. Вам как разработчику нужно передать в коде интерфейс горячего обновления (module.hot.xxx) объявляет Webpack, можно ли обновить зависимый модуль и текущий модуль, а также обработку до и после обновления.
Если обновление принято, разработчику необходимо очистить или сохранить необходимые данные и состояние перед заменой модуля и восстановить предыдущие данные и состояние после замены модуля.
Конечно, когда мы разрабатываем с помощью Vue или React, плагины, такие как vue-loder, уже сделали эти вещи за нас, и если файл *.vue нужно обрабатывать при его обновлении, многие детали понятны только внутри. vue-loader, мы можем с уверенностью его использовать.
Но в чем дело с горячим обновлением Webpack, было бы лучше, если бы вы могли иметь более глубокое понимание.Я встречал коллег, которые обрабатывали DOM самостоятельно в компоненте Vue (чтобы инкапсулировать компонент, который непосредственно манипулирует DOM ), и результат был связан с горячим обновлением.Присутствие вызывает некоторые проблемы с очисткой состояния.
В этом случае справиться с этим может только сам разработчик, а vue-loader не может справиться с таким частным случаем. По крайней мере, знайте, как использовать интерфейс горячего обновления Webpack, и в этом случае разработчики могут справиться с этим сами.
Представление механизма горячего обновления Webpack в этой статье относится только к уровню использования интерфейса или общего механизма и не объясняет принципы реализации и детали горячего обновления в деталях. Время и место ограничены, поэтому давайте сначала выложим картинку, а может быть успеем рассказать о ней подробно.
Источник изображения выше:
Webpack & The Hot Module Replacement medium.com/@raja вокруг DV/…
Эта англоязычная статья содержит подробное введение в принцип реализации горячего обновления Webpack.