Creating A “Save For Later” Chrome Extension With Modern Web Tools
- By Daniel Sternlicht
- November 17th, 2014
- 0 Comments
Creating an prolongation for a Chrome browser is a good approach to take a tiny and useful suspicion and discharge it to millions of people by a Chrome Web Store. This essay walks we by a growth routine of a Chrome prolongation with complicated web collection and libraries.
It all starts with an idea. Mine was shaped while reading an engaging (and long) essay about new front-end technologies. we was concentrating on reading a essay when unexpected my mother called me to flog out a bad baby seagul that got stranded on a balcony. When we finally got behind to a article, it was too late — we had to go to work.
To make a prolonged story short, we suspicion it would be good to emanate a Chrome prolongation that enables we to symbol your reading swell in articles so that we can continue reading them after — anywhere.
“Markticle” is a name we chose for this extension. I’ll share here a technologies that we used to rise it. After reading this article, you’ll have a ready-to-use “Save for Later”-like Chrome extension.
Prior Knowledge
We’re going to use a few front-end technologies. While we can learn some of them on a fly, believe of others is compulsory (marked in bold):
- jQuery
- AngularJS
- Node.js
- Grunt
- Bower
- Yeoman
Scaffolding
Let’s start with some infrastructure work.
Assuming you’re informed with npm2 (Node.js’ package manager), we’re going to use a Yeoman generator to emanate a simple prolongation for Chrome.
Note: If we still don’t have Yeoman commissioned on your machine, start by following a “Getting Started3” tutorial.
Open a new authority line or depot window, and write a following command:
npm implement -g generator-chrome-extension
This will implement Yeoman’s generator for Chrome extensions on your machine.
Create a new folder in your record system:
mkdir my-extension
And afterwards run a following authority to beget all of a files that you’ll need to start building your extension:
yo chrome-extension
After regulating this command, a generator will ask we that facilities to embody in a extension.
In a case, Markticle should do a few things:
- Add an idol subsequent to a residence bar.
- Run on any page that a user opens.
- Run some formula in a credentials to bond a stream page to a prolongation in sequence to save data.
For a initial feature, we’ll name “browser” as a UI action. To capacitate a prolongation to run on any web page, we’ll check a “Content scripts” box. Finally, to capacitate credentials processes to run, we’ll use a background.js
file.
Note: Another approach to emanate a Chrome prolongation is to use a online generator Extensionizr4. Extensionizr is a good apparatus that helps we emanate simple Chrome extensions. It has mixed pattern options, all of that can be enabled with checkboxes. In a end, you’ll get a ZIP record that includes all of a files you’ll need to start operative on a extension. The downside is that you’ll need to configure Grunt and Bower manually.
Folder Tree
Let’s demeanour during a generated files and folders we’ve got now.
app
test
bower.json
package.json
Gruntfile.js
Gruntfile.js
is where we’ll configure Grunt tasks for serving, building, contrast and wrapping a extension.
The package.json
and bower.json
files are Node.js and Bower JSON files that conclude a extension’s dependencies on third-party plugins and libraries.
The test
folder will embody all of a section and end-to-end tests for a extension. Finally, a app
folder is a many engaging since it is where a core of a prolongation will reside.
After reordering some of a folders and files, here’s what a app
folder will demeanour like:
icons
icon-16.png
icon-19.png
icon-38.png
icon-128.png
images
views
scripts
inject.js
background.js
styles
main.css
_locales
en
messages.json
index.html
manifest.json
The many critical record here is manifest.json
. It is indeed a heart of a extension, and it specifies several things, including a following:
- the plcae of any record used by a extension,
- which idol to benefaction as a “action” button,
- the permissions that your prolongation needs,
- the name of a extension.
Here’s an instance of what a manifest.json
record should demeanour like:
"name": "Markticle",
"version": "1.0.0",
"manifest_version": 2,
"icons":
"16": "icons/icon-16.png",
"38": "icons/icon-38.png",
"128": "icons/icon-128.png"
,
"default_locale": "en",
"background":
"scripts": [
"scripts/helpers/storage.helper.js",
"scripts/background.js"
]
,
"browser_action":
"default_icon": "icons/icon-19.png",
"default_popup": "index.html"
First Flight
We now have a simple prolongation that does nothing. Still, only to make certain all is in place and operative properly, let’s exam a prolongation in runtime.
Open Chrome and write this in a residence bar:
chrome://extensions
This page displays information about all of a extensions now commissioned in your browser.
In a top-right corner, you’ll see an choice to capacitate “Developer mode.” Click it.
Now, click a “Load unpacked extension” button, crop to a plcae of a prolongation we created, name a app
folder, and click “Select.”
You should now see a extension’s idol subsequent to a residence bar.
Installing Dependencies
Before regulating a app, we need to implement some Node.js plugin dependencies. We’ll do so by regulating a following command:
npm install
The final thing we need to do before diving into a formula is set adult a dependencies of a third-party libraries we’re going to use. We do this in a bower.json
file:
"name": "Markticle",
"version": "1.0.0",
"dependencies":
"angular": "1.2.6",
"jquery": "2.0.3",
"normalize.scss": "3.0.0"
,
"devDependencies":
I chose 3 libraries for this project: AngularJS, jQuery and Normalize.css. To implement these, run this command:
bower install
Development
Now that we are prepared to start development, let’s separate a work into dual parts.
The initial partial will be a popup window that opens when a user clicks a extension’s icon. Markticle’s popup will benefaction a list of bookmarks (i.e. websites) that a user has saved.
The second partial connects a user’s actions to a prolongation itself. Each time a user takes a sold movement on a page, a prolongation should save a URL and pretension of a stream add-on (so that we know what to arrangement in a popup).
The initial partial is flattering straightforward. We’ll use classical AngularJS formula to rise it.
Let’s start by adding a following record structure to a app/scripts
folder.
scripts
controllers
main.controller.js
directives
main.directive.js
helpers
storage.helper.js
services
storage.service.js
app.js
inject.js
background.js
In a app.js
file, we’ll supplement a following code, that will conclude a app’s categorical module:
angular.module('markticle', []);
Now, let’s supplement some simple formula to a index.html
file:
!DOCTYPE HTML
html
head
couple href="styles/main.css" rel="stylesheet"
/head
physique ng-app="markticle"
div id="main_wrapper"Sample/div
book src="bower_components/jquery/jquery.min.js"
book src="bower_components/angular/angular.min.js"
book src="scripts/app.js"
book src="scripts/controllers/main.controller.js"
book src="scripts/directives/main.directive.js"
/body
/html
What we’ve finished here is really simple:
- define a tellurian AngularJS procedure named
markticle
, - add a singular div component with representation text,
- include a list of book files that we’re going to use.
Now, let’s extend a div component that we created.
div id="main_wrapper" ng-controller="MainController"
header
h1My Marks/h1
/header
section id="my_marks"/section
/div
Again, zero special here — we’ve only set adult an AngularJS controller named MainController
and combined some header
and section
tags for a arriving content.
In a app/scripts/controllers/main.controller.js
file, let’s emanate a new AngularJS controller:
angular.module('markticle').controller('MainController', function($scope)
$scope.marks = [];
);
This controller now doesn’t do most solely conclude an array, named marks
, that is trustworthy to a controller’s scope. This array will embody a user’s saved items.
Just for fun, let’s supplement dual equipment to this array:
$scope.marks = [
title: 'Smashing magazine',
url: 'http://www.smashingmagazine.com/'
,
title: 'Markticle',
url: 'https://markticle.com'
];
Now, in a index.html
file, let’s loop by them with a ng-repeat
directive:
section id="my_marks"
ul
li ng-repeat="mark in marks"
a target="_blank" ng-href="mark.url"mark.title
/li
/ul
/section
Click a extension’s idol to open a popup and see a result!
After adding some simple CSS to a main.css
file, here’s what we’ve come adult with:
Now for a second part.
In a second part, we’ll bond user interactions to a extension.
Let’s start by adding a new skill to a manifest.js
file:
…
"background": …,
"content_scripts": [
"matches": ["http://*/*", "https://*/*"],
"js": ["bower_components/jquery/jquery.min.js", "scripts/inject.js"]
],
…
Here, we’ve combined a skill named content_scripts
, that has a possess dual properties:
matches
This is an array that defines in that websites to inject a book — in a case, all websites.js
This is an array of scripts that will be injected into any web page by a extension.
Let’s open a inject.js
book and supplement some simple formula to it:
$(document).ready(function()
var createMarkticleButton = function()
var styles = 'position: fixed; z-index: 9999; bottom: 20px; left: 20px;';
$('body').append('');
;
$(document).on('click', '#markticle_button', function()
var pretension = document.title;
var url = window.location.href;
console.log(title + ': ' + url);
);
createMarkticleButton();
);
This book does dual things once a page is ready. First, it adds a simple symbol regulating a createMarkticleButton()
method. Then, it adds an eventuality listener that writes a URL and pretension of a stream page to Chrome’s console any time a user clicks a button.
To exam this, go to chrome://extensions
, find your extension, and click a “Reload” button. Then, open any website, click a Markticle button, and demeanour during a console in Chrome Developer Tools.
Storing Data
To store information in a prolongation (without carrying to use a server-side solution), we have several options. My favorite is HTML5 localStorage7.
Let’s go behind to a scripts
folder and emanate a localStorage service. First, revise app/scripts/helpers/storage.helper.js
:
var markticleStorageService = function()
var lsName = 'marks';
var information = localStorage.getItem(lsName) ? JSON.parse(localStorage.getItem(lsName)) : [];
lapse
get: function()
lapse data;
,
add: function(item)
this.remove(item.url);
data.push(item);
this.save();
,
remove: function(url)
var idx = null;
for(var i = 0; i data.length; i++)
if(data[i].url === url)
idx = i;
break;
if(idx !== null)
data.splice(idx, 1);
this.save();
,
save: function()
localStorage.setItem(lsName, JSON.stringify(data));
;
;
With this, we’re initial holding a data
array with a stream information that we’re pulling from localStorage. Then, we’re divulgence a few methods to manipulate a data, such as get()
, add()
and remove()
.
After formulating this class, let’s also supplement it as an AngularJS use in app/scripts/services/storage.service.js
:
angular.module('markticle').service('StorageService', markticleStorageService);
Note: Don’t forget to impute to both scripts in index.html
.
The reason we’ve separate it into dual scripts is since we’re going to reuse a markticleStorageService
category in background.js
, where we won’t entrance AngularJS.
Returning to a MainController
, let’s make certain we’re injecting a storage use in a app:
angular.module('markticle').controller('MainController', function($scope, StorageService)
$scope.marks = […];
);
Finally, let’s bond a StorageService
information to a app and deliver a routine that will be used in a UI.
angular.module('markticle').controller('MainController', function($scope, StorageService)
$scope.marks = StorageService.get();
$scope.removeMark = function(url)
StorageService.remove(url);
$scope.marks = StorageService.get();
if(!$scope.$$phase)
$scope.$apply();
;
);
Back to a index.html
file. Let’s supplement an choice to mislay equipment by joining a perspective to a controller’s remove()
method:
li ng-repeat="mark in marks"
a ng-href="mark.url"mark.title/a
camber class="remove" ng-click="removeMark(mark.url)"remove/span
/li
So, any time a user clicks a “Remove” button, it will call a remove()
routine from a controller, with a page’s URL as a parameter. Then, a controller will go to StorageService
and mislay a intent from a information array and save a new information array to a localStrorage property.
Background Process
Our prolongation now knows how to get and mislay information from a localStorage service. It’s time to capacitate a user to supplement and save items.
Open app/scripts/background.js
, and supplement a following code:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse)
if(request)
var storageService = new markticleStorageService();
if(request.action === 'add')
storageService.add(request.data);
);
Here, we’re adding a listener for a onMessage
event. In a callback function, we’re formulating a new instance for markticleStorageService
and removing a request
object. This intent is what we’re going to send with a chrome.extension.sendMessage
eventuality that is triggered from a inject.js
script. It contains dual properties:
action
This is a form of movement that we wish a credentials routine to perform.data
This is a intent of a information that we wish to add.
In a case, a form of movement is add
, and a intent is a indication of a singular item. For example:
title: 'Markticle',
url: 'https://markticle.com'
Let’s go behind to a inject.js
book and bond it to a background.js
script:
$(document).on('click', '#markticle_button', function()
var pretension = document.title;
var url = window.location.href;
chrome.extension.sendMessage(
movement : 'add',
data:
title: title,
url: url
);
alert('Marked!');
);
Now, go to any website and click a “Mark me!” button. Open a popup again and see a new intent you’ve only added. Pretty cool, right?
Build
We’ve combined a cold “Save for Later” Chrome prolongation of sorts. Before releasing it to a Chrome store, let’s speak about a build routine for a Chrome extension.
A build routine for this kind of app could have a few goals (or “tasks,” to use Grunt’s fixing convention):
- test (if you’re essay section tests for a extension),
- minify,
- concatenate,
- increment a chronicle series in a perceptible file,
- compress into a ZIP file.
If you’re regulating Yeoman’s generator, we can perform all of these tasks automatically by regulating this command:
grunt build
This will emanate a new dist
folder, where we will find a minified and concatenated files, and another folder named package
, where you’ll find a ZIP record named with a stream chronicle of your extension, prepared to be deployed.
Deploy
All that’s left to do is muster a extension.
Go to your “Developer Dashboard8” in a Chrome Web Store, and click a “Add new item” button.
Browse to a ZIP record we combined and upload it. Fill in all of a compulsory information, and afterwards click a “Publish changes” button.
Note: If we wish to refurbish a extension, instead of formulating a new item, click a “Edit” symbol subsequent to a extension. Then, click a “Upload updated package” symbol and repeat a remaining steps.
Conclusion
As we can see, building a Chrome prolongation has never been easier!
If we use Node.js and Grunt for their time-saving features, AngularJS as a growth horizon and a Chrome Web Store for distribution, all we need is a good idea.
I wish you’ve enjoyed reading this article. If it was too prolonged to review in one sitting, cruise regulating Markticle10.
(il, al)
Footnotes
- 1 http://www.smashingmagazine.com/wp-content/uploads/2014/11/image01-large-opt.jpg
- 2 http://nodejs.org/
- 3 http://yeoman.io/learning/index.html
- 4 http://extensionizr.com/
- 5 http://www.smashingmagazine.com/wp-content/uploads/2014/11/image04-large-opt-500×180.jpg
- 6 http://www.smashingmagazine.com/wp-content/uploads/2014/11/image03-large-opt.jpg
- 7 http://www.w3schools.com/html/html5_webstorage.asp
- 8 https://chrome.google.com/webstore/developer/dashboard
- 9 http://www.smashingmagazine.com/wp-content/uploads/2014/11/image08-large-opt.jpg
- 10 https://markticle.com/
↑ Back to topShare on Twitter
Creating A “Save For Later” Chrome Extension With Modern Web Tools
Nenhum comentário:
Postar um comentário