Building Add-ons with Jetpack, Flightdeck and… Vim.

AddonEditor is an add-on for Firefox that allows you to use an external editor when building add-ons with the Add-ons Builder (aka Flightdeck). Yeah, say that 10 times fast.

While Skywriter (aka Bespin) is nice, it’s just not [insert your favorite editor here]. So I stole the code from the Ubiquity project for loading an external app as editor, and converted it to a CommonJS module for Jetpack (which I’ve listed on the Jetpack Modules page). I built an add-on using Jetpack’s page-mod module to add buttons to the Add-on Builder for loading a file in an external editor:

When you click the button the first time, you’re prompted with a file-open dialog. Select the editor application of your choice, and the file will open in it. From then on, your chosen editor will automatically load files when you click the button. To clear your choice, choose the other button.

Install AddonEditor. Requires Firefox 4 Beta 7 or newer.

Clone and make your own, based on AddonEditor. I built it using Jetpack 0.10, which isn’t released yet. However, I don’t think it takes advantage of anything new, so it might be test-able from the Builder. But the Builder is giving errors when I hit the “test” button (which I’ve reported to Zalun), so I can’t tell for sure yet.

BEWARE:

  • I’ve only tested on Linux. Let me know in the comments if it works or doesn’t for you.
  • Terminal apps not liked, apparently: /usr/bin/vim hangs Firefox completely. /usr/bin/gvim works fine.
  • The UI augmentation to Flightdeck probably made Zalun puke. It should probably just be an option in the context menu or something. Except that you’d never find it. Ideas?

Firefox, Plugins and Jetpack Widgets

Flash was chewing CPU in one of my myriad tabs, so I used Jetpack and the new AddonsManager API to whip up a quick add-on to enable and disable Flash quickly. It’s <30 lines of code and an image. It puts an icon in the Firefox 4 add-on bar that toggles the plug-in, and sends a Growl notification (or whatever system your OS uses) indicating that the plug-in was successfully enabled or disabled. Screenshot:

Install FlashToggle. Requires Firefox 4 beta 7 or newer.

Clone and make your own on the Add-on Builder. This might require a minor change in the code since I built using Jetpack 0.10, which isn’t released yet. Changing ‘contentURL’ to ‘image’ in the widget options should do the trick.

The entire code listing:

function toggleFlash(callback) {
  const { Cu } = require("chrome");
  Cu.import("resource://gre/modules/AddonManager.jsm", this);
  AddonManager.getAddonsByTypes(["plugin"], function(addons) {
    for (let i = 0; i < addons.length; i++) {
      if (addons[i].name == "Shockwave Flash") {
        addons[i].userDisabled = !addons[i].userDisabled;
        callback(addons[i].userDisabled);
        break;
      }
    }
  });
}

let flashLogoURL = require("self").data.url("flash-logo.jpg");
require("widget").Widget({
  label: "Toggle Flash",
  contentURL: flashLogoURL,
  onClick: function() {
    toggleFlash(function(disabled) {
      let message = "Flash is now " + (disabled ? "disabled" : "enabled") + ".";
      require("notifications").notify({
        title: message,
        iconURL: flashLogoURL
      });
    });
  }
});

Upcoming changes to the Jetpack Widget API

Between bug 612169 and bug 569479, the widget API has undergone a major transformation in the upcoming 0.10 SDK release.

Both sets of changes have made the API more compact, reducing the amount of code required to build widgets. The Electrolysis (e10s) changes are in preparation for moving Jetpack code out of the main Firefox process. They also make the widget API significantly more powerful, combining the current widget functionality with content scripts.

The e10s changes have affected the API to a significant degree; your widgets will certainly require more than just cosmetic changes.  I was worried at first that the e10s changes would complicate things, causing more verbose code patterns, and tricky message sequences to wire things together. However, the opposite was true: The documentation examples and the automated test code were both *more compact* and *simpler* after I’d rewritten them to use the new API.

Here’s an example widget that shows the Facebook profile pic of the most recent friend in your news feed:

require("widget").Widget({
  label: "Latest Friend",
  contentURL: "https://www.facebook.com/home.php",
  contentScript: "document.location = document.querySelector('.profilePic').src;",
  contentScriptWhen: "ready",
  onClick: function() require("tabs").tabs.active.location = this.contentURL
});

Hmmm, with the page-worker module, querySelectorAll and some hot timer action, you could have a Rockmelt-y bar…

A summary of the API changes:

  • You no longer need to explicitly add and remove widgets.
  • Constructing a widget immediately adds it to the add-on bar. To remove a widget, call its destroy() method.
  • The image property has been removed. Instead use the contentURL property, which can be used with image URLs, or local or remote content URLs. The content property is still present, used for HTML fragments or plain text.
  • The API now exposes the page-mod API set – meaning that you can attach a content script either inline via contentScript, or a separate file via contentScriptURL, and specify whether it runs at load or when the DOM is ready via contentScriptWhen.
  • The onLoad and onReady event listeners have been removed in favor of content scripts, where you can listen for those events, and post messages back to your Jetpack code. The examples in the docs show how easy this is.

