From MozillaWiki
Jump to: navigation, search

Want to work on Firefox Developer Tools? You've come to the right place! If you want more information about contributing, check out our guide for getting involved.

Building, running, updating and rebuilding

First Build

Follow the instructions on how to build Firefox. Roughly:

hg clone
./mach build

For your first build, this should do the trick. If you are going to be building a lot, you may want to set up your .mozconfig file.

First Run

Once you have built Firefox, you can run it with

 $ ./mach run


 $ ./mach run -P development

What is the -P development? It is a flag telling Firefox to use a different profile, named "development" (this name can be anything you want). If it does not exist the first time you run it, Firefox will open a popup and you can create a new profile with the name you passed in. If you don't specify a profile, mach will create a temporary profile in the path <objdir>/tmp/scratch_user.

Once this command runs, you should see a new Firefox window, called "Nightly".

Incremental Builds

Once you've already built Firefox once, if you want to update with the latest changes from the repo, run:

 $ hg pull -u

To build with the latest changes or with your own DevTools changes, you can run:

 $ ./mach build faster

which is much faster than your first build or clobber builds and should only take a few seconds. You can run your build the same way you did before:

 $ ./mach run -P development

If you happen to change any C++ files (which is pretty rare when working on DevTools), you may need a different command for incremental builds:

 $ ./mach build binaries

A full ./mach build will work for any type of change, it just takes longer to run than the incremental options above.

Note that whenever you pull the latest changes from fx-team into your local repository, you may need to "clobber". A "clobber" is similar to a "make clean". You'll know you need to clobber when you get a big error message telling you to do a clobber build after you tried to do an incremental build. To do a clobber build, enter these commands:

 $ ./mach clobber
 $ ./mach build

Artifact builds (or: building faster!)

If you are not going to modify any C/C++ code, you could use artifact builds. This method downloads prebuilt components, and then the build process becomes faster.

Essentially, add the following lines to your .mozconfig file:

 # Automatically download and use compiled C++ components:
 ac_add_options --enable-artifact-builds
 # Write build artifacts to:
 mk_add_options MOZ_OBJDIR=./objdir-frontend

And then you can follow the normal build process.

On OSX you might want to use MOZ_OBJDIR=./objdir-frontend.noindex instead. Using the .noindex file extension prevents spotlight from indexing your objdir, which is slow.

For more information on aspects such as technical limitations, read the Artifact Builds page.

Configuring your dev profile

You will want to make a couple of quick changes to the profile you use when running your version of Firefox.

Enable remote debugging and the Browser Toolbox

Open DevTools, and click the "Toolbox Options" gear icon in the top right (the image underneath is outdated). Make sure the following two options are checked:

  • Enable browser chrome and add-on debugging toolboxes
  • Enable remote debugging

These settings allow you to use the browser toolbox to set breakpoints inside of the DevTools code, inspect the DevTools themselves, and let you run the Scratchpad in the Browser environment.

Settings for developer tools - "Enable Chrome Debugging" and "Enable Remote Debugging"

You might also want to change the following preference in about:config to false:

  • devtools.debugger.prompt-connection

This will get rid of the prompt displayed every time you open the browser toolbox.

Enabling DevTools Logging

Depending on what you are working on, you may want to make some changes to your profile to enable more logging. If you type about:config in the URL bar, click through the warning page, and search for devtools you can see some of them.

Add the global "dump" function to all windows which logs strings to stdout.

 browser.dom.window.dump.enabled = true

Dumps all packets sent over the remote debugging protocol to stdout (requires browser.dom.window.dump.enabled):

 devtools.debugger.log = true

Log every event notification from the EventEmitter class (devtools/shared/event-emitter.js) (requires browser.dom.window.dump.enabled)

 devtools.dump.emit = true

Restart the browser to apply configuration changes.

You may also be interested in the remote protocol inspector add-on:

Enabling DevTools Assertions

Highly recommended for DevTools hackers!

Add this to your .mozconfig:

 ac_add_options --enable-debug-js-modules

Assert your own invariants like this:

 const { assert } = require("devtools/shared/DevToolsUtils");
 // ...
 assert(1 + 1 === 2, "I really hope this is true...");

When assertions are enabled, assertion failures are fatal, log console warnings, and throw errors.

When assertions are not enabled, the assert function is a no-op.

It also enables the "debug" builds of certain third party libraries, such as React.

