A couple of weeks ago I created my first Chrome extension. It was a great learning exercise, and if you’ve ever been curious about making your own, the basics I cover here will be helpful in your own journey if you choose to jump into the wide world of extension development. Here, I want to document my journey including the steps (and missteps) I took along the way.
Why Chrome Extensions?
I’ve always been a fan of Chrome extensions, yet somehow had never made one myself, despite having plenty of “what if” moments imagining how websites I frequently use could be made (even slightly) better. I finally made the decision to act with a site that happened to be the Firebase developer console’s hosting tab. This tab displays the DNS records one must add to the registrar from which the domain was purchased. There are two IP Address values one must copy over, and after a while I thought: “what if this copy paste could be automated?” The end result now lives on the Chrome Webstore.
Namecheap is a registrar which provides services on domain name registration. A couple years ago they added two-factor authentication as an option for additional account security. 2FA is great, but it makes logging into your dashboard more of an effort.
Luckily, Google has made plenty of documentation and guides available covering all things Chrome extension-related, and they can be found here. There are also countless articles on Medium, and other blogs serving as great complementary reading; I found seeing the same info described from different perspectives gives a fuller picture.
Initial Development + Dealing with Errors
The process started with doing a whole lot of copying and pasting, making sure the manifest.json file had everything it needs to contain. My first real roadblock had to do with figuring out how to dynamically add a button to the existing webpage. The particular challenge was that the modal I wanted that button to display inside of did not exist in the DOM on page load. Furthermore, the ID assigned to that modal appeared to be random due to it being different upon page every refresh:
That led me to try a different approach, utilizing the popup window that appears after clicking on the Chrome extension’s icon in the upper right-hand corner of the browser as the way of connecting the Firebase console to Namecheap’s API.
Switching from plain JS to React
There came a point where I realized there was too much conditional logic affecting the content of the popup. For example, I needed to take into account whether:
1. The user has the Namecheap API credentials already saved to the extension’s local storage.
2. The user is currently on the Firebase console hosting tab’s URL
3. The user has the “Connect domain” modal open
4. A request is being made with the user’s Namecheap API credentials
5. The extention successfully retrieved those credentials from the API call
All of this quickly became messy, so switching to React appeared to be a reasonable option. This guide gives a great starting point for doing so with create-react-app. The resulting App.js file contains the conditionals for driving the five scenarios mentioned above.
When the component first mounts, three asynchronous actions take place for 1) getting the user’s IP address, 2) getting the locally saved data, and 3) getting the URL of the current tab. The values retrieved determine what next appears in the popup window.
Namecheap API
Namecheap offers an API that lets users do most things they can do on the web dashboard. The only two methods I needed to use were getHosts and setHosts. These, along with all other API methods, require certain request parameters to exist such as ApiUser and ApiKey. Responses come back in XML format, which I had never dealt with in JavaScript before. This was not a major roadblock but led to a healthy dose of trial and error while attempting to access any response errors. Using something like this:
const errors = xmlDoc.getElementsByTagName('Error') || [];
was sufficient because that Errortag will only appear when there is at least one.
One thing I had to watch out for in using the setHostsmethod was making sure I didn’t accidentally delete existing DNS Host records, or at least not accidentally. I say accidentally because, as per the API docs:
“All host records that are not included into the API call will be deleted, so add them in addition to new host records.”
The only time I can see it being beneficial to delete records is to get rid of the two that exist by default after registering a new domain, one which is of type CNAME Recordwith value http://parkingpage.namecheap.com., and the other being a URL Redirect Record, since you would have to remove those eventually in order to see actual content on the site.
Publishing to the Chrome Webstore
Compared to the process of developing this application, actually publishing it to the Chrome Webstore was surprisingly easy. The steps are succinctly described here. A few screenshots, along with a one-time $5 registration fee, are the main necessities. After filling out other info (like the category this extension belongs to, whether you want to restrict its access in certain countries), and uploading a .zip file of the extension, it becomes accessible for anyone to download.
Next Steps
The Chrome extension I made was mostly for educational purposes, and without a doubt has at least a bug (or three). However, it’s helped pave a path toward making other extensions which have less niche use cases, such as one that adds custom “copy-to-clipboard” buttons with dynamically changing keyboard shortcuts to the page for every code snippet in a readme file on Github. Having already gone through the process and demystified the steps involved from inception to publishing, I feel more confident bringing my next “what if” idea to life. I hope this overview will help you do the same.