For more details, check out the updated widget API documentation.


Jetpacking: The 0.3 SDK and a peek at what’s coming next.

I’ve been working on the Jetpack project for about a month now – implementing features, fixing bugs, and generally helping move things forward as we build out the wide set of capabilities needed to enable an *awesome* future for Firefox add-on development.

The Jetpack team released the 0.3 version of the SDK yesterday, which has a bunch of platform improvements, and also the context menu API – the first UI feature to ship in the SDK. The SDK documentation has an example of using this feature that shows 1) how easy it is to build UI features with Jetpack, but also 2) shows how add-on development process has *changed* with the SDK. For example, all of the manual packaging steps are *gone*. That’s right. No more crazy directory structures, no more RDF files, no more GUIDs. All of that stuff is gone, replaced with a couple of simple commands. It’s not perfect yet, but expect it to get even easier to both package and deploy add-ons as we build out the SDK further.

So what’s next? The 0.4 release is where the feature set of the SDK really starts to blow up:

  • Panels: Floating rich content, tooltips, contextual UI.
  • Private Browsing: Making it easy for add-ons to respect your privacy.
  • Selection: Remember how awesome it was having an intuitive selection API in Ubiquity?
  • Localization: Simple access and distribution of locale data.
  • Page Worker: Like a Web Worker, but with more privileges and a DOM.
  • Simple Storage: Persistent object store – like DOMStorage for add-ons.
  • Places: Improved bookmarks and history searching and browsing.
  • Widgets: A preview of the ideas Daniel and Boriss have recently blogged about.
  • Request: Even easier AJAX (Please don’t make that into an acronym. Please.)
  • Installable without needing to restart Firefox (trunk builds only).
  • Documentation: More and better!

And it’s not just about the feature set: The diligent focus of the Jetpack core team on developer ergonomics, and the experience gained from the Jetpack prototype and projects like Ubiquity, is resulting in a set of APIs that are far more intuitive and easy to use than the current XPCOM-riddled minefield that add-on developers have to deal with today.

If you have questions or suggestions, let me know in the comments, or join us on Jetpack developer forum.


Firefox Performance Update

I’ve been focusing more on Jetpack development this quarter, but will still be posting performance round-ups regularly here. In fact, here’s one now:

  • Taras Glek continues to blog his progress on improving the binaries we ship, talking about how reordering binaries improves memory use as well as load time, leveraging GCC’s PGO for fast startup, and finally about Icegrind, his Valgrind plugin that generates a log of the order of access to mmap’d files.
  • Are we fast yet?! The answer to that question, at least in regards to JavaScript performance test suites, can be found at AreWeFastYet.com, where you’ll see graphs that show Firefox trunk’s performance relative to Google’s V8 and Apple’s Nitro on the Sunspider and V8Bench tests. I won’t spoil the answer for you, you’ll have to go check it out for yourself.
  • I finished and checked-in my changes to the Tinderbox Pushlog, adding a new feature that provides at-a-glance comparison in performance test results between any two pushes on the page (screenshot). It will go live next time Marcus pushes changes out to his server. But he’s not online at the moment, so I don’t know when this feature will go live. Heh, it went live moments after I published this post.
  • Heather Arthur and Clint Talbert are working on a project to add performance data to Addons.mozilla.org for extensions. They’re starting with the effect of a given extension on Firefox startup time. Follow along on the bug, or watch project Dirty Harry on Github.
  • Improving the AMO extension validator: AMO scans uploaded extensions and reports problems to the authors. For performance best-practices, we should at least warn the authors if possible if their add-on is doing something that’ll make Firefox slow. This bug is for warning about add-ons that don’t have their content in a JAR file. If you see any thing in the best practices guide that can be statically detected, please file a bug for it here.

If you have any other performance-related bugs, blog posts, anecdotes or other tomfoolery, post it in the comments!


Firefox Performance Update

