Monday, May 9, 2016

Build Your Own Chrome Extension Using Angular 2 & TypeScript

Chrome extensions are small web applications that add features to the Google Chrome browser. They can extend and customize browser behavior, the developer tools or the new tabs page. Extensions can be downloaded from the Chrome Web Store.

In this tutorial we are creating a Chrome extension that lets us save website URLs and displays them on every new tab's page. Of course, there are native Chrome bookmarks, but we want to integrate the bookmarks directly into the new tab's page and control their visual appearance.

You can find the complete project code in the GitHub repository here, and feel free to install a running version of the extension (with a few more features).

What We're Building

Let's start with a brief overview of what we want to develop. The screenshot shows that we will create a list consisting of a variable amount of bookmark items. The bookmarks are links that open the respective URLs when clicked.

Screenshot of the bookmark lists.

Every bookmark needs two pieces of information: its title and its URL. There will be an option to edit this information and another to delete the bookmark. To edit a bookmark, we'll need a form with two input fields and a submit button.

Screenshot of the edit modal.

To handle user input and render the list, we are going to use Angular 2 with TypeScript. Angular 2 is great for building client-side applications, and it works well with TypeScript, a typed super-set of JavaScript. If you'd like to start with an introduction to Angular 2 and TypeScript, I recommend this article.

You don't need more than a text editor and the Node Package Manager (npm) to follow this tutorial. However, publishing an extension requires a Google developer account, which can be created here.

Setup and Structure

It is time to work on the actual app, so let's create a new project folder:

mkdir sitepoint-extension && cd sitepoint-extension

TypeScript Config

Next we'll add a tsconfig.json file to the project folder. This file instructs the TypeScript compiler how to compile our .ts files.

{
  "compilerOptions": {
    "target": "ES5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ]
}

The important settings are the compilerOptions. There we specify that the ECMAScript target version should be ES5 and that the module code generation should happen with SystemJS ("module": "system").

With "sourceMap": true source map files will be generated. These .map files are great for debugging, because with them the browser can map the compiled ES5 code onto the TypeScript code.

For this tutorial we do not need to know more about the tsconfig.json file. The complete documentation can be found here.

Package.json

We are using npm to install the packages we need, and npm scripts to create some development and build tasks. To do this, we add a package.json to our main directory.

Angular 2 is currently in beta. For this tutorial, I used the beta 7 version. You may use a newer version of course, but I can not guarantee that everything will work smoothly because the framework might still change.

{
  "name": "SitePointBookmarkExtension",
  "description": "A Chrome Extension for Bookmarks",
  "version": "1.0.0",
  "scripts": {
    "lite": "lite-server",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "start": "concurrently \"npm run tsc:w\" \"npm run lite\""
  },
  "dependencies": {
    "angular2": "2.0.0-beta.7",
    "systemjs": "0.19.22",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.3",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.2",
    "zone.js": "0.5.15"
  },
  "devDependencies": {
    "concurrently": "^2.0.0",
    "lite-server": "^2.1.0",
    "typescript": "^1.7.5"
  }
}

Now let's install the packages with

npm install

Notice that there are some prepared npm scripts included that can be executed with npm run [script name]. At the moment, there are four scripts which will help us compile our TypeScript files and create a development server.

Manifest.json

Before we create our app, we need to add yet another .json file, the manifest.json. This file is necessary for every Chrome extension, as it specifies information about how the Web Store and the browser should handle the extension.

We will complete the file later, but for now let's just add the required and recommended properties:

{
    "manifest_version": 2,
    "name": "SitePoint Bookmark Extension",
    "short_name": "Make the most of a new tab",
    "description": "This extension helps you save your favorite webpages.",
    "version": "1.0.0",
    "author": "Michaela Lehr @fischaelameer"
}

Bookmark Component

Angular 2 is a component-based framework and our first component will be a single bookmark. This component will later be a child component, since we'll be creating a parent list component to contain the bookmarks.

Screenshot of the component architecture.

Let's create a new folder scripts and, within, a file called bookmark.component.ts.

// To create a component, we need Angular's "Component" function.
// It can be imported from the "angular2/core" module.
import { Component } from 'angular2/core';

// A component decorator tells Angular that the "BookmarkComponent" class
// is a component and adds its meta data: the selector and the template.
@Component({
    selector: 'sp-bookmark',
    template: '<h1>Bookmark</h1>'
})

// The "BookmarkComponent" module exports the "BookmarkComponent" class,
// because we will need it in other modules,
// e.g. to create the bookmark list.
export class BookmarkComponent { }

To bootstrap the BookmarkComponent component, we have to add another file, we call boot.ts:

// We need to reference a type definition (or 'typings') file 
// to let TypeScript recognize the Angular "promise" function
// (we'll need this later on) otherwise we'll get compile errors.
/// <reference path="../node_modules/angular2/typings/browser.d.ts" />

// Angular's "bootstrap" function can be imported 
// from the angular2/platform/browser module.
// Since we want to bootstrap the "BookmarkComponent",
// we have to import it, too.
import { bootstrap }    from 'angular2/platform/browser'
import { BookmarkComponent } from './bookmark.component'

// We can now bootstrap the "BookmarkComponent" as the root component.
bootstrap( BookmarkComponent );

Another new file, system.config.js, configures the SystemJS module loader. It will load the boot.ts file, we just created.

// SystemJS is the module loader for the application. 
// It loads the libraries and our modules and then catches and logs errors, 
// that may occur during the app launch.
System.config({
  packages: {
    scripts: {
      format: 'register',
      defaultExtension: 'js'
    }
  }
});
System.import('scripts/boot')
  .then(null, console.error.bind(console));

Before we can see anything in the browser, the last thing we need is an index.html file. We put the file in the root of our project directory, on the same level as the .json files.

<html>
  <head>

    <title>SitePoint Bookmark Extension</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- We load the libraries we need directly from the "node_modules" folder.
    In a more complex project, we would use a different approach here, 
    e.g. working with a build tool like gulp.js or Angular-CLI. -->
    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>

    <!-- Load the SystemJS config -->
    <script src="scripts/system.config.js"></script>

  </head>

  <body>
    <!-- Here we are using the selector "sp-bookmark", 
    which we defined as component meta data in the "BookmarkComponent" decorator. 
    Everything inside the element tag will only be seen 
    until our application is loaded. -->
    <sp-bookmark>Loading bookmarks...</sp-bookmark>
  </body>

</html>

Let's test what we've done by compiling the TypeScript files and starting the server:

npm run start

If everything worked correctly, we should see the browser open a new tab and showing a paragraph "Loading bookmarks..." before displaying our template, the headline "Bookmark".

Continue reading %Build Your Own Chrome Extension Using Angular 2 & TypeScript%


by Michaela Lehr via SitePoint

No comments:

Post a Comment