WebExtensions/Hacking: Difference between revisions

Add link to WebExtension-specific Try server article
(Add some more skeleton code layout docs)
(Add link to WebExtension-specific Try server article)
 
(15 intermediate revisions by 4 users not shown)
Line 1: Line 1:
The core WebExtension code lives in the same repository as the Firefox browser. If you've never hacked on Firefox before, there is a [http://areweeveryoneyet.org/onramp/desktop.html quick guide to getting started], which will show you how to check out the code and do your first build.


== Code Style ==
== Code Style ==
Line 19: Line 20:


ESLint will enforce most of these rules.
ESLint will enforce most of these rules.
== Code Guidelines ==
For Chrome APIs we'll support the callback interface to maintain compatibility. For new APIs, not Chrome ones, we'll use the promise interface to all APIs. See the [https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API#Callbacks_and_promises MDN docs] for the difference.


== Checking your code with ESLint ==
== Checking your code with ESLint ==
Line 24: Line 29:
All WebExtension directories in <code>mozilla-central</code> are configured with a set of ESLint rules, which all code is required to pass. Many of these rules help to catch serious errors, such as references to non-existent variables, or a missing trailing comma turning an array literal into an array dereference, so it is extremely important that you check you code against them before it lands.
All WebExtension directories in <code>mozilla-central</code> are configured with a set of ESLint rules, which all code is required to pass. Many of these rules help to catch serious errors, such as references to non-existent variables, or a missing trailing comma turning an array literal into an array dereference, so it is extremely important that you check you code against them before it lands.


The simplest way to check your code is using the <code>mach eslint</code> command. This requires that you have [https://docs.npmjs.com/ NPM] installed (and, if you're on Linux, it may require that you [https://docs.npmjs.com/getting-started/fixing-npm-permissions fix NPM permissions]).
The simplest way to check your code is using the <code>mach eslint</code> command. This requires that you have [https://docs.npmjs.com/ NPM] installed.


To setup ESLint, you need to run the following once:
To setup ESLint, you need to run the following once:
Line 52: Line 57:
The following assumes that you use the [https://github.com/VundleVim/Vundle.vim Vundle package manager]. It should be easy enough to adapt to any other package manager you happen to prefer, though.
The following assumes that you use the [https://github.com/VundleVim/Vundle.vim Vundle package manager]. It should be easy enough to adapt to any other package manager you happen to prefer, though.


You should configure Syntastic roughly as follows:
<code>mach eslint --setup</code> installs a specific ESLint version and some ESLint plugins to a subdirectory of the repository ([https://bugzilla.mozilla.org/show_bug.cgi?id=1305023 changed in Firefox 55]).
You should configure Syntastic roughly as follows (change <code>/path/to/mozilla-central</code> as needed):


  " Initialize Vundle.
  " Initialize Vundle.
Line 61: Line 67:
  Bundle 'scrooloose/syntastic'
  Bundle 'scrooloose/syntastic'
   
   
  " Enable ESLint in Syntasitc.
  " Enable the specific ESLint checker for files in mozilla-central/ only.
let g:syntastic_javascript_checkers = ['eslint']
  " Enable the HTML plugin, and enable JavaScript linting for HTML files.
  " Enable the HTML plugin, and enable JavaScript linting for HTML files.
  let g:syntastic_javascript_eslint_args = ['--plugin', 'html']
  autocmd FileType javascript,html
let g:syntastic_filetype_map = { "html": "javascript" }
    \ if stridx(expand("%:p"), "/mozilla-central/") != -1 |
    \    let b:syntastic_checkers = ['eslint'] |
    \    let b:syntastic_eslint_exec = '/path/to/mozilla-central/node_modules/.bin/eslint' |
    \    let b:syntastic_html_eslint_args = ['--plugin', 'html'] |
    \ endif


After you've added this to your configuration (and have installed Vundle, if necessary), launch Vim and run:
After you've added this to your configuration (and have installed Vundle, if necessary), launch Vim and run:
Line 99: Line 107:
;xpcshell tests
;xpcshell tests
: These reside under <code>toolkit/components/extensions/test/xpcshell/</code>, and are used to test low-level modules which do not require a browser UI, including those under <code>toolkit/modules/addons/</code>, <code>toolkit/components/utils/simpleServices.js</code>, and various pieces of C++ code.
: These reside under <code>toolkit/components/extensions/test/xpcshell/</code>, and are used to test low-level modules which do not require a browser UI, including those under <code>toolkit/modules/addons/</code>, <code>toolkit/components/utils/simpleServices.js</code>, and various pieces of C++ code.
[[WebExtensions/Try_Server]] has more information about using the try server to test WebExtension code.
=== Test tag ===
All tests in WebExtensions are [https://bugzilla.mozilla.org/show_bug.cgi?id=1296888 now tagged] with the tag: <code>webextensions</code>, so you can pass the <code>--tag</code> argument to <code>mochitest</code>, <code>xpcshell-test</code> and the [http://trychooser.pub.build.mozilla.org/ try server syntax].


=== Code coverage tests ===
=== Code coverage tests ===
Line 113: Line 127:
: This is code coverage for code run in a tab content process, excluding code run only in the main browser process.
: This is code coverage for code run in a tab content process, excluding code run only in the main browser process.


In general, the total code coverage numbers are what we focus on. However, it is extremely important code which is expected to run in both the main browser process and in a content process to be tested in both. If you know that your code falls into this category, please check that it's tested appropriately.
In general, the total code coverage numbers are what we focus on. However, it is extremely important for code which is expected to run in both the main browser process and in a content process to be tested in both. If you know that your code falls into this category, please check that it's tested appropriately.


The above results are generated using [https://people.mozilla.org/~kmaglione/webext-coverage.patch this patch], which could generously be described as a fairly gross hack. If you'd like to run the tests yourself, you can do so with something like the following:
The above results are generated using [https://people.mozilla.org/~kmaglione/webext-coverage.patch this patch], which could generously be described as a fairly gross hack. If you'd like to run the tests yourself, you can do so with something like the following:


  # Install the Instanbul code coverage tool
  # Install the Istanbul code coverage tool
  npm install istanbul
  npm install -g istanbul


  # Apply the code coverage patch
  # Apply the code coverage patch
Line 125: Line 139:
  # Instrument all WebExtension code, run the various test suites, and
  # Instrument all WebExtension code, run the various test suites, and
  # generate the coverage output files.
  # generate the coverage output files.
# Make sure that $OBJDIR points to the objdir of your current build.
  ./toolkit/components/extensions/test_coverage.sh
  ./toolkit/components/extensions/test_coverage.sh $OBJDIR


== Code layout ==
== Code layout ==
Line 159: Line 172:
Each API module must be explicitly registered, in order to be loaded. It must also register a schema if it exports any APIs to extensions.
Each API module must be explicitly registered, in order to be loaded. It must also register a schema if it exports any APIs to extensions.


Generic APIs are registered in <code>Extension.jsm</code> as follows:
Starting from Firefox 50 ([https://bugzilla.mozilla.org/1285063 Bug 1285063], [https://hg.mozilla.org/mozilla-central/rev/e9ca8dc4b42e hg commit e9ca8dc4b42e]) all the APIs schema and <code>ext-*.js</code> files must be registered to the category manager through one of the following manifest files:
 
* [https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/extensions-toolkit.manifest toolkit/components/extensions/extensions-toolkit.manifest], for Generic APIs registered at toolkit level
* [https://dxr.mozilla.org/mozilla-central/source/browser/components/extensions/extensions-browser.manifest browser/components/extensions/extensions-browser.manifest], for Firefox desktop APIs
* [https://dxr.mozilla.org/mozilla-central/source/mobile/android/components/extensions/extensions-mobile.manifest mobile/android/components/extensions/extensions-mobile.manifest], for Firefox for Android APIs
 
As an example, here is a snippet of the <code>extension-toolkit.manifest</code>:
# scripts
category webextension-scripts alarms chrome://extensions/content/ext-alarms.js
...
# schemas
category webextension-schemas alarms chrome://extensions/content/schemas/alarms.json
 
In previous Firefox versions, schemas and <code>ext-*.js</code> files were statically
registered through <code>Extension.jsm</code> and <code>nsBrowserGlue.js</code> source
files:
 
Generic APIs were registered in <code>Extension.jsm</code> as follows:


  ExtensionManagement.registerScript("chrome://extensions/content/ext-foobar.js");
  ExtensionManagement.registerScript("chrome://extensions/content/ext-foobar.js");
Line 165: Line 197:
  ExtensionManagement.registerSchema("chrome://extensions/content/schemas/foobar.json");
  ExtensionManagement.registerSchema("chrome://extensions/content/schemas/foobar.json");


Firefox desktop APIs are registered in [https://dxr.mozilla.org/mozilla-central/source/browser/components/nsBrowserGlue.js nsBrowserGlue.js]:
Firefox desktop APIs were registered in [https://dxr.mozilla.org/mozilla-central/source/browser/components/nsBrowserGlue.js nsBrowserGlue.js]:


  ExtensionManagement.registerScript("chrome://browser/content/ext-bazquux.js");
  ExtensionManagement.registerScript("chrome://browser/content/ext-bazquux.js");
   
   
  ExtensionManagement.registerSchema("chrome://browser/content/schemas/bazquux.json");
  ExtensionManagement.registerSchema("chrome://browser/content/schemas/bazquux.json");
=== Permission strings ===
The strings for permissions can be found in [https://dxr.mozilla.org/mozilla-central/source/browser/locales/en-US/chrome/browser/browser.properties browser.properties].
If you add an API that requires permissions, then you'll need to make sure the corresponding permission strings are also landed.
47

edits