Browser Extension - Extension architecture
Quentin Ménoret
Posted on January 25, 2021
I just published a new extension on Chrome and Firefox that allows anyone to run Code Tours from the Github UI. More information about Code Tours and the extension in this blog post.
Article No Longer Available
I thought it would be nice to write a series about how you could do exactly the same, step by step.
This first post will be about what an extension looks like in terms of architecture:
🛠 What are the main components? Let’s talk Background Script, Content Script and Injected Scripts
💡 Which one should you use for which purpose?
🤝 How to communicate between them?
The extension architecture
Background script
The heart of an extension is called a Background Script. This is simply a JavaScript script that runs in the browser as soon as the extension is loaded. It is not linked to any specific tab and can’t interact with their content. Its goal is to contain the state of your extension, and to implement all external calls or chrome API manipulation.
For instance, it’s from a Background Script that you would be able to focus a specific tab, or interact with the history or bookmarks of the browser. We won’t use such features for this extension, but we will need it to perform HTTP calls, and maintain the state of the application.
Content Script
A content script runs in the context of a single tab. The associated javascript code will get loaded when the tab opens, and stop as soon as it closes. You will be able to specify in which tabs your content scripts should be loaded (based on the URL for instance). We’ll see that in the next post.
A content script has access to most of the page context, including the DOM (you can add elements or alter the page from there). Note that because of security reasons, even though you have access to a window
object, it won’t be the same instance as the one available to the code running in the website you are injecting to. This is meant to prevent you from accessing functions defined by another extension, or by the web page. If you need access to the window
object, you would need to use injected scripts (the next part of this post!).
In order for the Content Script to communicate with a Background Script, you should use the Chrome Messaging API.
Sending a message is fairly easy and can be achieved with a single call:
chrome.runtime.sendMessage({message: "content"}, function(response) {
console.log('message has been received: ', response);
});
Injected Script
An injected script is just a bit of code you inject directly into the page, using DOM manipulation (for instance using a <script>
div tag). In this context, the script will have access to the same window
object as the website code, but won’t have access to the extension API.
For the injected script to communicate with a Content Script, you will use the postMessage API:
window.postMessage({ message: 'from the injected script' }, "*");
A side note
None of these components are required to build a Browser extension. You could just have a content script, or a background script. But to have an injected script, you actually need a content script (since it is the one doing the injection).
There won’t be a need for an injected script in this tutorial, but you might need it if you were to expose a public API to the website (by creating methods on the window
object for instance).
What it looks like
Conclusion
This was a short introduction to how a browser extension works. Next time, we’ll see how to bundle it all together so you can test the extension! Feel free to follow me here if you want to check the next post when it's out:
Photo by Ricardo Gomez Angel on Unsplash
Posted on January 25, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.