orange is the new blue: how to port chrome extension to firefox extension
TRANSCRIPT
Orange is the new blueHow to port Chrome Extension to Firefox Extensionor develop cross-browser extension from scratch
Boris Mossounovfacebook.com/mossounov
linkedin.com/in/borismossounovanotherguru.me
Major architectural differences:Chrome Extension v.s. Firefox Addon
Developer documentation
https://developer.chrome.com/extensionshttps://developer.mozilla.org/en-US/Add-ons
While digging Mozilla docs you can come across:Legacy Extensions Overlay extensions
Restartless Extensions Bootstrapped ExtensionsAdd-on SDK Extensions
Jetpack SDK Add-on SDK
==
=
Firefox Addon history digest:
Legacy Extensions / Overlay Extensions (XUL, JSM, XPCOM)
2004.06 - Firefox 0.9
Legacy Extensions / Overlay Extensions (XUL, JSM, XPCOM)
2004.06 - Firefox 0.9
Firefox Addon history digest:
Legacy Extensions / Overlay Extensions (XUL, JSM, XPCOM)
2004.06 - Firefox 0.9
browser.xul:
overlay.xul:
Firefox Addon history digest:
Legacy Extensions / Overlay Extensions (XUL, JSM, XPCOM)
2004.06 - Firefox 0.9
Mozilla starts Jetpack SDK project2009.09
Firefox Addon history digest:
Legacy Extensions / Overlay Extensions (XUL, JSM, XPCOM)
2004.06 - Firefox 0.9
Mozilla starts Jetpack SDK project2009.09
Restartless Extensions / Bootstrapped Extensions2011.03 - Firefox 4+
Jetpack SDK 0.1 releaseAddon SDK extensionscfx tool (python powered)
2011.06
jpm tool (node.js powered)2015.05 - Firefox 38
Firefox Addon history digest:
Google announces Chrome Extensions support2009.09
Google Chrome Store launches(with blackjack and extensions)
2010.12
Chrome Extension history digest:
Краткая история:2004.06 - Firefox 0.9
2009.09
2011.03 - Firefox 4+
2011.06
2015.05 - Firefox 38
2010.12
Google announces Chrome Extensions support
Legacy Extensions / Overlay Extensions (XUL, JSM, XPCOM)addons.mozilla.org
Mozilla starts Jetpack SDK project
Restartless Extensions / Bootstrapped Extensions
Jetpack SDK 0.1 releaseAddon SDK extensionscfx tool (python powered)
jpm tool (node.js powered)
Google Chrome Store launches (with blackjack and extensions)
While digging Mozilla docs you should read about:Legacy Extensions Overlay extensions
Restartless Extensions Bootstrapped ExtensionsAdd-on SDK Extensions
Jetpack SDK Add-on SDK
==
=
An average browser extensionconsists of the following blocks:
manifest
background script
content scripts, styles, assets
toolbar button popup
locales
embedded pages(options / help)
The major difference between Chrome Extension and Firefox Addon
is the way the following 3 blocks interact:
background.js
contentscript.js popup.js
Google Chrome possesses two APIs for message passing:
• Simple one-time requests• Long-lived connections
https://developer.chrome.com/extensions/messaging
Simple one-time requests
chrome.runtime.sendMessage({greeting: «hello»}, function(response) {
console.log(response.farewell);});
background.js
contentscript.js popup.js
chrome.tabs.sendMessage(tabs[0].id, {greeting: «hello»}, function(response) {console.log(response.farewell);});
background.js
contentscript.js
chrome.runtime.onMessage.addListener( function(request, sender, callback) { console.log(sender.tab ? "from a content script:" +
sender.tab.url : "from the extension"); if (request.greeting ==
"hello") callback({farewell:
"goodbye"}); });
background.js
contentscript.js popup.js
?
Long-lived connections
port.postMessage({joke: "Knock knock»});
port.onMessage.addListener(function(msg) { if (msg.question == "Who's there?"){ port.postMessage({answer: "#4front"}); }});
background.js
contentscript.js popup.js
Window chrome.extension.getBackgroundPage()
background.js
contentscript.js popup.js
contentscript.js & popup.js can:
Is cross-browser support on the table?
If it is, then don’t.If not, go on.
background.js
contentscript.js popup.js
• two message passing APIs• contentscript.js & popup.js can get
background window object and store some objects and methods there.
• all blocks can interact using untitled messages and setting response callbacks.
• background.js knows nothing about other scripts till they connect to it
What about Firefox?
https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/using_port
port.emit("myMessage", msg);
port.on("myMessage",function(msg) { if (msg.question == "Who's there?") port.emit("myMessage.reply", {
answer: "#4front"});});
background.js
contentscript.js popup.js
background.js
contentscript.js popup.js
• all blocks are run in isolated runtimes and can interact using named messages without response callbacks
• background.js creates contentscript.js & popup.js and can control them
callbacks = {«1234»:
function(payload){},«1235»:
function(payload){}
}
message = {action:
«myMessage.reply»,uid: 1234,paylaod: {}}
message = {}
message = {action:
«myMessage»,paylaod: {}}
message = {action:
«myMessage»,uid: 1234,paylaod: {}}
Let’s compare Mozilla Extension & Chrome Extensionby blocks:
manifest
background script
content scripts, styles, assets
toolbar button popup
locales
embedded pages(options / help)
manifest
manifest.jsondescribes:• title, description,
version, license,• location of all
scripts, styles, html,• permissions
package.jsondescribes:• title, description,
version, license,• location of background
script
and background scriptloads all the content & popup scripts, styles, html
manifest
How to develop cross-browser way:
Setup grunt task, that will synchronize manifest.json & package.json (version, title, description…)
• Invisible html page with it’s window js-object,
• this window js-object shares the same runtime context with content scripts and popup script
• Separate javascript without window object.
• this javascript is run in an isolated runtime
• Background script initializes content scripts and popup and can control them.
• EcmaScript 6
background script
How to develop cross-browser way:
1. Avoid chrome.extension.getBackgroundPage() at all costs
2. For Firefox - create separate background script since firefox addon sdk is implemented on ES6.
3. Develop a cross-browser middle layer to call browser specific API that above all implements message passing with named messages and response callbacks
4. Store background script and content script / popup script logic in separate files. Even if some mechanisms require both background and content scripts. Use message passing, Luke.
background script
• content scripts are run in a web-page isolated world
• can access background window
• cross-domain request are manifest permission dependent
• content scripts are run in a web-page isolated world
• are run in context isolated from background script
• cross-domain requests are forbidden
content scripts, styles, assets
How to develop cross-browser way:
1. Avoid chrome.extension.getBackgroundPage() at all costs2. Develop a cross-browser middle layer to call browser
specific API that above all implements message passing with named messages and response callbacks
3. Store background script and content script / popup script logic in separate files. Even if some mechanisms require both background and content scripts. Use message passing, Luke.
4. For ajax requests in Firefox use Request API in background and message passing.
content scripts, styles, assets
• only one toolbar button• can access background
window • popup load on toolbar
button click and unload on hide
• javascript is loaded using <script>
• popup size is calculated automatically
• several toolbar buttons allowed
• popup javascript context is isolated from background js
• popup is loaded when extension is initialized and unloaded with extension itself
• scripts should be loaded like content scripts
• popup size is set manually
toolbar button popup
How to develop cross-browser way:
1. Avoid chrome.extension.getBackgroundPage() at all costs2. Consider that only one toolbar button allowed3. Develop popup script assuming it is loaded once and should
react to all events that occur in content scripts and background script.
4. Keep in mind that Chrome and Firefox load popup differently though.
5. In Firefox load popup scripts using content script mechanism and block those loaded using <script>. (https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Display_a_Popup)
toolbar button popup
Format: .json
locale API available in:• background script• content script• popup script
Format: .properties
locale API available in:• background script only
that can pass dictionary to rest of scripts
• in popup.html you can use nls ids that will be replaced by localized strings
locales
How to develop cross-browser way:
1. Chose one of the formats as the base one (json).2. Use firefox properties to store language identifier only.3. In Firefox content scripts and popup scripts should request whole localized dictionary that background should read from json. Or you can provide dictionary on initialization of content and popup scripts as config.
locales
How to assemble cross-browser extension:
npm install -g yonpm install -g generator-chrome-extensionnpm install -g generator-firefox-extensionnpm install -g jpm
How to assemble?yo chrome-extension yo firefox-extension
Main difference:background scripts - /liball the rest - /data
Lets make it look more consistent
yo chrome-extension yo firefox-extension
Let’s move both to the single project
yo chrome-extension yo firefox-extension
.gitignore
.gitignore
1. In the single project:app-chromeapp-firefox
2. grunt copy:app-chrome/scripts/bg-* ->
app-firefox/libвсе остальное ->
app-firefox/data
3. add to .gitignoreapp-firefox/libapp-firefox/data
yo chrome-extension yo firefox-extension
or…
adjust folder structure to the Firefox standards and update manifest.json
Let’s move both to the single project
en-US.properties contains only one string:
lng= en
it is used to detect language and load appropriate .jsondictionary in bg-main-firefox
locales
and one last thing…
generator-firefox-extension uses cfx utility for building and runs it using shell
cfx is deprecated by Mozillayou should use jpm instead
but that’s easy
cfx syntax
jpm syntax
don’t forget:cd app-firefox
How to develop cross-browser way:• To generate prject use yeoman generators: generator-chrome-extension & generator-firefox-
extension. Replace cfx with jpm.• Merge code base to the single project and setup grunt build.• Setup grunt task that will synchronize manifest.json & package.json (version, title,
description…).• Develop a cross-browser middle layer to call browser specific API that above all implements
message passing with named messages and response callbacks• Avoid chrome.extension.getBackgroundPage() at all costs• Create two separate background scripts for Chrome & Firefox.• Store background script and content script / popup script logic in separate files. Even if some
mechanisms require both background and content scripts. Use message passing, Luke.• For ajax requests in Firefox use Request API in background and message passing, in Chrome -
jQuery.ajax will do.• Consider that only one toolbar button allowed.• Develop popup script assuming it is loaded once and should react to all events that occur in
content scripts and background script. Keep in mind that Chrome and Firefox load popup differently though.
• In Firefox load popup scripts using content script mechanism and block those loaded using <script>. (https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Display_a_Popup).
• Chose one of the formats as the base one (json). Use firefox properties to store language identifier only. In Firefox content scripts and popup scripts should request whole localized dictionary that background should read from json. Or you can provide dictionary on initialization of content and popup scripts as config.
manifestbackground scriptcontent scripts, styles, assets
toolbar button popupall together
Is it worth it?
Browsers market share in Russian Federation
Overall browsers market share
To create IE extension with the same functionality like Chrome or Firefox extension you need to
implement it on C#, so no cross-browser support here.
Google Chrome = Webkit = Opera = Yandex Browser, etc
Apple Safari is almost Webkit.
Keep in mind:
What about Safari?
So implementing browser extension the way it was described here covers support of all the
major browsers except IE.
Questions?