Inject scripts with Blob URLs
In earlier versions, scripts are injected like this:
const s = document.createElement('script');
This way works well on Chrome but does not work on Firefox 57- when page has a limit on inline script by CSP. See bugzilla.
Since Firefox 58, we have a workaround by injecting scripts like this:
Using Blob URLs instead of
textContent, scripts can be injected to pages on Firefox 58+ too.
Then we encountered a problem (v2.8.14, #249): sometimes the scripts are not injected at all. After debugging for a while, I figured out what was happening.
First let’s take a look at the injection procedure:
- inject an initializer to context of page script
- load userscripts from content script
- post userscripts to the initializer through custom events
- execute userscripts
The problem is, when the userscripts are loaded and posted to the initializer, the initializer may be not ready yet. As a result, the posted userscripts are discarded.
But why won’t this happen before?
textContent way is synchronous while the
src way is asynchronous.
textContent way, the initializer is initialized synchronously when injected. So the initializer is always ready when the userscripts are loaded.
But when using a Blob URL, the injection becomes asynchronous. Because it has to fetch the real content first. So the initializer may be not ready yet when the userscripts are laoded. Consequently, no userscript is injected.
Here is a demonstration:
By running the code above in a browser (e.g. Chrome), we got output as below:
So we just need to ensure that the initializer is ready when posting userscripts to it.
Finally, it works on Chrome any and Firefox v58+, even on pages with CSP limitations.