1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
Background
==========
WebExtensions run in a sandboxed environment much like regular web content.
The purpose of extensions is to enhance the browser in a way that
regular content cannot -- WebExtensions APIs bridge this gap by exposing
browser features to extensions in a way preserves safety, reliability,
and performance.
The implementation of a WebExtension API runs with
:doc:`chrome privileges </dom/scriptSecurity/index>`.
Browser internals are accessed using
:ref:`XPCOM`
or :doc:`ChromeOnly WebIDL features </dom/webIdlBindings/index>`.
The rest of this documentation covers how API implementations interact
with the implementation of WebExtensions.
To expose some browser feature to WebExtensions, the first step is
to design the API. Some high-level principles for API design
are documented on the Mozilla wiki:
- `Vision for WebExtensions <https://wiki.mozilla.org/WebExtensions/Vision>`_
- `API Policies <https://wiki.mozilla.org/WebExtensions/policy>`_
- `Process for creating new APIs <https://wiki.mozilla.org/WebExtensions/NewAPIs>`_
Javascript APIs
---------------
Many WebExtension APIs are accessed directly from extensions through
Javascript. Functions are the most common type of object to expose,
though some extensions expose properties of primitive Javascript types
(e.g., constants).
Regardless of the exact method by which something is exposed,
there are a few important considerations when designing part of an API
that is accessible from Javascript:
- **Namespace**:
Everything provided to extensions is exposed as part of a global object
called ``browser``. For compatibility with Google Chrome, many of these
features are also exposed on a global object called ``chrome``.
Functions and other objects are not exposed directly as properties on
``browser``, they are organized into *namespaces*, which appear as
properties on ``browser``. For example, the
`tabs API <https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs>`_
uses a namespace called ``tabs``, so all its functions and other
properties appear on the object ``browser.tabs``.
For a new API that provides features via Javascript, the usual practice
is to create a new namespace with a concise but descriptive name.
- **Environments**:
There are several different types of Javascript environments in which
extension code can execute: extension pages, content scripts, proxy
scripts, and devtools pages.
Extension pages include the background page, popups, and content pages
accessed via |getURL|_.
When creating a new Javascript feature the designer must choose
in which of these environments the feature will be available.
Most Javascript features are available in extension pages,
other environments have limited sets of API features available.
.. |getURL| replace:: ``browser.runtime.getURL()``
.. _getURL: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/getURL
- **Permissions**:
Many Javascript features are only present for extensions that
include an appropriate permission in the manifest.
The guidelines for when an API feature requires a permission are
described in (*citation needed*).
The specific types of features that can be exposed via Javascript are:
- **Functions**:
A function callable from Javascript is perhaps the most commonly
used feature in WebExtension APIs.
New API functions are asynchronous, returning a
`Promise <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise>`_. Even functions that do not return a result
use Promises so that errors can be indicated asynchronously
via a rejected Promise as opposed to a synchronously thrown Error.
This is due to the fact that extensions run in a child process and
many API functions require communication with the main process.
If an API function that needs to communicate in this way returned a
synchronous result, then all Javascript execution in the child
process would need to be paused until a response from the main process
was received. Even if a function could be implemented synchronously
within a child process, the standard practice is to make it
asynchronous so as not to constrain the implementation of the underlying
browser feature and make it impossible to move functionality out of the
child process.
Another consequence of functions using inter-process communication is
that the parameters to a function and its return value must all be
simple data types that can be sent between processes using the
`structured clone algorithm <https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm>`_.
- **Events**:
Events complement functions (which allow an extension to call into
an API) by allowing an event within the browser to invoke a callback
in the extension.
Any time an API requires an extension to pass a callback function that
gets invoked some arbitrary number of times, that API method should be
defined as an event.
Manifest Keys
-------------
In addition to providing functionality via Javascript, WebExtension APIs
can also take actions based on the contents of particular properties
in an extension's manifest (or even just the presence of a particular
property).
Manifest entries are used for features in which an extension specifies
some static information that is used when an extension is installed or
when it starts up (i.e., before it has the chance to run any code to use
a Javascript API).
An API may handle a manifest key and implement Javascript functionality,
see the
`browser action <https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/browserAction>`_
API for an example.
Other Considerations
--------------------
In addition to the guidelines outlined above,
there are some other considerations when designing and implementing
a WebExtension API:
- **Cleanup**: A badly written WebExtension should not be able to permanently
leak any resources. In particular, any action from an extension that
causes a resource to be allocated within the browser should be
automatically cleaned up when the extension is disabled or uninstalled.
This is described in more detail in the section on :ref:`lifecycle`.
- **Performance**: A new WebExtension API should not add any new overhead
to the browser when the API is not used. That is, the implementation
of the API should not be loaded at all unless it is actively used by
an extension. In addition, initialization should be delayed when
possible -- extensions ared started relatively early in the browser
startup process so any unnecessary work done during extension startup
contributes directly to sluggish browser startup.
|