CINXE.COM

WebExtensions/Hacking - MozillaWiki

<!DOCTYPE html> <html class="client-nojs" lang="en" dir="ltr"> <head> <meta charset="UTF-8"/> <title>WebExtensions/Hacking - MozillaWiki</title> <script>document.documentElement.className="client-js";RLCONF={"wgBreakFrames":false,"wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgDefaultDateFormat":"dmy","wgMonthNames":["","January","February","March","April","May","June","July","August","September","October","November","December"],"wgRequestId":"f6d588f9a95fd97999303856","wgCSPNonce":false,"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"WebExtensions/Hacking","wgTitle":"WebExtensions/Hacking","wgCurRevisionId":1204588,"wgRevisionId":1204588,"wgArticleId":242670,"wgIsArticle":true,"wgIsRedirect":false,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":[],"wgPageContentLanguage":"en","wgPageContentModel":"wikitext","wgRelevantPageName":"WebExtensions/Hacking","wgRelevantArticleId":242670,"wgIsProbablyEditable":false,"wgRelevantPageIsProbablyEditable":false,"wgRestrictionEdit":[],"wgRestrictionMove":[],"wgPageFormsTargetName":null, "wgPageFormsAutocompleteValues":[],"wgPageFormsAutocompleteOnAllChars":false,"wgPageFormsFieldProperties":[],"wgPageFormsCargoFields":[],"wgPageFormsDependentFields":[],"wgPageFormsCalendarValues":[],"wgPageFormsCalendarParams":[],"wgPageFormsCalendarHTML":null,"wgPageFormsGridValues":[],"wgPageFormsGridParams":[],"wgPageFormsContLangYes":null,"wgPageFormsContLangNo":null,"wgPageFormsContLangMonths":[],"wgPageFormsHeightForMinimizingInstances":800,"wgPageFormsShowOnSelect":[],"wgPageFormsScriptPath":"/extensions/PageForms","edgValues":null,"wgPageFormsEDSettings":null,"wgAmericanDates":false,"wgMFDisplayWikibaseDescriptions":{"search":false,"nearby":false,"watchlist":false,"tagline":false},"wgVector2022PreviewPages":[]};RLSTATE={"site.styles":"ready","user.styles":"ready","user":"ready","user.options":"loading","skins.vector.styles.legacy":"ready"};RLPAGEMODULES=["site","mediawiki.page.ready","mediawiki.toc","skins.vector.legacy.js","ext.Bugzilla"];</script> <script>(RLQ=window.RLQ||[]).push(function(){mw.loader.implement("user.options@12s5i",function($,jQuery,require,module){mw.user.tokens.set({"patrolToken":"+\\","watchToken":"+\\","csrfToken":"+\\"});});});</script> <link rel="stylesheet" href="/load.php?lang=en&amp;modules=skins.vector.styles.legacy&amp;only=styles&amp;skin=vector"/> <script async="" src="/load.php?lang=en&amp;modules=startup&amp;only=scripts&amp;raw=1&amp;skin=vector"></script> <meta name="ResourceLoaderDynamicStyles" content=""/> <link rel="stylesheet" href="/load.php?lang=en&amp;modules=site.styles&amp;only=styles&amp;skin=vector"/> <meta name="generator" content="MediaWiki 1.39.10"/> <meta name="format-detection" content="telephone=no"/> <meta name="viewport" content="width=1000"/> <link rel="icon" href="/images/favicon.ico"/> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch_desc.php" title="MozillaWiki (en)"/> <link rel="EditURI" type="application/rsd+xml" href="https://wiki.mozilla.org/api.php?action=rsd"/> <link rel="alternate" type="application/atom+xml" title="MozillaWiki Atom feed" href="/index.php?title=Special:RecentChanges&amp;feed=atom"/> </head> <body class="mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject page-WebExtensions_Hacking rootpage-WebExtensions skin-vector action-view skin-vector-legacy vector-feature-language-in-header-enabled vector-feature-language-in-main-page-header-disabled vector-feature-language-alert-in-sidebar-disabled vector-feature-sticky-header-disabled vector-feature-sticky-header-edit-disabled vector-feature-table-of-contents-disabled vector-feature-visual-enhancement-next-disabled"><div id="mw-page-base" class="noprint"></div> <div id="mw-head-base" class="noprint"></div> <div id="content" class="mw-body" role="main"> <a id="top"></a> <div id="siteNotice"></div> <div class="mw-indicators"> </div> <h1 id="firstHeading" class="firstHeading mw-first-heading"><span class="mw-page-title-main">WebExtensions/Hacking</span></h1> <div id="bodyContent" class="vector-body"> <div id="siteSub" class="noprint">From MozillaWiki</div> <div id="contentSub"><span class="subpages">&lt; <a href="/WebExtensions" title="WebExtensions">WebExtensions</a></span></div> <div id="contentSub2"></div> <div id="jump-to-nav"></div> <a class="mw-jump-link" href="#mw-head">Jump to navigation</a> <a class="mw-jump-link" href="#searchInput">Jump to search</a> <div id="mw-content-text" class="mw-body-content mw-content-ltr" lang="en" dir="ltr"><div class="mw-parser-output"><p>The core WebExtension code lives in the same repository as the Firefox browser. If you've never hacked on Firefox before, there is a <a rel="nofollow" class="external text" href="http://areweeveryoneyet.org/onramp/desktop.html">quick guide to getting started</a>, which will show you how to check out the code and do your first build. </p> <div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading"><input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none" /><div class="toctitle" lang="en" dir="ltr"><h2 id="mw-toc-heading">Contents</h2><span class="toctogglespan"><label class="toctogglelabel" for="toctogglecheckbox"></label></span></div> <ul> <li class="toclevel-1 tocsection-1"><a href="#Code_Style"><span class="tocnumber">1</span> <span class="toctext">Code Style</span></a></li> <li class="toclevel-1 tocsection-2"><a href="#Code_Guidelines"><span class="tocnumber">2</span> <span class="toctext">Code Guidelines</span></a></li> <li class="toclevel-1 tocsection-3"><a href="#Checking_your_code_with_ESLint"><span class="tocnumber">3</span> <span class="toctext">Checking your code with ESLint</span></a> <ul> <li class="toclevel-2 tocsection-4"><a href="#Integrating_ESLint_with_your_editor"><span class="tocnumber">3.1</span> <span class="toctext">Integrating ESLint with your editor</span></a> <ul> <li class="toclevel-3 tocsection-5"><a href="#Vim"><span class="tocnumber">3.1.1</span> <span class="toctext">Vim</span></a></li> </ul> </li> <li class="toclevel-2 tocsection-6"><a href="#Version_control_hooks"><span class="tocnumber">3.2</span> <span class="toctext">Version control hooks</span></a></li> </ul> </li> <li class="toclevel-1 tocsection-7"><a href="#Unit_tests"><span class="tocnumber">4</span> <span class="toctext">Unit tests</span></a> <ul> <li class="toclevel-2 tocsection-8"><a href="#Test_tag"><span class="tocnumber">4.1</span> <span class="toctext">Test tag</span></a></li> <li class="toclevel-2 tocsection-9"><a href="#Code_coverage_tests"><span class="tocnumber">4.2</span> <span class="toctext">Code coverage tests</span></a></li> </ul> </li> <li class="toclevel-1 tocsection-10"><a href="#Code_layout"><span class="tocnumber">5</span> <span class="toctext">Code layout</span></a> <ul> <li class="toclevel-2 tocsection-11"><a href="#API_modules"><span class="tocnumber">5.1</span> <span class="toctext">API modules</span></a></li> <li class="toclevel-2 tocsection-12"><a href="#Permission_strings"><span class="tocnumber">5.2</span> <span class="toctext">Permission strings</span></a></li> </ul> </li> </ul> </div> <h2><span class="mw-headline" id="Code_Style">Code Style</span></h2> <p>WebExtension JavaScript code follows the Mozilla <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style">coding style guide</a>, with the following differences: </p> <ul><li><code>===</code> may be used in favor of <code>==</code> when doing so makes sense.</li> <li>The opening brace in function statements or expressions should be on the same line as the <code>function</code> keyword.</li> <li><code>let</code> or <code>const</code> should be used in place of <code>var</code> wherever possible.</li> <li>Function arguments and variable names should never use Hungarian Notation.</li> <li>All JavaScript files or inline <code>&lt;script&gt;</code> nodes must begin with <code>"use strict";</code></li> <li>All members in multi-line object or array literals must be followed by a comma, including the last.</li> <li>Do <i>not</i> use proprietary, Mozilla-specific JavaScript extensions, including array and generator comprehensions, <code>catch</code> guard expressions, the <code>__proto__</code> property, or the <code>yield</code> operator in non-star-functions.</li> <li>Use <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow functions</a> in preference to function expressions where appropriate.</li> <li>Use <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest parameters</a> in preference to the <code>arguments</code> object where possible.</li> <li>Use <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">default parameters</a> for optional arguments where appropriate.</li> <li>Use <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator">spread expressions</a> in preference to <code>.apply()</code> where possible.</li></ul> <p>ESLint will enforce most of these rules. </p> <h2><span class="mw-headline" id="Code_Guidelines">Code Guidelines</span></h2> <p>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 <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API#Callbacks_and_promises">MDN docs</a> for the difference. </p> <h2><span class="mw-headline" id="Checking_your_code_with_ESLint">Checking your code with ESLint</span></h2> <p>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. </p><p>The simplest way to check your code is using the <code>mach eslint</code> command. This requires that you have <a rel="nofollow" class="external text" href="https://docs.npmjs.com/">NPM</a> installed. </p><p>To setup ESLint, you need to run the following once: </p> <pre>./mach eslint --setup </pre> <p>This should install ESLint, along with the necessary plugins. After that's done, you can check the files you've been working on with the following: </p> <pre>./mach eslint path/to/file.js </pre> <p>Or you can check all WebExtension code with: </p> <pre>./mach eslint toolkit/components/extensions browser/components/extensions toolkit/modules/addons </pre> <h3><span class="mw-headline" id="Integrating_ESLint_with_your_editor">Integrating ESLint with your editor</span></h3> <p>Since manually checking your code isn't always practical (and is easy to forget), it's best to integrate automatic checking with your code editor. Many editors <a rel="nofollow" class="external text" href="http://eslint.org/docs/user-guide/integrations.html">have integration plugins</a>, or built-in support. </p><p>Some editors may need special settings to work well with our codebase. Feel free to add other editors below, as you see fit. </p><p>There is some additional useful information in the <a href="/DevTools/CodingStandards#JS_linting_with_ESLint" title="DevTools/CodingStandards">developer tools hacking</a> section of the wiki. </p> <h4><span class="mw-headline" id="Vim">Vim</span></h4> <p>The easiest way to integrate ESLint with Vim is using the <a rel="nofollow" class="external text" href="https://github.com/scrooloose/syntastic">Syntastic plugin</a>. </p><p>The following assumes that you use the <a rel="nofollow" class="external text" href="https://github.com/VundleVim/Vundle.vim">Vundle package manager</a>. It should be easy enough to adapt to any other package manager you happen to prefer, though. </p><p><code>mach eslint --setup</code> installs a specific ESLint version and some ESLint plugins to a subdirectory of the repository (<a rel="nofollow" class="external text" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1305023">changed in Firefox 55</a>). You should configure Syntastic roughly as follows (change <code>/path/to/mozilla-central</code> as needed): </p> <pre>" Initialize Vundle. filetype off call vundle#rc() " Enable the Syntastic bundle. Bundle 'scrooloose/syntastic' " Enable the specific ESLint checker for files in mozilla-central/ only. " Enable the HTML plugin, and enable JavaScript linting for HTML files. autocmd FileType javascript,html \ if stridx(expand("%:p"), "/mozilla-central/")&#160;!= -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 </pre> <p>After you've added this to your configuration (and have installed Vundle, if necessary), launch Vim and run: </p> <pre>:BundleInstall </pre> <p>This will install the Syntastic plugin. After this, you should be good to go. </p> <h3><span class="mw-headline" id="Version_control_hooks">Version control hooks</span></h3> <p>The <code>mozilla-central</code> tree contains a Mercurial plugin to automatically check any changed files, using ESLint, when you commit. This can be enabled by adding the following to your global <code>.hgrc</code> file, or to <code>.hg/hgrc</code> in your repository: </p> <pre>[extensions] # Replace "~/src/mozilla-central/" with the full path to your mozilla-central repository. mozeslint = ~/src/mozilla-central/tools/mercurial/eslintvalidate.py </pre> <p>On non-Windows systems, this can be achieved with: </p> <pre>printf '[extensions]\nmozeslint = %s/tools/mercurial/eslintvalidate.py' "$(pwd)" &gt;&gt;.hg/hgrc </pre> <p>Now Mercurial will check your code for you, and show any warnings or errors, every time you commit. </p><p><br /> </p> <h2><span class="mw-headline" id="Unit_tests">Unit tests</span></h2> <p>All WebExtension code is required to be covered by comprehensive unit tests. There is <a rel="nofollow" class="external text" href="https://developer.mozilla.org/en-US/docs/Mozilla/QA/Automated_testing">some information on MDN</a> about the various test suites used in Mozilla code. WebExtension code primarilly uses: </p> <dl><dt>Mochitests</dt> <dd>These reside under <code>toolkit/components/extensions/test/mochitest/</code>, and are used to test most APIs that live in the <code>toolkit/components/extensions/</code> directory.</dd> <dt>Browser chrome mochitests</dt> <dd>These reside under <code>browser/components/extensions/test/browser/</code>, and are used to test most APIs that live in the <code>browser/components/extensions/</code> directory.</dd> <dt>xpcshell tests</dt> <dd>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.</dd></dl> <p><a href="/WebExtensions/Try_Server" title="WebExtensions/Try Server">WebExtensions/Try_Server</a> has more information about using the try server to test WebExtension code. </p> <h3><span class="mw-headline" id="Test_tag">Test tag</span></h3> <p>All tests in WebExtensions are <a rel="nofollow" class="external text" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1296888">now tagged</a> 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 <a rel="nofollow" class="external text" href="http://trychooser.pub.build.mozilla.org/">try server syntax</a>. </p> <h3><span class="mw-headline" id="Code_coverage_tests">Code coverage tests</span></h3> <p>Ideally, our test suite should exercise as close to 100% of our codebase as possible. 100% coverage may not always be practical, or desirable, but it's still an ideal we'd like to strive for. To that end, we run code coverage tests weekly, for the above three main test suites. If you land any code in a given week, it's best to check the end-of-week coverage tests to make sure it has adequate test coverage. </p><p>The test results are published in three separate sets: </p> <dl><dt><a rel="nofollow" class="external text" href="https://people.mozilla.org/~kmaglione/webextension-test-coverage/">Total code coverage</a></dt> <dd>This is code coverage for all code run in either the main browser process or in a tab content process.</dd> <dt><a rel="nofollow" class="external text" href="https://people.mozilla.org/~kmaglione/webextension-test-coverage/default/">Main process code coverage</a></dt> <dd>This is code coverage for code run in the main browser process, excluding code run only in a content process.</dd> <dt><a rel="nofollow" class="external text" href="https://people.mozilla.org/~kmaglione/webextension-test-coverage/content/">Content process code coverage</a></dt> <dd>This is code coverage for code run in a tab content process, excluding code run only in the main browser process.</dd></dl> <p>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. </p><p>The above results are generated using <a rel="nofollow" class="external text" href="https://people.mozilla.org/~kmaglione/webext-coverage.patch">this patch</a>, 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: </p> <pre># Install the Istanbul code coverage tool npm install -g istanbul </pre> <pre># Apply the code coverage patch hg import <a rel="nofollow" class="external free" href="https://people.mozilla.org/~kmaglione/webext-coverage.patch">https://people.mozilla.org/~kmaglione/webext-coverage.patch</a> </pre> <pre># Instrument all WebExtension code, run the various test suites, and # generate the coverage output files. ./toolkit/components/extensions/test_coverage.sh </pre> <h2><span class="mw-headline" id="Code_layout">Code layout</span></h2> <p>WebExtension code lives in several different parts of the tree, depending on its purpose: </p> <dl><dt>Generic APIs</dt> <dd>These are the base APIs which don't rely on a browser UI.</dd> <dd>They are defined in files matching <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/">toolkit/components/extensions/ext-*.js</a></code></dd> <dd>Each of these APIs also has a schema definition file, located in <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/schemas/">toolkit/components/extensions/schemas/</a></code></dd> <dt>Content Script APIs</dt> <dd>These are a very simple set of APIs which are available to content scripts, and run in the content process.</dd> <dd>They are all defined in a single file, <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/ExtensionContent.jsm">toolkit/components/extensions/ExtensionContent.jsm</a></code></dd> <dt>Firefox Desktop APIs</dt> <dd>These are APIs which are specific to desktop Firefox, and generally deal directly with the browser UI.</dd> <dd>They are defined in files matching <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/browser/components/extensions/">browser/components/extensions/ext-*.js</a></code></dd> <dd>Each of these APIs also has a schema definition file, located in <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/browser/components/extensions/schemas/">browser/components/extensions/schemas/</a></code></dd> <dt>Low-level helper modules</dt> <dd>These modules deal with some of the low-level functionality required by WebExtension code, including match pattern handling and web request monitoring.</dd> <dd>They live in <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/addons/">toolkit/modules/addons/</a></code></dd> <dt>Core WebExtension modules</dt> <dd>These deal with the core functionality of WebExtensions, including initializing and tearing down extension instances.</dd> <dd>They live in files matching <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/">toolkit/components/extensions/*.jsm</a></code></dd> <dt>XPCOM components</dt> <dd>These are primarily stub interfaces to allow native code to interact with WebExtension management code.</dd> <dd>They are currently all defined in a single file, <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/utils/simpleServices.js">toolkit/components/utils/simpleServices.js</a></code></dd></dl> <h3><span class="mw-headline" id="API_modules">API modules</span></h3> <p>All API modules are loaded into a single module, <code><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/Extension.jsm">toolkit/components/extensions/Extension.jsm</a></code>, and share the same global namespace. All global variables in the <code>Extension.jsm</code> module are automatically available to code in the <code>ext-*.js</code> files. Code in these files may make variables available to other modules by defining them as properties of the <code>global</code> object. For instance, if one module defines <code>global.FooBar = {}</code>, other modules may access it as simply <code>FooBar</code>. </p><p>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. </p><p>Starting from Firefox 50 (<a rel="nofollow" class="external text" href="https://bugzilla.mozilla.org/1285063">Bug 1285063</a>, <a rel="nofollow" class="external text" href="https://hg.mozilla.org/mozilla-central/rev/e9ca8dc4b42e">hg commit e9ca8dc4b42e</a>) all the APIs schema and <code>ext-*.js</code> files must be registered to the category manager through one of the following manifest files: </p> <ul><li><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/extensions-toolkit.manifest">toolkit/components/extensions/extensions-toolkit.manifest</a>, for Generic APIs registered at toolkit level</li> <li><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/browser/components/extensions/extensions-browser.manifest">browser/components/extensions/extensions-browser.manifest</a>, for Firefox desktop APIs</li> <li><a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/mobile/android/components/extensions/extensions-mobile.manifest">mobile/android/components/extensions/extensions-mobile.manifest</a>, for Firefox for Android APIs</li></ul> <p>As an example, here is a snippet of the <code>extension-toolkit.manifest</code>: </p> <pre># scripts category webextension-scripts alarms chrome://extensions/content/ext-alarms.js ... # schemas category webextension-schemas alarms chrome://extensions/content/schemas/alarms.json </pre> <p>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: </p><p>Generic APIs were registered in <code>Extension.jsm</code> as follows: </p> <pre>ExtensionManagement.registerScript("chrome://extensions/content/ext-foobar.js"); ExtensionManagement.registerSchema("chrome://extensions/content/schemas/foobar.json"); </pre> <p>Firefox desktop APIs were registered in <a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/browser/components/nsBrowserGlue.js">nsBrowserGlue.js</a>: </p> <pre>ExtensionManagement.registerScript("chrome://browser/content/ext-bazquux.js"); ExtensionManagement.registerSchema("chrome://browser/content/schemas/bazquux.json"); </pre> <h3><span class="mw-headline" id="Permission_strings">Permission strings</span></h3> <p>The strings for permissions can be found in <a rel="nofollow" class="external text" href="https://dxr.mozilla.org/mozilla-central/source/browser/locales/en-US/chrome/browser/browser.properties">browser.properties</a>. </p><p>If you add an API that requires permissions, then you'll need to make sure the corresponding permission strings are also landed. </p> <!-- NewPP limit report Cached time: 20250217081543 Cache expiry: 86400 Reduced expiry: false Complications: [show鈥恡oc] CPU time usage: 0.016 seconds Real time usage: 0.021 seconds Preprocessor visited node count: 38/1000000 Post鈥恊xpand include size: 0/2097152 bytes Template argument size: 0/2097152 bytes Highest expansion depth: 2/100 Expensive parser function count: 0/100 Unstrip recursion depth: 0/20 Unstrip post鈥恊xpand size: 0/5000000 bytes --> <!-- Transclusion expansion time report (%,ms,calls,template) 100.00% 0.000 1 -total --> <!-- Saved in parser cache with key wiki:pcache:idhash:242670-0!canonical and timestamp 20250217081543 and revision id 1204588. --> </div> <div class="printfooter" data-nosnippet="">Retrieved from "<a dir="ltr" href="https://wiki.mozilla.org/index.php?title=WebExtensions/Hacking&amp;oldid=1204588">https://wiki.mozilla.org/index.php?title=WebExtensions/Hacking&amp;oldid=1204588</a>"</div></div> <div id="catlinks" class="catlinks catlinks-allhidden" data-mw="interface"></div> </div> </div> <div id="mw-navigation"> <h2>Navigation menu</h2> <div id="mw-head"> <nav id="p-personal" class="vector-menu mw-portlet mw-portlet-personal vector-user-menu-legacy" aria-labelledby="p-personal-label" role="navigation" > <h3 id="p-personal-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">Personal tools</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="pt-login" class="mw-list-item"><a href="/index.php?title=Special:UserLogin&amp;returnto=WebExtensions%2FHacking" title="You are encouraged to log in; however, it is not mandatory [o]" accesskey="o"><span>Log in</span></a></li><li id="pt-createaccount" class="mw-list-item"><a href="/Special:RequestAccount" title="You are encouraged to create an account and log in; however, it is not mandatory"><span>Request account</span></a></li></ul> </div> </nav> <div id="left-navigation"> <nav id="p-namespaces" class="vector-menu mw-portlet mw-portlet-namespaces vector-menu-tabs vector-menu-tabs-legacy" aria-labelledby="p-namespaces-label" role="navigation" > <h3 id="p-namespaces-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">Namespaces</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="ca-nstab-main" class="selected mw-list-item"><a href="/WebExtensions/Hacking" title="View the content page [c]" accesskey="c"><span>Page</span></a></li><li id="ca-talk" class="new mw-list-item"><a href="/index.php?title=Talk:WebExtensions/Hacking&amp;action=edit&amp;redlink=1" rel="discussion" title="Discussion about the content page (page does not exist) [t]" accesskey="t"><span>Discussion</span></a></li></ul> </div> </nav> <nav id="p-variants" class="vector-menu mw-portlet mw-portlet-variants emptyPortlet vector-menu-dropdown" aria-labelledby="p-variants-label" role="navigation" > <input type="checkbox" id="p-variants-checkbox" role="button" aria-haspopup="true" data-event-name="ui.dropdown-p-variants" class="vector-menu-checkbox" aria-labelledby="p-variants-label" /> <label id="p-variants-label" aria-label="Change language variant" class="vector-menu-heading " > <span class="vector-menu-heading-label">English</span> </label> <div class="vector-menu-content"> <ul class="vector-menu-content-list"></ul> </div> </nav> </div> <div id="right-navigation"> <nav id="p-views" class="vector-menu mw-portlet mw-portlet-views vector-menu-tabs vector-menu-tabs-legacy" aria-labelledby="p-views-label" role="navigation" > <h3 id="p-views-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">Views</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="ca-view" class="selected mw-list-item"><a href="/WebExtensions/Hacking"><span>Read</span></a></li><li id="ca-viewsource" class="mw-list-item"><a href="/index.php?title=WebExtensions/Hacking&amp;action=edit" title="This page is protected.&#10;You can view its source [e]" accesskey="e"><span>View source</span></a></li><li id="ca-history" class="mw-list-item"><a href="/index.php?title=WebExtensions/Hacking&amp;action=history" title="Past revisions of this page [h]" accesskey="h"><span>View history</span></a></li></ul> </div> </nav> <nav id="p-cactions" class="vector-menu mw-portlet mw-portlet-cactions emptyPortlet vector-menu-dropdown" aria-labelledby="p-cactions-label" role="navigation" title="More options" > <input type="checkbox" id="p-cactions-checkbox" role="button" aria-haspopup="true" data-event-name="ui.dropdown-p-cactions" class="vector-menu-checkbox" aria-labelledby="p-cactions-label" /> <label id="p-cactions-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">More</span> </label> <div class="vector-menu-content"> <ul class="vector-menu-content-list"></ul> </div> </nav> <div id="p-search" role="search" class="vector-search-box-vue vector-search-box-show-thumbnail vector-search-box-auto-expand-width vector-search-box"> <div> <h3 > <label for="searchInput">Search</label> </h3> <form action="/index.php" id="searchform" class="vector-search-box-form"> <div id="simpleSearch" class="vector-search-box-inner" data-search-loc="header-navigation"> <input class="vector-search-box-input" type="search" name="search" placeholder="Search MozillaWiki" aria-label="Search MozillaWiki" autocapitalize="sentences" title="Search MozillaWiki [f]" accesskey="f" id="searchInput" > <input type="hidden" name="title" value="Special:Search"> <input id="mw-searchButton" class="searchButton mw-fallbackSearchButton" type="submit" name="fulltext" title="Search the pages for this text" value="Search"> <input id="searchButton" class="searchButton" type="submit" name="go" title="Go to a page with this exact name if it exists" value="Go"> </div> </form> </div> </div> </div> </div> <div id="mw-panel"> <div id="p-logo" role="banner"> <a class="mw-wiki-logo" href="/Main_Page" title="Visit the main page"></a> </div> <nav id="p-navigation" class="vector-menu mw-portlet mw-portlet-navigation vector-menu-portal portal" aria-labelledby="p-navigation-label" role="navigation" > <h3 id="p-navigation-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">Navigation</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="n-mainpage-description" class="mw-list-item"><a href="/Main_Page" title="Visit the main page [z]" accesskey="z"><span>Main page</span></a></li><li id="n-Product-releases" class="mw-list-item"><a href="/Releases"><span>Product releases</span></a></li><li id="n-newpages" class="mw-list-item"><a href="/Special:NewPages"><span>New pages</span></a></li><li id="n-recentchanges" class="mw-list-item"><a href="/Special:RecentChanges" title="A list of recent changes in the wiki [r]" accesskey="r"><span>Recent changes</span></a></li><li id="n-Recent-uploads" class="mw-list-item"><a href="/Special:NewFiles"><span>Recent uploads</span></a></li><li id="n-randompage" class="mw-list-item"><a href="/Special:Random" title="Load a random page [x]" accesskey="x"><span>Random page</span></a></li><li id="n-Help" class="mw-list-item"><a href="/MozillaWiki:Help" title="The place to find out"><span>Help</span></a></li></ul> </div> </nav> <nav id="p-How_to_Contribute" class="vector-menu mw-portlet mw-portlet-How_to_Contribute vector-menu-portal portal" aria-labelledby="p-How_to_Contribute-label" role="navigation" > <h3 id="p-How_to_Contribute-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">How to Contribute</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="n-All-hands-meeting" class="mw-list-item"><a href="/WeeklyUpdates"><span>All-hands meeting</span></a></li><li id="n-Other-meetings" class="mw-list-item"><a href="/Community_Calendar"><span>Other meetings</span></a></li><li id="n-Contribute-to-Mozilla" class="mw-list-item"><a href="/Contribute"><span>Contribute to Mozilla</span></a></li><li id="n-Community-Portal" class="mw-list-item"><a href="//community.mozilla.org" rel="nofollow"><span>Community Portal</span></a></li><li id="n-Community-Participation-Guidelines" class="mw-list-item"><a href="//www.mozilla.org/en-US/about/governance/policies/participation/" rel="nofollow"><span>Community Participation Guidelines</span></a></li></ul> </div> </nav> <nav id="p-MozillaWiki" class="vector-menu mw-portlet mw-portlet-MozillaWiki vector-menu-portal portal" aria-labelledby="p-MozillaWiki-label" role="navigation" > <h3 id="p-MozillaWiki-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">MozillaWiki</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="n-About" class="mw-list-item"><a href="/MozillaWiki:About"><span>About</span></a></li><li id="n-Team" class="mw-list-item"><a href="/MozillaWiki:Team"><span>Team</span></a></li><li id="n-Policies" class="mw-list-item"><a href="/MozillaWiki:Policies"><span>Policies</span></a></li><li id="n-Report-a-wiki-bug" class="mw-list-item"><a href="//bugzilla.mozilla.org/enter_bug.cgi?product=Websites&amp;component=wiki.mozilla.org" rel="nofollow"><span>Report a wiki bug</span></a></li></ul> </div> </nav> <nav id="p-Around_Mozilla" class="vector-menu mw-portlet mw-portlet-Around_Mozilla vector-menu-portal portal" aria-labelledby="p-Around_Mozilla-label" role="navigation" > <h3 id="p-Around_Mozilla-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">Around Mozilla</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="n-Mozilla-Support" class="mw-list-item"><a href="//support.mozilla.org/" rel="nofollow"><span>Mozilla Support</span></a></li><li id="n-Mozilla-Developer-Network" class="mw-list-item"><a href="//developer.mozilla.org/" rel="nofollow"><span>Mozilla Developer Network</span></a></li><li id="n-Planet-Mozilla" class="mw-list-item"><a href="//planet.mozilla.org/" rel="nofollow"><span>Planet Mozilla</span></a></li><li id="n-Mozilla-Blog" class="mw-list-item"><a href="//blog.mozilla.org/" rel="nofollow"><span>Mozilla Blog</span></a></li><li id="n-Research" class="mw-list-item"><a href="//www.mozilla.org/research/" rel="nofollow"><span>Research</span></a></li></ul> </div> </nav> <nav id="p-tb" class="vector-menu mw-portlet mw-portlet-tb vector-menu-portal portal" aria-labelledby="p-tb-label" role="navigation" > <h3 id="p-tb-label" class="vector-menu-heading " > <span class="vector-menu-heading-label">Tools</span> </h3> <div class="vector-menu-content"> <ul class="vector-menu-content-list"><li id="t-whatlinkshere" class="mw-list-item"><a href="/Special:WhatLinksHere/WebExtensions/Hacking" title="A list of all wiki pages that link here [j]" accesskey="j"><span>What links here</span></a></li><li id="t-recentchangeslinked" class="mw-list-item"><a href="/Special:RecentChangesLinked/WebExtensions/Hacking" rel="nofollow" title="Recent changes in pages linked from this page [k]" accesskey="k"><span>Related changes</span></a></li><li id="t-specialpages" class="mw-list-item"><a href="/Special:SpecialPages" title="A list of all special pages [q]" accesskey="q"><span>Special pages</span></a></li><li id="t-print" class="mw-list-item"><a href="javascript:print();" rel="alternate" title="Printable version of this page [p]" accesskey="p"><span>Printable version</span></a></li><li id="t-permalink" class="mw-list-item"><a href="/index.php?title=WebExtensions/Hacking&amp;oldid=1204588" title="Permanent link to this revision of this page"><span>Permanent link</span></a></li><li id="t-info" class="mw-list-item"><a href="/index.php?title=WebExtensions/Hacking&amp;action=info" title="More information about this page"><span>Page information</span></a></li></ul> </div> </nav> </div> </div> <footer id="footer" class="mw-footer" role="contentinfo" > <ul id="footer-info"> <li id="footer-info-lastmod"> This page was last edited on 29 November 2018, at 15:29.</li> </ul> <ul id="footer-places"> <li id="footer-places-privacy"><a href="/MozillaWiki:Privacy_policy">Privacy policy</a></li> <li id="footer-places-about"><a href="/MozillaWiki:About">About MozillaWiki</a></li> <li id="footer-places-mobileview"><a href="https://wiki.mozilla.org/index.php?title=WebExtensions/Hacking&amp;mobileaction=toggle_view_mobile" class="noprint stopMobileRedirectToggle">Mobile view</a></li> </ul> <ul id="footer-icons" class="noprint"> <li id="footer-poweredbyico"><a href="https://www.mediawiki.org/"><img src="/resources/assets/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" srcset="/resources/assets/poweredby_mediawiki_132x47.png 1.5x, /resources/assets/poweredby_mediawiki_176x62.png 2x" width="88" height="31" loading="lazy"/></a></li> </ul> </footer> <script>(RLQ=window.RLQ||[]).push(function(){mw.config.set({"wgPageParseReport":{"limitreport":{"cputime":"0.016","walltime":"0.021","ppvisitednodes":{"value":38,"limit":1000000},"postexpandincludesize":{"value":0,"limit":2097152},"templateargumentsize":{"value":0,"limit":2097152},"expansiondepth":{"value":2,"limit":100},"expensivefunctioncount":{"value":0,"limit":100},"unstrip-depth":{"value":0,"limit":20},"unstrip-size":{"value":0,"limit":5000000},"timingprofile":["100.00% 0.000 1 -total"]},"cachereport":{"timestamp":"20250217081543","ttl":86400,"transientcontent":false}}});mw.config.set({"wgBackendResponseTime":325});});</script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10