Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 3758

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 61k
Author
Asked: November 26, 20242024-11-26T05:40:10+00:00 2024-11-26T05:40:10+00:00

Lessons learned from creating a Chrome extension πŸ“—

  • 61k

I recently had a side project where I had to gather information on some websites. It was a repetitive task that I had to do daily and it was quite boring. Since I thought it could be automated, I chose to give it a try by creating my first Chrome extension. 🧩

This post will serve me as a reflection article on some learning that I realized during this project. πŸ€”

Note : this extension was built using the Manifest V2, which will be replaced in some time by the Manifest V3. Thus, some information in this post may be out of date or needs to be adapted for the next version, which should be released in January 2021.

Callback hell 😈

While building this extension, I experienced something that I think had ceased to exist since the async/await functions and promises : callback hell. Every external function that I needed to call does not return a promise and takes a callback function… Oh my god, it was really a challenge to work with asynchronous code asynchronously!

Fortunately for us, the Manifest V3 should add promises to its APIs and, eventually, all methods will support promises. If I had known this information earlier, I would have tried to begin directly with the next version! I should have read the Chrome extensions guide before starting to create my extension! 😝

Let's see what new functions I used for my extension.

browserAction

Execute a function after clicking on the extension icon

For my extension, the listener function was my entry point , where the main logic is. I have not used its tab parameter, but after looking at it, it looks like it is the information about the current opened tab. I also add an async tag as my code is asynchronous. 🀘

const listener = async (tab) => {};  // Fired when a browser action icon is clicked. Does not fire if the browser action has a popup. chrome.browserAction.onClicked.addListener(listener); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.browserAction.onClicked.addListener function

For an example of the tab details, take a look at the chrome.tabs.get function below.

tabs

Create a tab

As one of the goals of my extension is to navigate to a list of URLs, I quickly use the function to create a new tab. In its simplest form, I only provide the absolute URL I want to visit, with the url parameter.

I recently added the windowId parameter to make sure the tabs are created in the same window, instead of the active window. It will alloy me to do other things in a separate window while my script is running. 🧭

const createProperties = { url, windowId }; const callback = async (createdTab) => {};  // Creates a new tab chrome.tabs.create(createProperties, callback); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.tabs.create function

Execute a script inside a tab

Once the tab was created and fully loaded (after a minimal sleep), I could inject any JavaScript file into the page and retrieve with a couple of document.querySelector the information I was looking for.

const details = {   file: fileToExecute, }; const callback = (result) => {};  // Injects JavaScript code into a page chrome.tabs.executeScript(tabId, details, callback); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.tabs.get function

Unfortunately, I had no way to know if my script had finished running or not, as it was wrapped into an async IIFE to have asynchronous functionalities. So I found a not very clean solution by renaming the tab title to a known value as the last line of my script.

Get information about a tab

The chrome.tabs.get function gives a lot of information about a tab, but I found the most interesting are the three following properties:

  • status : the tab's loading status ("unloaded", "loading", or "complete")
  • title : the title of the tab
  • url : the URL of the main frame of the tab
const callback = async (specifiedTab) => {};  // Retrieves details about the specified tab chrome.tabs.get(tabId, callback); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.tabs.get function
{   "active": true,   "audible": false,   "autoDiscardable": true,   "discarded": false,   "favIconUrl":"",   "height": 767,   "highlighted": true,   "id": 188,   "incognito": false,   "index": 1,   "mutedInfo": {     "muted": false   },   "pinned": false,   "selected": true,   "status": "complete",   "title": "Extensions",   "url": "chrome://extensions/",   "width": 1440,   "windowId": 1 } 
Enter fullscreen mode Exit fullscreen mode

Tab information from the chrome://extensions/ page

Delete a tab

Once my scripts were injected and executed inside the new tabs, I would manually close them all at first, but it got tedious as I added more and more URLs to check. So with the previous function, I decided to just get rid of the tab once I got all the info I need.

// Closes one or more tabs const tabIds = 10 || [10, 12]; chrome.tabs.remove(tabIds); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.tabs.remove function

webNavigation

Get all frames of a tab

One of the pages I was interested in had information inside an iframe, so my initial script was not working as I did not have access to it. Fortunately, we could specify the frameId to target a specific frame of the tab. So, I use the getAllFrames function to find the frame I want with its hostname.

const details = { tabId }; const callback = (frames) => {}  // Retrieves information about all frames of a given tab chrome.webNavigation.getAllFrames(details, callback); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.webNavigation.getAllFrames function

I initially tried to use the allFrames parameter of the executeScript function to inject the script into all frames of the selected tab, but I was not working for me. I now believe it was because the frame had not finished loading. Anyway, I still prefer to inject my script only where it is needed, rather than injecting it on every iframes on the page.

[   {     "errorOccurred": false,     "frameId": 0,     "parentFrameId": -1,     "processId": 612,     "url": "chrome://extensions/"   } ] 
Enter fullscreen mode Exit fullscreen mode

Frames information of chrome://extensions/ page

runtime

Send a message

While I was looking for a way to know when I could close a tab that had an iframe, I came across the sendMessage function. It allows us to send a message to our extension. So I end up sending a message with the current URL to my extension to let it know that the script has been executed successfully.

 // Sends a single message to event listeners within your extension chrome.runtime.sendMessage(messageObject); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.runtime.sendMessage function

Listen for messages

To listen to messages, I just add the function below at the start of my extension and now I receive messages from my injected scripts. As it seems much better to depend on messages rather than updating the tab title, I plan to refactor that part someday.

const callback = (message, sender) => {};  // Fired when a message is sent from an extension process chrome.runtime.onMessage.addListener(callback); 
Enter fullscreen mode Exit fullscreen mode

Using the chrome.runtime.onMessage.addListener function

While writing this post, I also learned that the function has a sender argument which contains information about the frame AND the tab. I plan to use that information because it seems more reliable than my document.URL message. πŸ˜‰

Here's an example of a sender argument below:

{   "id": "ngjdjkfidkkafkjkdadmdfndkmlbffjf",   "url": "https://FRAME_HOSTNAME.com/FRAME_URI",   "origin": "https://FRAME_HOSTNAME",   "frameId": 1233,   "tab":{     "active": true,     "audible": false,     "autoDiscardable": true,     "discarded": false,     "favIconUrl": "https://TAB_HOSTNAME.com/favicon.ico",     "height": 767,     "highlighted": true,     "id": 226,     "incognito": false,     "index": 4,     "mutedInfo": {       "muted": false     },     "pinned": false,     "selected": true,     "status": "complete",     "title": "TAB_TITLE",     "url":"https://TAB_HOSTNAME.com/TAB_URI",     "width": 1440,     "windowId": 1   } } 
Enter fullscreen mode Exit fullscreen mode

Example of the sender argument

Conclusion

In retrospect, it was really fun learning to code a Chrome extension. I had never had the opportunity to try it before, both at work and in my personal projects. I hope to have another chance to build a more complex extension! πŸ€“

Note : as my extension is intended entirely for private use and has not been made reusable, so I do not plan on deploying it on the Chrome Web Store or releasing its source code. Sorry! πŸ”’

developmentjavascriptshowdevwebdev
  • 0 0 Answers
  • 5 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 2k
  • Popular
  • Answers
  • Author

    ES6 - A beginners guide - Template Literals

    • 0 Answers
  • Author

    Understanding Higher Order Functions in JavaScript.

    • 0 Answers
  • Author

    Build a custom video chat app with Daily and Vue.js

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.