Гаряча перезавантаження Chrome-розширення

На днях виникло бажання написати простеньку розширення для Google Chrome. Зіткнувся з такою проблемою, що після змін в коді розширення браузер не перезавантажує його автоматично. Це дуже сильно ускладнює розробку, т. к. після кожного Cmd-S у редакторі, доводиться натискати "Reload" у списку розширень, а потім ще й рефрешить сторінку, щоб перезапустити контент-скрипти.
Після нетривалих пошуків з'ясувалося, що Chrome надає всі необхідні API для того, щоб реалізувати подібну функціональність для свого розширення самостійно.
Готове вбудовується рішення лежить на github.com/xpl/crx-hotreload, а в цій статті я розповім, як воно реалізовано.
Використовуємо File and Directory Entries API для рекурсивного отримання списку файлів в папці:
const filesInDirectory = dir => new Promise (resolve =>

dir.createReader ().readEntries (entries =>

Promise.all (entries.filter (e => e.name[0] !== '.').map (e =>

e.isDirectory
? filesInDirectory (e)
: new Promise (resolve => e.file (resolve))
))
.then (files => [].concat (...files))
.then (resolve)
)
)

Генеруємо «збірний» timestamp з усіх timestamp'ів отриманих файлів і їх імен:
const timestampForFilesInDirectory = dir =>
filesInDirectory (dir).then (files =>
files.map (f => f.name + f.lastModifiedDate).join ())

Таким чином, ми можемо детектувати не тільки зміни у файлах, але і їх видалення/додавання/перейменування.
Вотчдог, перевіряючий зміни кожні 1000мс:
const watchChanges = (dir, lastTimestamp) => {

timestampForFilesInDirectory (dir).then (timestamp => {

if (!lastTimestamp || (lastTimestamp === timestamp)) {

setTimeout (() => watchChanges (dir, timestamp), 1000) // retry after 1s

} else {
reload ()
}
})

}

Перезавантаження розширення та активної вкладки:
const reload = () => {

chrome.tabs.query ({ active: true, currentWindow: true }, tabs => {

if (tabs[0]) { chrome.tabs.reload (tabs[0].id) }

chrome.runtime.reload ()
})
}

Перезавантаження вкладки викликається до
runtime.reload
, інакше вона не спрацює — виклик
runtime.reload
припиняє виконання скрипта. Але оскільки перезавантаження вкладки відпрацьовує асинхронно, то в підсумку все перезавантажується в коректному порядку — хоч і виглядає в коді нелогічно.
Ну і фінальний штрих — запускаємо вотчдог, натравленный на папку з кодом розширення. Але робимо це тільки якщо розширення завантажено в режимі розробника, через "Load unpacked extension":
chrome.management.getSelf (self => {

if (self.installType === 'development') {

chrome.runtime.getPackageDirectoryEntry (dir => watchChanges (dir))
}
})

Таким чином, ми позбавляємо розробника від необхідності морочитися з ручним вирізанням этото вотчдога з продакшн-білду.
Finally
Ось, загалом-то, і все. Абсолютно незрозуміло, втім, як тестувати такі штуки. Навряд чи який-небудь Selenium тут допоможе, або все-таки? Фідбек вітається.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.