Building a New Tab Chrome Extension with Zero Dependencies

Written by Dane | Published 2020/06/24
Tech Story Tags: hackernoon-top-story | chrome-extension | javascript | html | css | tutorial | chrome | browsers | web-monetization

TLDR Building a New Tab Chrome Extension with Zero Dependencies will walk you through the basic steps needed to get started building a new tab Chrome Extension powered by an API without any dependencies. Google provides a ton of boilerplate examples, but digging through that mess can be a little like navigating through a labyrinth. Google recommends having a 128x128 pixel icon and a 16x16 pixel icon at minimum. The extension will be used when a user opens a new browser window and fetches content from an API.via the TL;DR App

This story will walk you through the basic steps needed to get started building a new tab Chrome Extension powered by an API without any dependencies. Check out our Tech Stories Tab extension for reference.
Developing a new extension can be a little overwhelming. Google provides a ton of boilerplate examples, but digging through that mess can be a little like navigating through a labyrinth. A lot of examples are incomplete or lead you down the wrong path.
Here's what you need to get started building a new tab extension that fetches content from an API.
Step 1: Create a new folder for your extension
However you choose to make a new folder (
mkdir
) and where you put it (
~/
) is up to you.
Don't get too caught up in the name, it really doesn't matter. I called my folder
tech-stories-extension
, but it won't be visible once you start marketing your extension. You can always rename this later.
Step 2: Create a manifest.json file in your new folder
This is a necessary file for every Chrome Extension. Don't worry about every field you could add to your manifest at this stage. That's a future problem. For now, just start with something like this.
{
  "manifest_version": 2,
  "name": "Tech Stories Tab by Hacker Noon",
  "version": "1.0",
  "description": "The latest Hacker Noon tech stories.",
  "author": "Hacker Noon",
  "chrome_url_overrides" : {
    "newtab": "index.html"
  },
  "permissions": [
    "storage",
    "https://api.hackernoon.com/"
  ],
  "icons": {
    "16": "icon16.png",
    "128": "icon128.png"
  }
}
manifest_version
This is basically just a number to tell Google how to interpret your manifest.json file. Changing this will throw an error when you try and install your extension.
name/description/author
These fields will be used in the web store to describe your extension. You'll eventually want to be thoughtful in what you add here but for testing purposes, feel free to go with something random.
version
While testing, go with "0.1" or "1.0". Once you get published, you'll have to worry about incrementing by .1 for a minor upgrade and 1 for a major upgrade.
chrome_url_overrides
This is where you determine which html file will be used whenever a user opens a new tab. I've named mine
index.html
but feel free to stick it to the man and break convention.
permissions
Security is a pretty big deal when it comes to Chrome Extensions. By default, everything is pretty locked down. For example, you can't just go storing data to
localStorage
willy nilly like some random webpage. You've got to ask users permission to store things locally. You'll also want to add urls to any APIs you're fetching data from.
icons
At minimum, Google recommends having a 128x128 pixel icon and a 16x16 pixel icon.
Step 3: Create an index.html file
<html>
<head>
  <meta charset="utf-8">
  <title>Fancy Title</title>
  <meta name="description" content="Fancy description...">
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="stories"></div>
  <script src="script.js"></script>
</body>
</html>
You'll probably want to change the fancy title and description to something a little more imaginative, but this will get you started. Take note of the
<div id="stories"></div>
element, we'll reference this in our javascript.
Step 4: Create a script.js file
const storiesDiv = document.querySelector('#stories');

const storyNode = (story) => {
  var template = document.createElement('template');
  template.innerHTML = story;
  return template.content.childNodes[0];
}

const addStories = (stories) => {
  for (let index in stories) {
    const story = stories[index];
    const html = `<div class="story">
      <a href="${story.url}">${story.title}</a>
    </div>`;
    storiesDiv.appendChild(storyNode(html));
  }
}

if (localStorage.lastFetch && localStorage.stories && (new Date() - localStorage.lastFetch) < (1000*60*60)) {
  addStories(JSON.parse(localStorage.stories));
} else {
  if (localStorage.stories) {
    addStories(JSON.parse(localStorage.stories));
  }

  fetch('https://api.hackernoon.com/featured-stories',{
      method: 'GET',
      mode: 'cors',
      credentials: 'include'
    })
    .then(response => response.json())
    .then(data => {
      if (!localStorage.stories) {
        addStories(data);
      }

      localStorage.setItem("stories", JSON.stringify(data));
      localStorage.setItem("lastFetch", new Date()-1);
    });
}
This is where the bulk of the work is happening in the chrome extension. You might be tempted to load Vue.js, React, or your favorite flavor of javascript, but if you just want to inject a few chunks for HTML into a static page, go with vanilla JS. Anything else is just not worth the trouble, in my opinion.
The above javascript is basically doing the following:

1) Check to see if you have cached stories (
localStorage.stories
) and you most recently fetched stories less than an hour ago.

2) If your check passes, grab stories from the cache.
3) If the check fails, fetch new stories from the API.
4) Add the stories to the
<div id="stories"></div>
element from
index.html
.
It's ok if you don't quite follow some of the logic here. The code is far from pristine. We can dive into the logic line-by-line in the comments below. I just don't want to get too deep into the weeds here so it's easier to understand what is going on at a high level.
Step 5: Create a style.css file
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}

#stories {}
.story {}
This sad CSS is going to look like garbage. It's really just a CSS reset and some boilerplate to get started. Check out CSS Tricks for tips on spicing things up a bit.
Step 6: Install your extension
2) Turn on "Developer mode" in the top right corner
3) Click "load unpacked" and select the folder containing your extension files.
4) Open and new tab and see your code in action!
Step 7: Iterate
Once you can see your code functioning in a new tab, start tweaking the HTML, JS, and CSS until you get things looking good enough to launch.
Step 8: Submit your extension for inclusion into the web store
You'll need to create a few promotional images, add a longer description and add security information in order to submit. Here is a walkthrough of the publishing process.
Conclusion
Without dependencies, you can build a new tab Chrome extension in less than 100 lines of code. Here is a github boilerplate repo in case you aren't the copy and pasting type.
This tutorial is a WIP, if you get stuck on any step, please leave a comment.
If you have any ideas for improvements to our extension, please leave a comment on our Product Hunt page.

Written by Dane | Co-founder of Coin Field Guide
Published by HackerNoon on 2020/06/24