Things I Learned from Developing Chrome Extensions (Manifest V3)
Do you know about Chrome extensions? Chrome extensions are features for customizing the Chrome browser.
I have created two Chrome extensions in the past (a few years ago), and at that time, I was following the Chrome extension specification, Manifest V2. And now, I have something I want to create with Chrome extensions again, so I decided to create it after a long time. However, it seems that the current Chrome extension specification recommends Manifest V3. So, I will summarize what I learned during development this time.
By the way, what I actually created is the following.
- https://github.com/silverbirder/chrome-extensions-tiktok-scraping-downloader
- The diagram above is the blueprint for this Chrome extension
※ If you want to know more about Chrome extensions, please check out What are extensions? - Chrome Developers.
Chrome Extensions Components
Chrome extensions mainly consist of the following four components.
- Background Scripts
- They operate on service workers and respond to event-driven actions on the browser (such as page transitions and bookmark differences).
- Set in the
background
field of the manifest.
- Content Scripts
- They operate in the context of a web page and can access the DOM.
- Set in the
content_scripts
field of the manifest.
- UI Elements
- This is the UI that appears when you press the button on the right side of the URL bar (Action).
- It is recommended to provide only the minimum necessary functions that do not impair the browser experience.
- Set in the
action
field of the manifest.
- Options Page
- This is the UI that appears when you right-click the Chrome extension icon and select options.
- It is used for the settings page if you want to customize the Chrome extension.
- Set in the
options_page
field of the manifest.
In my opinion, the use of these components can be divided as follows:
- When you need to access the DOM
- Use Content Scripts
- When there is a process that does not depend on the page
- Use Background Scripts
- When you need to set environment variables
- Use Option Page
I thought that UI Elements are basically not necessary.
Debug
How do you debug?
The method is written here. From my interpretation, I think it is divided into the following two.
- ① When the Chrome extension cannot be loaded in the first place
There are times when the Chrome extension cannot be loaded due to errors in the manifest.json file, etc. In such a case, perform the following steps.
- Access
chrome://extensions
- Click the ERROR button as shown in the next figure
Probably, some error message is output. Let's solve it.
- ② Cases other than ①
There are times when the Chrome extension can be loaded, but it does not work as expected. In such a case, open DevTools.
- In the case of Background Scripts
- Access
chrome://extensions
and click the link to the right ofinspect views
. (See the above figure)- DevTools will open.
- Access
- In the case of Content Scripts, UI Elements, Options Page
- Right-click on the UI and click
Inspect
- DevTools will open.
- Right-click on the UI and click
There should be a console tab in DevTools. Check the log messages there.
Message Passing
How should I communicate between each component? For example, when you want to pass data from Content Scripts to Background Scripts. The following document will be helpful.
Reading the document, it seems that you can communicate in the following patterns.
- Communication between each component
- Such as Background Scripts ⇔ Content Scripts
- Communication between Chrome extensions
- A Chrome extension ⇔ B Chrome extension
- Communicate using the ID of the Chrome extension
- Communication from web pages (Sending messages from web pages)
- Web page ⇔ Component of Chrome extension
The specific code for communication uses the chrome.runtime.sendMessage
method.
When communicating from Background Scripts to Content Scripts, you need to find the id in advance with chrome.tabs.query
to determine which Chrome tab to send to.
Also, as I will introduce later, when you Inject Javascript accessible with Web Accessible Resources
to a web page (document.querySelector('body').append()
), use window.postMessage
and window.addEventListener
for communication between that Javascript and Content Scripts.
Because you can't use chrome.runtime
.
Web Accessible Resources
You can access the DOM of a web page from Content Scripts, but you cannot access variables in the window object.
To access the window object, you can use Web Accessible Resources.
Let's explain in code.
The example of the necessary fields in manifest.json is as follows.
{
"manifest_version": 3,
"content_scripts": [
{
"js": ["content-script.js"],
"matches": ["https://*/*"]
}
],
"web_accessible_resources": [
{
"resources": ["web_accessible_resources.js"],
"matches": ["https://*/*"]
}
]
}
The Javascript of Content Scripts and Web Accessible Resources is as follows.
// content-script.js
const injectScript = (filePath, tag) => {
var node = document.getElementsByTagName(tag)[0];
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", filePath);
node.appendChild(script);
};
injectScript(chrome.runtime.getURL("web_accessible_resources.js"), "body");
// web_accessible_resources.js
console.log(window["hoge"]);
// To communicate with Content Scripts, use window.postMessage.
In this way, append web_accessible_resources.js to the body tag of the Web page. In that web_accessible_resources.js, you can access the window object.
chrome.webRequest API
There is an API for Chrome extensions that monitor network traffic in the Chrome browser.
That is chrome.webRequest
.
With this, you can see what requests are being made on the Web page.
You need to set host_permissions
in the fields of manifest.json.
As a sample, I will introduce the code of Background Scripts. First, write the necessary fields in manifest.json.
{
"manifest_version": 3,
"host_permissions": ["https://*/*"],
"background": {
"service_worker": "background.js"
}
}
Next, write the code to monitor the event when a request from the Web page is completed (onCompleted).
// background.js
chrome.webRequest.onCompleted.addListener(
async (details) => {
console.log(`request url is ${details.url}`);
},
{
urls: ["https://*/*"],
},
["responseHeaders"] // responseHeadersをdetailsオブジェクトに含めることができます。
);
This details includes the URL of the request. If you want to know more, please check here.
Finally
Developing Chrome extensions after a long time, I struggled to catch up with the evolution. I hope this can be of help to those who are in the same situation as me.
Share
Related tags
- Created an App to Consistently Record and Visualize Data in a Free Format
- Developing "Bochi-Bochi", an App to Easily Find Cheap Ingredients
- What I Learned from Refreshing My Blog Page with Qwik
- Introducing AI Ghostwriter - A Tool to Improve Writing Efficiency
- Development of Stable Diffusion API
- Defining Fragments Composed in Micro Frontends as Web Components and Sharing them with Module Federation
- Created OEmbed and OGP WebComponents for use on my blog site
- If you're writing in Markdown, Rocket, an SSG that uses WebComponents, is recommended!
- Refreshing Silverbirder's Portfolio Page (v2)
- I Made an API That Only Returns Google Account Images
- Building a TikTok Scraping Infrastructure on GCP and the Challenges Faced
- Micro Frontends on the Client Side (ES Module)
- Micro Frontends with Zalando tailor (LitElement & etcetera)
- Micro Frontends with SSR in Ara-Framework
- Created a GAS Library, zoom-meeting-creator, to Automatically Generate Zoom Meetings
- Introducing a Tool for Bulk Updating Account Images and What I Learned
- Cotlin is a Tool for Collecting Links on Twitter, Discover Presentations from Around the World
- I tried creating rMinc, a service that registers GMail to GCalendar
- I Tried Making a One-Frame Comic Search Service Tiqav2 (Algolia + Cloudinary + Google Cloud Vision API)