As I mentioned in my previous update, the scope of these updates has expanded beyond start-up time. That said, I can’t keep track of everything! So if you have an update, email it to me if you want it in the post, or just add it in the comments.

  • First, I just have to say that Marco’s fix for bug 542943 has changed the way I think about browser restarts, removing the fear entirely. It turns out that, for me anyway, the majority of the slowness involved in restarting was waiting for the process to exit. After Marco’s landing, it’s nearly instantaneous.
  • While I was away, Taras blogged nearly daily about his findings while working on Linux code locality. He first posted a graph of I/O from library loading, then a long post about why library loading sucks on Linux, followed by some findings regarding madvise and prelink, finally posting about linker inefficiencies and SuSE’s workaround.
  • Mike Wu and others are moving forward on the “omnijar” project, which moves most of the core application files into a single JAR file. Taras described it as “extreme filesystem makeover”, and found ~10% start-up improvement with this approach on the desktop.
  • Clint Talbert and Heather Arthur are beginning work on a project that measures add-on performance, that will hook into AMO to show developers how their add-ons perform.
  • Drew Willcoxon got r+ on bug 536893 to allow asynchronous opening of Places query results. Once we start using the feature, expect bookmark and history UI to get snappier!
  • Taras got review on bug 516085, which consolidates access to core services that currently accessed hundreds of thousands of times during a browsing session.
  • A bunch of people have added tips to the add-on performance “best practices” document. I’ll be cleaning it up and moving it to MDC soon.
  • While the tinderbox pushlog is fantastic for viewing per-checkin results, and a broader view of tree activity, it doesn’t provide any facility for comparing the results of performance tests between landings. So I spent some time this week writing an addition that allows you to select any two pushes, and view a comparison table showing the difference in performance across all tests on all operating systems for those revisions. I’ll clean it up, and try to get it deployed, but regardless will make it available as a Jetpack or Greasemonkey script sometime next week.

For more info:

  • Startup performance activity is tracked here.
  • Add-on performance efforts are being tracked on this page.
  • Weekly performance results for all measurements are available on the snapshot, and trends available on the dashboard.

Firefox Performance Report, Startup and Otherwise – March 19, 2010

A couple of notices: First, I’m going to start including various performance-related items in these posts that aren’t purely about startup time. There’s a whole bunch of activity happening that isn’t really rolled up anywhere, so it might as well be here. Second, I’ll be out on vacation in Florida next week, so there will not be a status update.

  • Last week I forgot to add that Marco Bonardo landed bug 542943, which removed a hash of all bookmarks that stayed resident for the lifetime of the application. This resulted in a 97% improvement in shutdown time for our test of a very large bookmarks+history collection.
  • Ted’s taken over the static build project, and has new patches up.
  • Taras is working on Linux code locality via a Valgrind plugin he’s writing, with help from those folks.
  • At the platform work week Taras talked to Ehsan, who it turns out had a bunch of ideas for improving startup there. I’ve filed bugs from Ehsan’s notes for better Windows code locality, binding DLL function addresses to the executable, DLL rebasing, and DLL lazy-loading.
  • The add-on performance “best practices” document is getting bigger and better. If you have ideas for improving add-on performance, please add them to the doc!
  • All of our add-on performance efforts are being tracked centrally on this page. If you want to get involved, hop on one of those bugs. If you want to stay updated, “watch” that page and you’ll get emails whenever it’s updated.
  • I’ve updated the main Performance wiki page. The top sections are now up to date. Next I’ll be updating the testing and reference sections, and breaking out the task-specific content and moving it to an updated table of performance activities, like we currently have for startup, addons, etc. When the page is more manageable, I’ll remove the TOC that’s pushing everything below the fold.
  • As usual, the table of active startup performance activity is here.

Firefox Startup Performance March 12, 2010

No update on the ongoing code projects this week. However, we investigated the extension performance work I mentioned last week, and got a conversation going, with posts by Taras, Asa and myself. I’ve listed the various ideas and approaches that came out of those posts and comments here.


Firefox, Extensions and Performance

Extensibility is a double-edged sword. It’s a keystone feature in Firefox – differentiating even now that just about every other browser has some vector for augmentation. However, along with the freedom and power of Firefox extensions comes the ability to slow the browser down. And worse, users and developers have little or no visibility into the causes of poor extension performance.

Not all extensions slow Firefox down. But they can. To prevent that, we need to do three things:

  1. Make it *easy* for extension developers to keep their extensions fast.
  2. Allow users to see the performance effect of their extensions.
  3. Mitigate the effects of badly-behaving extensions in Firefox itself.

For Extension Developers

First, we need to loudly and clearly educate extension developers, and provide them tools. Some ideas:

  • Write an extension performance “best practices” guide on MDC.
  • Build warnings into Firefox, that highlight code that might perform poorly (bug 550242).
  • Provide a try-server that allows extensions to be uploaded and installed into the test profile.
  • Perform automated performance testing of extensions upload to AMO (bug 458990, maybe?)
  • Ensure that Jetpack generates extensions that are models for good behavior.

For Users

Users should be able to make informed choices about the extensions they install, and be able to monitor the effect of extensions on their browsing sessions. We could:

  • Provide performance information for extensions on their pages on AMO.
  • Build a performance dashboard similar to about:memory, but tracking startup time, page-load time, and browser UI behavior such as menu responsiveness. Given a visualization of these things over time, users can see the effects of installing different extensions.

In the Core

There are also things we can do to mitigate poor performance in core Firefox code. This is being discussed in bug 533038.

We’re already working on some of the ideas listed above. Ping me in #startup on irc.mozilla.org if you want to help out. If you have ideas for other ways to improve extension performance, or to communicate back to users and developers, let me know in the comments.


Firefox Startup Performance – March 5, 2010

I spent the week on-site at Mozilla HQ in Mountain View, which was great.