{"id":82,"date":"2011-06-06T15:58:58","date_gmt":"2011-06-06T15:58:58","guid":{"rendered":"http:\/\/alexrock.com\/blog\/?p=82"},"modified":"2017-10-10T13:52:10","modified_gmt":"2017-10-10T13:52:10","slug":"differences-between-firefox-and-chrome-extensions","status":"publish","type":"post","link":"https:\/\/alexrock.com\/blog\/archives\/82-differences-between-firefox-and-chrome-extensions.html","title":{"rendered":"Differences between Firefox and Chrome Extensions"},"content":{"rendered":"<p>This entry was written during my time at IBM for a Firefox extension I had developed related to bookmarks<\/p>\n<p dir=\"ltr\">I&#8217;ve been using <a href=\"http:\/\/www.google.com\/chrome\">Google Chrome<\/a> more often lately. I still prefer Firefox in a lot of ways, but you can&#8217;t beat the speed of Chrome.<\/p>\n<p dir=\"ltr\">One thing I miss in chrome is a lot of my extensions, including my project. I decided to take a look at how hard (if even possible) it would be to port my project to Chrome. It turns out, not as bad as I thought (though certainly not trivial).<\/p>\n<p dir=\"ltr\">Chrome&#8217;s approach to extensions is fundamentally different than Firefox. In Firefox an extension has pretty much full access to the entire browser &#8211; you can <a href=\"https:\/\/addons.mozilla.org\/en-us\/firefox\/addon\/tamper-data\/\">monitor and change every request the browser makes<\/a>, you can <a href=\"https:\/\/addons.mozilla.org\/en-US\/firefox\/user\/364\/\">modify the way tabs work<\/a>, heck you can build the <a href=\"https:\/\/addons.mozilla.org\/en-US\/firefox\/addon\/firebug\/\">best javascript debugger on the planet<\/a>. Chrome extensions are far more limited in what they can do. They run in their own sandbox, apart from the rest of the browser. You&#8217;re limited to a <a href=\"http:\/\/code.google.com\/chrome\/extensions\/browserAction.html\">button with a dropdown (popup)<\/a> display, an i <a href=\"http:\/\/code.google.com\/chrome\/extensions\/pageAction.html\">con on the URL bar <\/a>(also with a potential popup), <a href=\"http:\/\/code.google.com\/chrome\/extensions\/contextMenus.html\">adding items to context menus<\/a>, and that&#8217;s about it. While you can get access to the websites the user accesses, and even modify them, you can&#8217;t fundamentally alter the browsers UI or behavior the way you can do with Firefox. This is not necessarily a bad thing &#8211; simplicity has it&#8217;s virtues &#8211; but it makes a big difference in the approach you take to the extensions.<\/p>\n<p dir=\"ltr\">Despite the differences in approach, the differences in writing an extension for one app or the other is not quite as big as I expected. Firefox extensions (for the most part) have their UI written in <a href=\"https:\/\/developer.mozilla.org\/en\/XUL\">XUL<\/a>(XML User Language), are scripted with JavaScript, and is themed with CSS. Chrome extensions have their UI written in HTML, are scripted with JavaScript, and themed with CSS. Well, hey, we have 2 out of 3, right? And while XUL and HTML are pretty different, they&#8217;re not <i>that<\/i> different, especially when talking into account the HTML5 features chrome supports.<\/p>\n<div dir=\"ltr\">\n<p>Writing an extension for Chrome is very similar to writing a website. In fact, it&#8217;s pretty much identical. The only difference is that you have access to the <a href=\"http:\/\/code.google.com\/chrome\/extensions\/api_index.html\">chrome.* API<\/a>, giving you some control over browser tabs, windows, history, etc. The downside is that you don&#8217;t have a rich featureset of widgets like you do with firefox ( <a href=\"https:\/\/developer.mozilla.org\/en\/XUL_controls\">trees, autocomplete, date controls, etc)<\/a>. On the other hand however, you can use javascript libraries like <a href=\"http:\/\/jquery.com\/\">jquery <\/a>or <a href=\"http:\/\/dojotoolkit.org\/\">dojo<\/a>, and not pollute or mess up the browser namespace. If you&#8217;re experienced with developing web applications, then it&#8217;s pretty easy to dive into creating an extension for chrome. Writing an extension for Firefox takes a bit more getting used to, learning a new UI language (similar to, but still different from HTML), new set of widgets, new set of quirks (although projects like <a href=\"https:\/\/jetpack.mozillalabs.com\/\">jetpack<\/a> are making it easier to write Firefox extensions).<\/p>\n<p>Here&#8217;s a list of things I&#8217;ve found different going through and porting my project.<\/p>\n<div>\n<h4>No <span style=\"font-style: italic;\">for each<\/span> loop<\/h4>\n<p>One of the nice things about writing a Firefox or Chrome extension is that both browsers are fairly standards compliant, and both support modern versions of javascript ( <a href=\"https:\/\/developer.mozilla.org\/en\/JavaScript\/New_in_JavaScript\/1.8.1\">Version 1.8.1<\/a> as of Firefox 3.5. Chrome supports <a href=\"http:\/\/en.wikipedia.org\/wiki\/ECMAScript\">ECMA Script<\/a> Edition 3, + roughly <a href=\"https:\/\/developer.mozilla.org\/en\/JavaScript\/New_in_JavaScript\/1.7\">Javascript 1.7<\/a> ). This means stuff like <a href=\"https:\/\/developer.mozilla.org\/en\/JavaScript\/Guide\/Working_with_Objects#Defining_Getters_and_Setters\">properties<\/a>, <a href=\"https:\/\/developer.mozilla.org\/en\/JavaScript\/Guide\/Predefined_Core_Objects#Array_Methods\">fun array methods<\/a> and other little goodies. One of the things that Firefox supports is the <a href=\"https:\/\/developer.mozilla.org\/en\/JavaScript\/Reference\/Statements\/for_each...in\">for each<\/a> loop, which is actually part of the <a href=\"http:\/\/en.wikipedia.org\/wiki\/E4x\">E4X <\/a>standard. This is a handy little item, it lets you loop through all of the items in an object, rather than the properties in an object. The catch? It&#8217;s not supported in chrome. I had to remove all of these loops in the my project&#8217;s code in order for chrome to even load my JavasScript.<\/p>\n<h4>No Preferences System<\/h4>\n<p>Firefox has a fairly nice <a href=\"https:\/\/developer.mozilla.org\/en\/Code_snippets\/Preferences\">preference system<\/a>. Accessing it is a bit clunky, but the nice thing is that you can place an observer on any preference branch and get updates as soon as it changes.<\/p>\n<p>In chrome there&#8217;s no such thing. There is <a href=\"http:\/\/dev.w3.org\/html5\/webstorage\/\">localStorage<\/a>, which you can use to store preferences, but if you want the observer functionality, you have to build it yourself.<\/p>\n<p>I wrote a wrapper around localStorage to present a similar interface to Firefox for preferences, and added methods for registering observers. Because all of the pref changes that need observing are made by only by my project, I didn&#8217;t have to worry about observers getting updates if they changed through some other means.<\/p>\n<h4>No Password Storage<\/h4>\n<p>Firefox has <a href=\"https:\/\/developer.mozilla.org\/en\/XPCOM_Interface_Reference\/nsILoginManager\">nsILoginManager<\/a> for storing passwords. By default these are stored unencrypted, but you can set a <a href=\"http:\/\/kb.mozillazine.org\/Password_Manager\">master password <\/a>to encrypt them. In chrome, the only option for storing password is localStorage, which is unencrypted.<\/p>\n<h4>Different way to get the current window information<\/h4>\n<p>my project needs to know the URL of the current window so it can bookmark it. The way to access this information is different in each browser.<\/p>\n<p>Firefox:<\/p>\n<pre>var info={url:getWebNavigation().currentURI.spec,\n  title: getWebNavigation().document.title}<\/pre>\n<div>In chrome the method is asynchronous, and requires additional permissions in the chrome.manifest:<\/div>\n<pre>        chrome.tabs.getSelected(null, function _getWinInfo(tab){\n                var info = {\n                        url:tab.url,\n                        title:tab.title\n                };\n            });<\/pre>\n<h4>Different logging<\/h4>\n<p>My project has a bunch of built in logging. Much is for diagnostic purposes, but some is for important errors. For the most important errors <a href=\"https:\/\/developer.mozilla.org\/en\/Components.utils.reportError\">Components.utils.reportError<\/a> is used. This reports the error to the built in Firefox <a href=\"https:\/\/developer.mozilla.org\/en\/error_console\">Error Console<\/a>. It&#8217;s possible to report other errors to this console, but it&#8217;s <a href=\"https:\/\/developer.mozilla.org\/en\/Console_service\">more complicated<\/a>.<\/p>\n<p>The rest of logging in my project is provided by a home-grown logging service. Extensions in Firefox can write to disk, so that&#8217;s what the project&#8217;s logging service does. Chrome doesn&#8217;t allow extensions to write to disk. It does have a console object however, that can be used for logging at various levels (a la firebug).<\/p>\n<p>To prevent having to change a bunch of code, I created a bridge to reportError:<\/p>\n<pre>\/\/Fake out the report error method so we can still use it in code\n\n    Components = {\n            utils:console\n    }\n    Components.utils.reportError=console.error;<\/pre>\n<h4>Different system for localization<\/h4>\n<p>Chrome&#8217;s localization system sucks.\u00a0 The FF version isn&#8217;t great either, but I really hate the chrome one.\u00a0 In FF you have two different ways to localize strings &#8211; in XUL, you can use <a href=\"https:\/\/developer.mozilla.org\/en\/XUL_Tutorial\/Localization\">DTDs<\/a>.\u00a0 This is a very strange use of DTD, but in practice it&#8217;s pretty straightforward.\u00a0 In your XUL, you reference some string with an entity reference like <b>&amp;confirmButtonLabel;<\/b>.\u00a0 In your DTD you will have an entry like so:<\/p>\n<div>&lt;!ENTITY confirmButtonLabel &#8220;Do It!&#8221;&gt;<\/div>\n<div><\/div>\n<div>\n<p>The other method is through javascript, using <a href=\"https:\/\/developer.mozilla.org\/en\/XUL_Tutorial\/Property_Files\">stringbundles<\/a>.\u00a0 You create a .properties file with strings (similar to java), get reference to the bundle, and then call<\/p>\n<pre>somebundle.getString(\"somekey\")<\/pre>\n<div>You can also call <code class=\"plain\">getFormattedString <\/code>to fill in placeholders in a string.<\/div>\n<div><\/div>\n<div>\n<p>In chrome, there is only one <a href=\"http:\/\/code.google.com\/chrome\/extensions\/i18n.html\">localization system<\/a>.\u00a0 You create a weird JSON formatted messages.json for each language, and pull strings from that file.\u00a0 You get a string by calling<\/p>\n<pre>chrome.i18n.getMessage(\"somekey\")<\/pre>\n<div>The reason I say this sucks is that there&#8217;s no way to automatically substitute strings in an HTML file.\u00a0 You have to do it all with script.\u00a0 If your popup is just some fixed HTML, you have to figure out your own substitution system.\u00a0 This is annoying, and a feature sorely lacking from chrome.\u00a0 The messages.json format is also weird, and there&#8217;s no existing tools that I could find to work with it.<\/div>\n<\/div>\n<\/div>\n<h4>No Prompt Service<\/h4>\n<p>Firefox has the <a href=\"https:\/\/developer.mozilla.org\/en\/nsIPromptService\">nsIPromptService<\/a> which makes simple dialogs easy.\u00a0 You can crate things from a simple <a href=\"https:\/\/developer.mozilla.org\/en\/nsIPromptService#section_34\">alert<\/a> (with control of the title) to a more complex dialog with <a href=\"https:\/\/developer.mozilla.org\/en\/nsIPromptService#section_38\">multiple custom labeled buttons<\/a>.\u00a0 I haven&#8217;t ported the functionality needed to do this just yet, but when I do, I will probably use jQuery UI.<\/p>\n<h4>No Built In Widgets<\/h4>\n<div>Firefox has all kinds of built in widgets.\u00a0 The main one I was missing was a <a href=\"https:\/\/developer.mozilla.org\/En\/XUL\/Textbox_%28Toolkit_autocomplete%29\">typeahead <\/a>and <a href=\"https:\/\/developer.mozilla.org\/en\/XUL\/Attribute\/textbox.type\">search textbox<\/a>. I used <a href=\"http:\/\/jqueryui.com\/\">jQuery UI<\/a> for the typeahead, and wrote a custom search textbox to emulate the behavior of the FF version.<\/div>\n<h4>getElementsByTagName is not scoped to the default namespace<\/h4>\n<\/div>\n<\/div>\n<div dir=\"ltr\">In Firefox, when dealing with a namespaced document (like an atom feed), doing <span style=\"font-weight: bold;\">feed.getElementsByTagName<\/span> is limited to the default namespace of the document. In chrome, it looks in all the namepsaces. This is a problem, because in dogear feeds there are two link elements. They&#8217;re not really the same element, because they&#8217;re in different namepsaces, but apparently that doesn&#8217;t matter to chrome.<\/div>\n<div dir=\"ltr\">\n<pre id=\"line1\">&lt;link href=\"http:\/\/signature.innovate.ibm.com\/index\" \/&gt;\n&lt;snx:link linkid=\"9a18b409-3188-41be-a87c-815d4de784ec\"\/&gt;<\/pre>\n<div>To be fair, the dom spec doesn&#8217;t say which way browsers should implement this method. I can&#8217;t really think of an instance where the chrome behavior would be useful. While both those things above are in a tag named link, they have completely different meanings. That&#8217;s the whole reason for having namespaces in the first place.<\/div>\n<div>\n<p>Fortunately the solution isn&#8217;t that difficult, you just have to call <span style=\"font-weight: bold;\">getElementsByTagNameNS<\/span>, passing in the default atom namespace. It&#8217;s an annoying thing to have to change, however.<\/p>\n<h4>Less tolerance for twice defined variables<\/h4>\n<div>Another problem I quickly encountered was issues with variables defined twice. Javascript only has two levels of scope, function or local scope, and global scope (JS 1.7 now has <a href=\"https:\/\/developer.mozilla.org\/en\/JavaScript\/New_in_JavaScript\/1.7#Block_scope_with_let_%28Merge_into_let_Statement%29\">block level scope<\/a>, but never you mind that). No mater how nested it might be, once a variable is defined in a function, it exists throughout the entire function. This means that it&#8217;s actually wrong to declare it again (though you&#8217;ll get no error if you do so). Firefox and Chrome behave differently if you do so. Here&#8217;s an example of an issue I had<\/div>\n<pre>if(someCondition){\n    var something=\"xyz\";\n}else{\n    var something=\"123\";\n}\nalert(something);<\/pre>\n<div>\n<p>In Firefox, if <span style=\"font-weight: bold;\">someCondition <\/span>is <span style=\"font-weight: bold;\">true<\/span>, the result is the alert will display &#8220;xyz&#8221;. This is valid because once <span style=\"font-weight: bold;\">something<\/span> is defined, it&#8217;ll exist throughout the function.<\/p>\n<p>In chrome, the value of <span style=\"font-weight: bold;\">something<\/span> ended up being <span style=\"font-weight: bold;\">undefined<\/span> (actually, if you run this example, chrome will say xyz. Mine must have been more specific, but was similar in concept). The reason wasn&#8217;t clear until I looked in <span style=\"text-decoration: line-through;\">fireb <\/span>Developer Tools. What was happening is <span style=\"font-style: italic;\">two<\/span> <span style=\"font-weight: bold;\">something<\/span> variables were being defined, and chrome decided to use the second, uninitialized one. One way to fix this is to remove the second var:<\/p>\n<\/div>\n<pre>if(someCondition){\n    var something=\"xyz\";\n}else{\n    something=\"123\";\n}\nalert(something);<\/pre>\n<p>alert(something);but this makes the Java\/C++ developer in me cringe. Instead, I did a more proper looking:<\/p>\n<pre>var something;\nif(someCondition){\n    something=\"xyz\";\n}else{\n    something=\"123\";\n}\n\nalert(something);<\/pre>\n<div>(Note I couldn&#8217;t actually come up with a sample that replicates this problem &#8212; maybe it was really another issue and I just thought this was the issue.)<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This entry was written during my time at IBM for a Firefox extension I had developed related to bookmarks I&#8217;ve been using Google Chrome more often lately. I still prefer Firefox in a lot of ways, but you&#8230; <a class=\"read-more\" href=\"https:\/\/alexrock.com\/blog\/archives\/82-differences-between-firefox-and-chrome-extensions.html\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-82","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/posts\/82","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/comments?post=82"}],"version-history":[{"count":3,"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/posts\/82\/revisions"}],"predecessor-version":[{"id":85,"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/posts\/82\/revisions\/85"}],"wp:attachment":[{"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/media?parent=82"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/categories?post=82"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alexrock.com\/blog\/wp-json\/wp\/v2\/tags?post=82"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}