Developer Tools Directories Overview

  • devtools/shared: Code shared by both the DevTools client (front-end UI) and server. If we are using any third party libraries, or importing external repositories into our tree, those libraries generally live here (eg, devtools/shared/acorn), assuming they are used by both client and server.
    • devtools/shared/client: Code for the DevTools Remote Debugging Protocol client. (You may wonder why this is not in devtools/client below: it's mainly because tests in server also need access to the RDP client.)
    • devtools/shared/locales: Strings used in either the DevTools server only, or shared with both the client and server
  • devtools/server: Code for the DevTools Remote Debugging Protocol server and transport layer.
  • devtools/client: Front end user interfaces for our tools. Should be pretty obvious what is what based on the directory names and each panel we have in our toolbox. This directory is only shipped with desktop Firefox, as opposed to other directories above, which are shipped with all Gecko products (Firefox OS, Firefox for Android, etc.)
    • devtools/client/locales: Strings used in the DevTools client (front-end UI)
    • devtools/client/themes: CSS and images used in the DevTools client (front-end UI)

Various DevTools resource types

JavaScript Modules

Build Configuration

JavaScript modules are installed by our build system using files. If you add a new JavaScript module, you'll need to update (or add) one of these files to make the build system aware of your new module. See the example below.

A file must live in the same directory as the files to be installed. Don't list files from a subdirectory in a from a parent directory.

Following these steps ensures that require() and resource:// paths map directly to locations in the source tree, instead of being totally arbitrary.


  • File: /devtools/server/actors/layout.js
  • In /devtools/server/actors/


Most DevTools JS code is in the form of CommonJS modules that loaded with require().

To require() a file, the module ID is exactly its source tree path.


  • File: /devtools/server/actors/layout.js
  • Usage (prefer lazy in most cases):
    • loader.lazyRequireGetter(this, "layout", "devtools/server/actors/layout")
    • require("devtools/server/actors/layout")


Some older DevTools JS modules use the Gecko "JavaScript code module" format with the file extension .jsm. We are trying to move away from this format, so it's unlikely you would add a new one, but you might need to import an existing one in your code.

These modules are loaded using Cu.import(). To import() a file, you provide a resource:// URL, which is exactly the source tree path.

In more detail:

  • /devtools/client/<X>: resource://devtools/client/<X>
  • /devtools/server/<X>: resource://devtools/server/<X>
  • /devtools/shared/<X>: resource://devtools/shared/<X>


  • File: /devtools/shared/Loader.jsm
  • Usage:
    • Cu.import("resource://devtools/shared/Loader.jsm")


  • File: /devtools/client/framework/gDevTools.jsm
  • Usage (prefer lazy in most cases):
    • loader.lazyImporter(this, "gDevTools", "resource://devtools/client/framework/gDevTools.jsm")
    • Cu.import("resource://devtools/client/framework/gDevTools.jsm")

Chrome Content

Much of the DevTools front-end / UI is currently loaded using chrome:// URLs, which allow those files to have privileged access to platform internals.

This is typically used to load XUL, HTML, and JS files in the UI.

Note: "Chrome" here means "browser chrome", as in the UI, and bears no relation to "Chrome" as in the browser. We'd like to move away from this on DevTools and be more like regular web sites, but most tools are using chrome:// URLs for now.


If you add a new file that should be loaded via a chrome:// URL, you need to update a manifest file at /devtools/client/ so that it's packaged correctly.

Please ensure that any new files are added so their entire source tree path is part of the URL. To do so, the entry should look like:

   content/<X> (<X>)

where <X> is the path to your file after removing the /devtools/client/ prefix.


  • File: /devtools/client/webaudioeditor/models.js
  • Entry: content/webaudioeditor/models.js (webaudioeditor/models.js)


Chrome content URLs almost match their source tree path, with one difference: the segment client is replaced by content. This is a requirement of the chrome:// protocol handler.


  • File: /devtools/client/webaudioeditor/models.js
  • Usage: chrome://devtools/content/webaudioeditor/models.js

For files within a single tool, consider relative URLs. They're shorter!

Chrome Themes

Similar to the chrome content section above, we also use chrome themes (or skin URLs) in the DevTools UI. These are typically used to load CSS and images.


If you add a new file that should be loaded via chrome:// (such as a new CSS file for a tool UI), you need to update a manifest file at /devtools/client/ so that it's packaged correctly.

Please ensure that any new files are added so their entire source tree path is part of the URL. To do so, the entry should look like:

   skin/<X> (themes/<X>)

where <X> is the path to your file after removing the /devtools/client/themes/ prefix.


  • File: /devtools/client/themes/images/add.svg
  • Entry: skin/images/add.svg (themes/images/add.svg)


Chrome theme URLs almost match their source tree path, with one difference: the segment client/themes is replaced by skin. This is a requirement of the chrome:// protocol handler.


  • File: /devtools/client/themes/images/add.svg
  • Usage: chrome://devtools/skin/images/add.svg

Localization (l10n)

Similar to the other chrome sections above, we also use locale URLs in the DevTools UI to load localized strings. This section applies to *.dtd (for use as entities within XUL / XHTML files) and *.properties (for use via runtime APIs) files.

We currently have two sets of localized files:

  • devtools/client/locales: Strings used in the DevTools client (front-end UI)
  • devtools/shared/locales: Strings used in either the DevTools server only, or shared with both the client and server


If you add a new l10n file (such as a new *.dtd or *.properties file), there should not be any additional packaging steps to perform, assuming the new file is placed in either of the 2 directories mentioned above. Each one contains a which uses wildcards to package all files in the directory by default.


Locale URLs differ somewhat based on whether they are in client or shared. While we would have preferred them to match the source tree path, the requirements of the chrome:// protocol don't make that easy to do.


  • File: /devtools/client/locales/en-US/debugger.dtd
  • Usage: chrome://devtools/locale/debugger.dtd


  • File: /devtools/shared/locales/en-US/
  • Usage: chrome://devtools-shared/locale/


Localization files should follow a set of guidelines aimed at making it easier for people to translate the labels in these files in many languages.

Find these guidelines on MDN.

In particular, it's important to write self-explanatory comments for new keys, deleting unused keys, changing the key name when changing the meaning of a string, and more. So make sure you read through these guidelines should you have to modify a localization file in your patch.

DevTools Automated Tests

We use three suites of tests:

  • xpcshell: Unit-test style of tests. No browser window, just a JavaScript shell. Mostly testing APIs directly.
  • mochitest-chrome: Unit-test style of tests, but with a browser window. Mostly testing APIs that interact with the DOM directly.
  • mochitest-devtools: Integration style of tests. Fires up a whole browser window with every test and you can test clicking on buttons, etc.

More information about the different types of tests can be found on the MDN automated testing page

Running DevTools Tests

To run all DevTools tests, regardless of suite type:

 $ ./mach test devtools/*

The following sections show more specific commands for running only a single suite or single test in a suite.

xpcshell Tests

To run all of the xpcshell tests:

 $ ./mach xpcshell-test --tag devtools

To run a specific xpcshell test:

 $ ./mach xpcshell-test devtools/path/to/the/test_you_want_to_run.js

Chrome Mochitests

To run the whole suite of chrome mochitests for DevTools:

 $ ./mach mochitest -f chrome --tag devtools

To run a specific chrome mochitest:

 $ ./mach mochitest devtools/path/to/the/test_you_want_to_run.html

DevTools Mochitests

To run the whole suite of browser mochitests for DevTools (sit back and relax):

 $ ./mach mochitest --subsuite devtools --tag devtools

To run a specific tool's suite of browser mochitests:

 $ ./mach mochitest devtools/client/<tool>

For example, run all of the debugger browser mochitests:

 $ ./mach mochitest devtools/client/debugger

To run a specific DevTools mochitest:

 $ ./mach mochitest devtools/client/path/to/the/test_you_want_to_run.js

Note that the mochitests must have focus while running.

Writing Tests

When working on a patch for DevTools, there's almost never a reason not to add a new test. If you are fixing a bug, you probably should write a new test to prevent this bug from occurring again. If you're implementing a new feature, you probably should write many new tests to cover the various aspects of this new feature.

You should ask yourself:

  • Are there enough tests for my patch?
  • Are they the right types of tests?

To help with writing nice, maintainable and consistent DevTools mochitests, please follow our DevTools mochitests coding guide.

Debugging Intermittent Test Failures

When a test fails sometimes, but not always, it is called an "intermittent". Handling these is complicated enough that we have a separate page with tips on debugging.

Finding documentation

If you read through the source code about something you do not know about, you may find documentation here:

We recommend adding a smart keyword search for DXR and MDN. If you still have questions, ask us on IRC or leave a comment on the Bugzilla ticket.

Making and Submitting a Patch

Before you make any changes, read the documentation on how to use Mozilla's version control.

Before you submit a patch, you should read our Coding Standards and run ESLint to validate your code changes (to avoid loosing time during code reviews with formatting details for instance). In general, try to be File Consistent. For new files, follow the standards.

Once you have a patch file, add it as an attachment to the Bugzilla ticket you are working on and add the feedback? or review? flag depending on if you just want feedback and confirmation you're doing the right thing or if you think the patch is ready to land respectively. Read more about how to submit a patch and the Bugzilla review cycle here.

You can also take a look at the DevTools/Code Review Checklist as it contains a list of checks that your reviewer is likely to go over when reviewing your code.

Coding Standards

DevTools has some coding standards that your changes should follow:

Potential Pitfalls

Today there are a few techniques and conventions we use that can be confusing, especially when you first start working with the code base. We hope to improve these with time to make things easier for everyone, but for now this etherpad might be a helpful set of notes if you are having trouble. If you find new pitfalls that aren't listed there, feel free to add your own entries, so we know to address them. Also, please come talk to us in #devtools on IRC, as that might be the fastest path to solving the issue.