The other day there was a desire to write a simple extension for Google Chrome. Faced such a problem that after changes in the extension code, the browser does not automatically reload it. This is very difficult to develop, because after each Cmd-S in the editor, you have to click "Reload" in the list of extensions, and then refresh the page to restart the content scripts.
After some research, it turned out that Chrome provides all the necessary APIs in order to implement this functionality for its expansion on its own.
The ready built-in solution lies on github.com/xpl/crx-hotreload , and in this article I will tell how it is implemented.
Use the File and Directory Entries API to recursively get a list of files in a folder:
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) ) )
We generate a “composite” timestamp from all the timestamps of the received files and their names:
const timestampForFilesInDirectory = dir => filesInDirectory (dir).then (files => files.map (f => f.name + f.lastModifiedDate).join ())
Thus, we can detect not only changes in files, but also their deletion / addition / renaming.
Watchdog checking for changes every 1000ms:
const watchChanges = (dir, lastTimestamp) => { timestampForFilesInDirectory (dir).then (timestamp => { if (!lastTimestamp || (lastTimestamp === timestamp)) { setTimeout (() => watchChanges (dir, timestamp), 1000) // retry after 1s } else { reload () } }) }
Reloading the extension and active tab:
const reload = () => { chrome.tabs.query ({ active: true, currentWindow: true }, tabs => { if (tabs[0]) { chrome.tabs.reload (tabs[0].id) } chrome.runtime.reload () }) }
The reload of the tab is called before runtime.reload
, otherwise it will not work - a call to runtime.reload
stops the execution of the script. But since the reloading of a tab works asynchronously, in the end everything reloads in the correct order - although it looks illogical in the code.
Well, and the final touch - we run out watchdog, set on a folder with the extension code. But we do it only if the extension is loaded in the developer mode, through the "Load unpacked extension" :
chrome.management.getSelf (self => { if (self.installType === 'development') { chrome.runtime.getPackageDirectoryEntry (dir => watchChanges (dir)) } })
Thus, we save the developer from having to bother with manually cutting out this work from the production build.
Here, in general, that's all. It is completely incomprehensible, however, how to test such things. Hardly any Selenium will help here, or is it? Fidbek is welcome.
Source: https://habr.com/ru/post/314766/
All Articles