The Stuff New(s) Tab Chrome Extension
The idea — Josie Brough
We are lucky enough to work at an organisation that offers us a full day every other Friday for “innovation time” — time we can use to learn new skills, build new things, or test new ideas. The Chrome extension ended up being something that provided the opportunity for all three.
The idea came about after I (Josie) had seen a similar extension for a design portfolio website. Once I'd installed it, I realised how much I was engaging with it — pretty much every time I opened a new browser tab I was engaging with one of the items, and clicking through to their website. And I realised that the model was applicable to stuff.co.nz — it’s a way of putting Stuff in front of readers without them even having to actively go to our website.
So I had the idea, but lacked any sort of “techy know how” (I think that’s the technical term?) to put it into practice. Knowing that our team are collaboration masters, I started telling people about the idea. One of the first people I talked to about it was Lance — and as it turned out, he’d been thinking that he would like to try his hand at building a Chrome extension — perfect!
The development — Lance Cooper
Creating a Chrome extension was surprisingly easy for the most part. It’s simply HTML, CSS and Javascript. We load in the top stories using a JSON feed, cache them and display them.
It was also refreshing stepping out of the browser support game for a short while. I could use fancy new things, such as the fetch API, and not worry about the plethora of devices I normally test on.
Using React to render the UI
I’ve been wanting to try React for a little while, and figured this is a good use case. When you first load the extension, it pulls all the previous stories from the Google Storage API. At the same time, it heads off to the server for fresh stories. Traditionally you would display the stories from the cache, then blow them away and re-render everything once the JSON has come back.
With React, instead of blowing away everything, it only renders the differences. This is great, as you will never see a blank screen when stories are being removed and replaced.
This worked by calling React.render
on page load. This renders stories from storage. We also do a call to the server for a fresh JSON file.
Sometimes the JSON is the same as what is already displayed, while sometimes there are new stories, or stories that are in a different order — we don't have to worry about any of this. We update the storage with the new JSON; this triggers React.render
, and React re-renders all the stories. It only removes and adds the differences, otherwise it does nothing. Very nice!
Chrome storage for caching JSON
Loading news from a JSON feed is fine, but it takes time. You could be staring at a loading spinner for quite a while, which is not a great experience.
To solve this issue we made use of the Google Storage API that is exposed for extensions. Once stories are downloaded we cache them, so next time you open a new tab you see content straight away.
We fetch new stories and store them. This example is using the Fetch API and Promises:
var stories = fetch('/path/to/json')
.then(function(response) {
return response.json();
});
stories.then(function(data) {
chrome.storage.local.set({
'stories': data.stories
});
});
When we render the stories to the page, we get them from storage. If no storage exists yet, nothing happens.
function loadStories() {
chrome.storage.local.get('stories', function(result) {
if (result && result['stories']) {
// render your UI
}
});
}
And finally, we listen for changes to the storage. When changes are detected we simply call our render function to update the page for us. It's also smart enough not to call a change event when the same JSON is set.
chrome.storage.onChanged.addListener(function() {
// re-render your UI from storage
});
Google Analytics is meant to be easy
Surprisingly, Google Analytics was not straight-forward to implement. The documentation offers a tutorial on how to include Google Analytics into a chrome extension, but it uses the old google tracking code, which does not work. After researching around, I managed to hack together a working solution.
First up, you need to add a new content security policy to your manifest.json. This allows your plugin to talk to to the google analytics server:
"content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'"
The next catch is you need to have your analytics snippet in an external javascript file. Chrome extensions will not render inline javascript for security reasons. So create an analytics.js file, and include this into your HTML. Don't forget to add it to the background scripts in your manifest.json file.
"background": {
"scripts": [
"scripts/app.js",
"scripts/analytics.js"
]
}
In your analytics.js file, paste your Google Analytics snippet. To get it working we need to change a few values. Change the URL from '//www.google-analytics.com/analytics.js' to the URL we added in the content security policy. Also add an extra line to stop Google Analytics looking for an HTTP protocol.
// Standard Google Universal Analytics code
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://ssl.google-analytics.com/analytics.js','ga'); // change the URL here
ga('create', 'UA-XXXXXXXX-1', 'auto');
ga('set', 'checkProtocolTask', function(){}); // Removes failing protocol check. @see: http://stackoverflow.com/a/22152353/1958200
ga('require', 'displayfeatures');
ga('send', 'pageview', '/index.html');
And this seemed to get Google Analytics working. I really thought it would be a simple copy and paste job, but that would be too easy I guess.
The result
Turns out making a Google Chrome Extension was much easier than I thought. It only took about a day from start to finish, and I could develop in the comfort of my usual web development workflow.
Download the extension, give it a spin, and see what you think.