Making Chrome Extensions is Easy with Yeoman

If you’re like me, you spend a fair amount of time on the Internet. For much of that time, we’re passive observers of the web, with little control over content or format. However, the major browser vendors have opened up their platforms by making it possible to create extensions for those browsers. Extensions allow us to significantly change our experience of the web, in ways that we find valuable.

Thanks to the work of the Yeoman project contributors, we have an easy way to create our own browser extensions. Yeoman is a “scaffolding tool for modern webapps.” It provides a development and build environment based on best practices that allows us to get up and running quickly.

The rest of this post will guide you through making a simple extension that changes all occurrences of the word “apps” on a page to the word “appetizers.”

The Ingredients

The three main components of Yeoman are the scaffolding tool, a build tool, and a package manager.

The scaffolding tool is called yo, and it provides a generator ecosystem with starting templates for over 1,500 different projects. We’ll be using the Chrome extension generator, but if you have a different favorite browser, there are also generators for Firefox and Safari, and getting started with those should be just as easy.

The next component of Yeoman is the build tool, which is responsible for previewing and testing your project as you develop it, as well as building a production-ready distribution. Grunt and Gulp are two such build tools that target JavaScript projects. The Chrome extension generator happens to use Gulp.

Lastly, Yeoman and the extension generator set us up with a package manager to manage all of our dependencies. Bower and npm are possible options, and here the generator opts for Bower.

Prep Work

The first thing we need to do is get npm, the Node.js package manager. Since it comes with the Node.js JavaScript runtime, we need to install that. I will direct readers to the Node.js download page to find an installation method for their particular platform, but as a spoiler for those on Mac OS X who use Homebrew, simply run:

$ brew install node

Having npm allows us to install Yeoman, Gulp, Bower, and the Chrome extension generator.

$ npm install --global yo gulp bower generator-chrome-extension

Let’s make a directory for our extension and change into it.

$ mkdir my-new-chrome-extension && cd $_

Then invoke the generator.

$ yo chrome-extension

The generator will ask you a series of questions about how you’d like your extension set up, such as what name and description you’d like to give it. In the process, the generator will also ask you which features particular to Chrome extensions you would like to enable, so let’s take a quick look at what those features are.

The Recipe

Chrome allows your extension to change the UI of the browser itself, in the form of browser actions or page actions.

Browser actions are used in extensions that don’t necessarily apply to a single page, or might apply to more than one page. For example, the Google Mail Checker extension displays the number of unread emails in your inbox, regardless of the page you’re on.

Page actions, on the other hand, are used in extensions that apply to particular pages. An example is the Turn Off the Lights extension that dims the rest of the page while you’re watching a video on a YouTube.

Note that you may choose a browser action or a page action for your extension, or neither, but not both. Your extension can still affect the browsing experience in other ways even if you don’t choose a UI action at this step. Feel free to select ‘No’ if you’re following along with this walkthrough.

Regardless of which selection you make for UI action, the generator will also ask you if you’d like to include an options UI, content scripts, or affect the omnibox (a.k.a. address bar). Content scripts allow us to run JavaScript code in the context of the page, and they make for a fun example, so be sure to select that option.

? Would you like more UI Features?
 ◯ Options UI
❯◉ Content Scripts
 ◯ Omnibox

The last set of options the generator will present you with is which permissions you would like to set for your extension. Most are self-explanatory, but see this complete listing for details. None are required for this walkthrough, so just hit 'Enter’ and let Yeoman wrap up the generation process.

create bower.json
create package.json
create gulpfile.babel.js
create .gitignore
create .gitattributes
create .bowerrc
create .editorconfig
create app/manifest.json

# more messages...

Now we’re ready to develop!

Shake 'n Bake

Let’s add that content script we were talking about earlier. If you open up app/manifest.json in your project directory, you’ll see a section like the following.

"content_scripts": [
  {
    "matches": [
      "http://*/*",
      "https://*/*"
    ],
    "js": [
      "scripts/contentscript.js"
    ],
    // ...
  }
]

The matches key specifies the URL patterns for which your content script will be activated. It defaults to any URL, but you can restrict it to a particular domain or path if you’d like.

The js key is where your extension will look for JavaScript code to run. By default it includes scripts/contentscript.js, but you can add additional scripts as well.

Open scripts/contentscript.js and add the following code to change all occurrences of “app” on a page to “appetizer.”

'use strict';

function textNodesUnder(element) {
  let node;
  let textNodes = [];
  let walker = document.createTreeWalker(
    element,
    NodeFilter.SHOW_TEXT,
    null,
    false
  );

  while (node = walker.nextNode()) {
    textNodes.push(node);
  }

  return textNodes;
}

let textNodes = textNodesUnder(document.body);

textNodes.forEach(node =>
  node.nodeValue = node.
                     nodeValue.
                     replace(/App/g, 'Appetizer').
                     replace(/app/g, 'appetizer')
);

Now, to run a watcher that will both build your extension initially, and also watch for changes while you develop, run:

$ gulp watch

Sweet Rewards

The last step is to load your extension into Chrome. Visit chrome://extensions in your browser, and make sure 'Developer mode’ is checked. Then click the 'Load unpacked extension’ button, and navigate to and select the app subdirectory of your project.

Let’s visit a page on apple.com to test it out:

The Mac Appetizer Store

From here, you can do things like give your extension its own icon, build a production version, and submit it to the Chrome Web Store. Be sure to check out the extensions Developer’s Guide, which has a full list of the available features.

Is anyone hungry?

Tweet at Jeff

Share this post!