"Every day starts, my eyes open and I reload the program of misery. I open my eyes, remember who I am, what I'm like, and I just go, 'Ugh'."
"Every day starts, my eyes open and I reload the program of misery. I open my eyes, remember who I am, what I'm like, and I just go, 'Ugh'."
When developing Chrome extensions or Firefox addons it can be daunting having to keep clicking reload manually. Here is a step-by-step guide on how to implement extension live reloading in the browser.
Use neutrino-webextension which works out of the box.
Read on if you are interested in the theory behind the scene.
There is a browser.management
API which is used by many extension-livereload extensions. But looks like it does not work when manifest.json
changes.
Instead we use another API browser.runtime.reload()
which reloads the extension itself.
How do we know when to reload? It should happens after file changes. If using bundler there usually be hooks for performing jobs after bundling. Otherwise take a look at fs.watch or node-watch.
How does the extension know when to reload itself? It is not ideal using WebSocket or extension messaging API which involves native setups. Instead we try to leverage the browser extension API itself.
The idea is that the extension monitors web requests for a special url. Whenever the browser requests this url the extension gets notified and performs reloading logic.
This is an example project structure for the sake of this post.
project/
├── livereload
│ ├── background.js
│ ├── livereload.html
│ └── livereload.js
├── src
│ ├── background
│ │ └── index.js
│ └── popup
│ ├── index.html
│ └── index.js
└── manifest.json
First we need to be able to redirect web requests.
{
"background": {
"persistent": true,
"scripts": [
"livereload/background.js",
"src/background/index.js"
]
},
"permissions": [
"*://neutrino-webextension.reloads/*",
"webRequest",
"webRequestBlocking"
],
"web_accessible_resources": [
"livereload/*"
]
}
http://neutrino-webextension.reloads
is the special url that we are going to monitor.
const b = typeof browser === 'undefined' ? chrome : browser
b.webRequest.onBeforeRequest.addListener(
() => ({ redirectUrl: b.runtime.getURL('livereload/livereload.html') }),
{
urls: ['*://neutrino-webextension.reloads/*'],
types: ['main_frame']
},
['blocking']
)
It will redirect the request to livereload/livereload.html
.
We first send a message to background, then close the page immediately.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Live Reload</title>
</head>
<body>
<script src="./livereload.js"></script>
</body>
</html>
Script has to be in separate file.
const b = typeof browser === 'undefined' ? chrome : browser
b.runtime.sendMessage('_neutrino-webextension.reloads_')
if (window.history.length <= 1) {
window.close()
} else {
history.back()
}
In background we listen to the messages and perform reloading.
const b = typeof browser === 'undefined' ? chrome : browser
b.webRequest.onBeforeRequest.addListener(
() => ({ redirectUrl: b.runtime.getURL('livereload/livereload.html') }),
{
urls: ['*://neutrino-webextension.reloads/*'],
types: ['main_frame']
},
['blocking']
)
b.runtime.onMessage.addListener(message => { if (message === '_neutrino-webextension.reloads_') { b.runtime.reload() }})
So far so good! Except there is one tiny issue. The redirection will leave browsing histories in the browser. Let's remove it!
{
"background": {
"persistent": true,
"scripts": [
"livereload/background.js",
"src/background/index.js"
]
},
"permissions": [
"browsingData", "*://neutrino-webextension.reloads/*",
"webRequest",
"webRequestBlocking"
],
"web_accessible_resources": [
"livereload/*"
]
}
Remove before reloading.
const b = typeof browser === 'undefined' ? chrome : browser
b.webRequest.onBeforeRequest.addListener(
() => ({ redirectUrl: b.runtime.getURL('livereload/livereload.html') }),
{
urls: ['*://neutrino-webextension.reloads/*'],
types: ['main_frame']
},
['blocking']
)
b.runtime.onMessage.addListener(message => {
if (message === '_neutrino-webextension.reloads_') {
b.browsingData.remove( { hostnames: [ 'neutrino-webextension.reloads' ], originTypes: { unprotectedWeb: true, protectedWeb: true }, since: Date.now() - 2000 }, { history: true } ) b.browsingData.remove( { originTypes: { extension: true }, since: Date.now() - 2000 }, { history: true } )
b.runtime.reload()
}
})
This will remove the history of the special url and the livereload.html
.
To open the brower with the special url:
npm install --save-dev open
After file changes, call
open('http://neutrino-webextension.reloads')
// specify browser
open('http://neutrino-webextension.reloads', { app: 'firefox' })
// with arguemnts
open(
'http://neutrino-webextension.reloads',
{
app: ['google-chrome', '--profile-directory=Profile 1']
}
)
The extension should recognise the request and reload itself.
Even though it works, this is still a lot of work to setup if implementing manually. It is recommended use a preset like neutrino-webextension which is battery included.
评论没有加载,检查你的局域网
Cannot load comments. Check you network.