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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
|
---
title: Construction d'une extension cross-browser
slug: Mozilla/Add-ons/WebExtensions/construction_extension_cross_browser
tags:
- Add-ons
- Extensions
- Guide
- WebExtensions
translation_of: Mozilla/Add-ons/WebExtensions/Build_a_cross_browser_extension
---
<p>{{AddonSidebar()}}</p>
<p>L'introduction de l'API d'extension de navigateur a créé un paysage plus uniforme pour le développement d'extensions des navigateurs. Cependant, parmi les navigateurs qui utilisent les API d'extensions (les principales étant Chrome, Firefox, Opera et Edge), vous verrez des différences à la fois dans l'implémentation de l'API et dans la portée de la couverture. Et puis, Safari utilise ses propres extensions Safari Extensions JS.</p>
<p>Maximiser la portée de votre extension de navigateur signifie la développer pour au moins deux navigateurs différents, voire plus. Cet article examine six des principaux défis rencontrés lors de la création d'une extension multi-navigateurs, et dans chaque cas, suggère comment relever ce défi.</p>
<p>Cet article ne traite pas de la création d'extensions de navigateur pour Safari. Il est possible de partager certaines ressources avec une extension Safari, comme des images et du contenu HTML. Cependant, le codage JavaScript doit être entrepris comme un projet de développement séparé, à moins que vous ne souhaitiez créer votre propre polyfill.</p>
<h2 id="Obstacles_lors_du_codage_dextension_multiplateforme">Obstacles lors du codage d'extension multiplateforme</h2>
<p>Il y a six domaines que vous devez aborder lorsque vous vous attaquez à une extension multiplateforme :</p>
<ul>
<li>Espace de nommage de l'API</li>
<li>Gestion asynchrone des événements API</li>
<li>Couverture des fonctions API</li>
<li>Clés du Manifest</li>
<li>Package d'Extension</li>
<li>Publication</li>
</ul>
<h3 id="Espace_de_nommage_de_lAPI">Espace de nommage de l'API</h3>
<p>Deux espaces de noms API sont utilisés parmi les quatre principaux navigateurs :</p>
<ul>
<li><code>browser.*</code>, le standard proposé pour l'API d'extensions, utilisé par Firefox et Edge.</li>
<li><code>chrome.*</code> utilisé par Chrome et Opera.</li>
</ul>
<p>Firefox prend également en charge l'espace de noms <code>chrome.*</code> pour les API compatibles avec Chrome, principalement pour faciliter le <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Porting_a_Google_Chrome_extension">portage</a>. Cependant, il est préférable d'utiliser l'espace de nommage <code>browser.*</code>. En plus d'être la norme proposée, <code>browser.*</code> utilise des promesses — un mécanisme moderne et pratique pour gérer les événements asynchrones.</p>
<p>Ce n'est que dans les extensions les plus triviales que l'espace de nommage sera probablement le seul problème multiplateforme qui devra être traité. Il est donc rarement, voire jamais, utile d'essayer d'aborder cette question seul. La meilleure approche consiste à traiter ce problème avec une gestion asynchrone des événements.</p>
<h3 id="Gestion_asynchrone_des_événements_API">Gestion asynchrone des événements API</h3>
<p>Il existe deux approches pour gérer les événements asynchrones utilisées par les quatre principaux navigateurs :</p>
<ul>
<li><a href="/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise">Promises</a>, le standard proposé pour l'API d'extensions, utilisé par Firefox.</li>
<li>callbacks, utilisés par Chrome, Edge, et Opera.</li>
</ul>
<p>Firefox prend également en charge les rappels pour les API qui prennent en charge l'espace de noms <code>chrome.*</code>. Cependant, il est recommandé d'utiliser des promesses (et l'espace de noms <code>browser.*</code> du navigateur). Des promesses ont été adoptées dans le cadre de la norme proposée. Il simplifie grandement la gestion asynchrone des événements, en particulier lorsque vous devez enchaîner des événements.</p>
<p>Si vous n'êtes pas familier avec les différences entre ces deux méthodes, jetez un coup d'oeil à <a href="https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee">Apprendre à connaître le Javascript asynchrone : Rappels, promesses et synchronisation/attente</a> ou la page des <a href="/fr/docs/Web/JavaScript/Guide/Utiliser_les_promesses">promesses d'utilisation</a> de MDN.</p>
<p>Alors, comment tirer profit des promesses facilement, alors que Firefox est le seul navigateur qui les supporte ? La solution est de coder pour Firefox en utilisant des promesses et d'utiliser le <a href="https://github.com/mozilla/webextension-polyfill/">navigateur WebExtension API Polyfill</a>. Cette polyfill prend en compte l'espace de nommage de l'API et la gestion asynchrone des événements dans Firefox, Chrome et Opera. Au moment de la rédaction du présent document (novembre 2018), le soutien pour Edge était en cours d'élaboration.</p>
<p>Vous installez le navigateur WebExtension API Polyfill dans votre environnement de développement à l'aide de npm ou vous le téléchargez directement depuis les <a href="https://github.com/mozilla/webextension-polyfill/releases">versions de GitHub</a>. Vous référencerez alors <code>browser-polyfill.js</code> dans :</p>
<ul>
<li><code>manifest.json</code>, pour mettre à disposition des scripts de fond et de contenu.</li>
<li>Documents HTML, tels que les popups <code>browserAction</code> ou les pages à onglet.</li>
<li>L'appel <code>executeScript</code> dans les scripts de contenu dynamiquement injectés chargés par <code>tabs.executeScript</code>, où il n'a pas été chargé en utilisant une déclaration <code>content_scripts</code> dans manifest.json.</li>
</ul>
<p>Ainsi, par exemple, ce code <code>manifest.json</code> rend le polyfill disponible pour vos scripts d'arrière-plan :</p>
<pre class="brush: json">{
// ...
"background": {
"scripts": [
"browser-polyfill.js",
"background.js"
]
}
}</pre>
<p>Votre but est de vous assurer que le polyfill s'exécute dans votre extension avant tout autre script qui attend le <code>browser.*</code> API namespace s'exécute.</p>
<p>Pour plus de détails et d'informations sur l'utilisation du polyfill avec un module bundler, voir le <a href="https://github.com/mozilla/webextension-polyfill/blob/master/README.md">readme du projet sur GitHub.</a></p>
<p>Il existe d'autres options de polyfill mais, au moment d'écrire ces lignes, aucune ne fournit la couverture de l'API Polyfill du navigateur WebExtension. Ainsi, lorsque vous n'avez pas choisi Firefox comme premier choix, vos options sont d'accepter les limitations des polyfills alternatifs, de porter sur Firefox et d'ajouter la prise en charge du cross-browser, ou de développer votre propre polyfill.</p>
<h3 id="Couverture_des_fonctions_API">Couverture des fonctions API</h3>
<p>Les différences dans les fonctions API offertes dans chacun des quatre principaux navigateurs se répartissent en trois grandes catégories :</p>
<ul>
<li>Manque de soutien pour l'ensemble d'une fonction. Par exemple, au moment d'écrire ces lignes, Edge ne prenait pas en charge la fonction de <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/privacy#Browser_compatibility">vie privée</a>.</li>
<li>Variations in the support for features within a function. For example, at the time of writing, Firefox doesn’t support the notification function method <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/notifications/onButtonClicked#Browser_compatibility">onButtonClicked</a> while Firefox is the only browser that supports <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/notifications/onShown#Browser_compatibility">onShown</a>.</li>
<li>Proprietary functions, supporting browser specific features. For example, at the time of writing, containers was a Firefox-specific feature supported by the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/contextualIdentities#Browser_compatibility">contextualIdentities</a> function.</li>
</ul>
<p>You can find details about the support for the extension APIs among the four main browsers and Firefox for Android on the Mozilla Developer Network <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_support_for_JavaScript_APIs">Browser support for JavaScript APIs</a> page. Browser compatibility information is also included with each function and its methods, types, and events in the Mozilla Developer Network <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API">JavaScript APIs</a> reference pages.</p>
<p>A simple approach to addressing these differences is to limit the functions used in your extension to functions that offer the same functionality across your range of targeted browsers. In practice, for most extensions, this approach is likely to be too restrictive.</p>
<p>The approach you should take where there are differences among the APIs, is to offer either alternative implementations or fallback functionality. Remember that you may also need to do this to allow for differences in API support between versions of the same browser.</p>
<p>The use of runtime checks on the availability of a function’s features is the recommended approach to implementing alternative or fallback functionality. The benefit of performing a runtime check is that if the function becomes available you don’t need to update and redistribute the extension to take advantage of it.</p>
<p>The following code enables you to perform a runtime check:</p>
<pre class="brush: js">if (typeof <function> === "function") {
// safe to use the function
}</pre>
<h3 id="Manifest_keys">Manifest keys</h3>
<p>The differences in the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_compatibility_for_manifest.json">manifest.json</a> file keys supported by the four main browsers fall broadly into three categories:</p>
<ul>
<li>Extension information attributes. For example, at the time of writing, Firefox and Opera include the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/developer#Browser_compatibility">developer</a> key for details about the developer, as well as the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/author#Browser_compatibility">author</a>, of the extension.</li>
<li>Extension features. For example, at the time of writing, Edge did not support the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/commands#Browser_compatibility">commands</a> key that enables shortcut keys to be defined for an extension.</li>
<li>Key optionality. For example, at the time of writing, the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/author#Browser_compatibility">author</a> key is mandatory in Edge but optional in the other main browsers.</li>
</ul>
<p>Browser compatibility information is included with each key in the Mozilla Developer Network <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json">manifest.json key reference pages</a>.</p>
<p>As <code>manifest.json</code> files tend to change little—except for release numbers, which may be different between the various browsers—creating and editing a static version for each browser is usually the simplest approach.</p>
<h3 id="Extension_packaging">Extension packaging</h3>
<p>Packaging an extension for distribution through the browser extension stores is relatively straightforward. Firefox, Chrome, and Opera all use a simple zip format that requires the <code>manifest.json</code> file to be at the root of the zip package. However, submitting to the Microsoft store requires additional packaging of the extension file.</p>
<p>For details on packaging, refer to the guidance on the respective extension’s developer portals.</p>
<h3 id="Publishing">Publishing</h3>
<p>Each of the four major browsers maintains browser extension stores. As a consequence, you need to approach adding and updating your extension in each separately. In some cases you can upload your extension using a utility. Each of the stores also performs a review of your extension to check for security vulnerabilities. The table below summarizes the approach and features of each store:</p>
<table>
<tbody>
<tr>
<td></td>
<td>
<p>Registration fee</p>
</td>
<td>
<p>Upload utility</p>
</td>
<td>
<p>Pre-publication review process</p>
</td>
<td>
<p>Account two factor authentication</p>
</td>
</tr>
<tr>
<td>
<p>Firefox</p>
</td>
<td>
<p>No</p>
</td>
<td>
<p><a href="/en-US/Add-ons/WebExtensions/web-ext_command_reference">web-ext</a></p>
</td>
<td>
<p>Automatic, a few seconds<sup>1</sup></p>
</td>
<td>
<p>No</p>
</td>
</tr>
<tr>
<td>
<p>Chrome</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Automatic, less than an hour</p>
</td>
<td>
<p>Yes</p>
</td>
</tr>
<tr>
<td>
<p>Opera</p>
</td>
<td>
<p>No</p>
</td>
<td>
<p>No</p>
</td>
<td>
<p>Manual, no SLA provided</p>
</td>
<td>
<p>No</p>
</td>
</tr>
<tr>
<td>
<p>Edge</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>No</p>
</td>
<td>
<p>Manual, up to 72 hours<sup>2</sup></p>
</td>
<td>
<p>Yes</p>
</td>
</tr>
</tbody>
</table>
<p>1) A manual review of the extension takes place after publication, which may result in the extension being suspended where issues that need fixing are found.</p>
<p>2) At the time of writing, Microsoft was only allowing publication of preapproved extensions.</p>
<h3 id="Other_considerations">Other considerations</h3>
<h4 id="Extension_naming">Extension naming</h4>
<p>Microsoft requires that extensions have unique names and provides a process for claiming one or more names for your extension through the Windows Dev Center. It may therefore be prudent to reserve an extension name with Microsoft, even if you’re not intending to support Edge immediately. None of the other stores apply name restrictions.</p>
<h4 id="Version_numbering">Version numbering</h4>
<p>The Firefox and Chrome stores require that each uploaded version has a separate version number. This means that you cannot revert to an earlier version number, if you come across issues in a release.</p>
<h4 id="Share_content">Share content</h4>
<p>Even when you include developing extensions for Safari, there are a number of assets you can potentially share across all of your implementations. These include:</p>
<ul>
<li>Images</li>
<li>HTML</li>
<li>CSS</li>
</ul>
<h2 id="Conclusion">Conclusion</h2>
<p>When approaching a cross-platform extension development, addressing the fundamental differences between extension API implementations can be addressed by targeting Firefox and using the <a href="https://github.com/mozilla/webextension-polyfill/">WebExtension browser API Polyfill</a>. Following this approach you benefit from using API features that are closely aligned with the proposed extensions API standard and offer you the simplicity of promises for asynchronous event handling.</p>
<p>The bulk of your cross-platform work is likely to focus on handling variations among the API features supported by the main browsers. Creating your <code>manifest.json</code> files should be relatively straightforward and something you can do manually. You will then need to account for the variations in extension packaging and the processes for submitting to each of the extension stores.</p>
<p>Following the advice in this article, you should be able to create an extension that works well on all of the four main browsers, enabling you to deliver your extension features to more people.</p>
|