Building Chrome Extensions using Ember CLI
Nick Blanchet @h55nick
André Malan @ramcio
SimpleReach
http://simplereach.com
Dear God Why?
- Why climb Everest?
- Small app for teaching Ember
- It's not that hard and Ember is awesome
What we built...
Building a Chrome Extension
- Manifest File
- Background JS
- Developer Pane Include
Manifest.json
{
"name": "SimpleReach Internal Extension",
"version": "2.5",
"manifest_version": 2,
"description": "Internal use tool for admin purposes",
"icons": { "128": "icon128.png" },
"browser_action": {
"default_icon": "icon.png",
"default_popup": "dist/index.html"
},
"devtools_page": "html/devtools.html",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"background": {
"page": "html/background.html"
},
"omnibox": { "keyword" : "SR" },
"permissions": [
"background",
"webRequest",
"debugger",
"tabs",
"http://*/*",
"https://*/*"
]
}
background.js
//
// Add webRequest Listener
//
console.log("[SRPLUGIN] Add Listener to edge.simplereach.com");
chrome.webRequest.onBeforeRequest.addListener(
addRequestToLocalStorage, { urls: [ '*://edge.simplereach.com/*' ] }
);
//
// Properly format data to insert into localstorage
//
function addRequestToLocalStorage(details){
var result = SPR.decode(details.url.split('?')[1]);
result.type = details.url.split('?')[0].split('/')[3];
result.id = details.method + ':' + details.requestId;
result.ts = details.timeStamp;
result.tab_id = details.tabId;
// add to DB
BG.addRequestToLocalStorage(result);
};
Our Server
devtools.html
<!doctype html>
<html>
<head>
<style>
body {
min-width: 357px;
overflow-x: hidden;
}
img {
margin: 5px;
border: 2px solid black;
vertical-align: middle;
width: 75px;
height: 75px;
}
</style>
<script src="devtools.js"></script>
</head>
<body>
</body>
</html>
var panelWindow,
injectedPanel = false,
injectedPage = false,
panelVisible = false,
savedStack = [];
chrome.devtools.panels.create(
"Reach", "/icon.png", "/dist/index.html"
);
Making it work with Ember CLI
ember build --watch
Security for evals
//manifest.json
{
"content_security_policy": "default-src 'self' 'unsafe-eval'",
}
Debugging
Dit maak jou gat seer...
Run as plain Ember app (also good for testing)
//vendor/chrome/chrome.js
if(!chrome.devtools){
console.log('loading DEV CHROME');
chrome.devChrome = true;
chrome.devtools = {
inspectedWindow: {
eval: function(evalString){ },
getResources: function(callback){ },
reload: function(options){ }
}
});
}
//brocfile.js
app.import('vendor/chrome/chrome.js');
Model Layer
(because everybody loves Ember Data)
LocalStorage Adapter
import DS from 'ember-data';
export default DS.LSAdapter.extend({
namespace: 'reach'
});
https://github.com/kurko/ember-localstorage-adapter
startServices: function(){
var self = this;
function onStorageEvent(storageEvent){
if(storageEvent['key'] === 'reach'){
self.store.find('n').then(function(views){
self.set('model', views);
});
}
}
window.addEventListener('storage', onStorageEvent, false);
}.on('init')
BG.addRequestToLocalStorage = function(responseObject){
var localStorageJSON = JSON.parse(localStorage.getItem(DB.localStorageName));
if (!localStorageJSON){ // create proper structure for localStorage DB.
localStorageJSON = {
'n' : {'records': {}},
't' : {'records': {}},
'x' : {'records': {}}
};
}
localStorageJSON[responseObject.type]['records'][responseObject.id] = responseObject;
localStorage.setItem(DB.localStorageName, JSON.stringify(localStorageJSON));
};
Custom Chrome Adapter
https://github.com/emberjs/ember-inspector/tree/master/app/adapters
/* globals chrome */
import BasicAdapter from "./basic";
var emberDebug = null;
export default BasicAdapter.extend({
name: 'chrome',
sendMessage: function(options) {
options = options || {};
this.get('_chromePort').postMessage(options);
},
_chromePort: function() {
return chrome.extension.connect();
}.property(),
_connect: function() {
var self = this;
var chromePort = this.get('_chromePort');
chromePort.postMessage({ appId: chrome.devtools.inspectedWindow.tabId });
chromePort.onMessage.addListener(function(message) {
if (typeof message.type === 'string' && message.type === 'iframes') {
sendIframes(message.urls);
}
self._messageReceived(message);
});
}.on('init'),
Fin!
Questions?
Thanks to @pnts for helping with styles
Thanks to Ember CLI folks
Thanks to Ember Inspector folks for lots of code examples
http://www.simplereach.com/careers
Ember Chrome Extensions
By Andre Malan
Ember Chrome Extensions
- 2,388