You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2012-01-04-requirejs.markdown
+39-39Lines changed: 39 additions & 39 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,17 +5,17 @@ author: filirom1
5
5
tags: [requirejs, javascript, webapp]
6
6
---
7
7
8
-
Je suis certain que vous aussi, vous avez connu la frénésie jQuery. Le JavaScript prend de plus en plus de place au sein de l'application. On commence à avoir des difficultés à gérer l'ordre des balises scripts, la navigateur télécharge un nombre incroyable de fichiers js et le navigateur rame, on perd le compte du nombre de variables globales, on trouve du code javascript dans l'html et du html dans du javascript, le code dupliqué se multiplie et très vite, on ne sait plus qui fait quoi et rien n'est testé...
8
+
Je suis certain que vous aussi, vous avez connu la frénésie jQuery. Le JavaScript prend de plus en plus de place au sein de l'application. On commence à avoir des difficultés à gérer l'ordre des balises scripts, le navigateur télécharge un nombre incroyable de fichiers js et le navigateur rame, on perd le compte du nombre de variables globales, on trouve du code javascript dans l'html et du html dans du javascript, le code dupliqué se multiplie et très vite, on ne sait plus qui fait quoi et rien n'est testé...
9
9
10
10
Alors comment s'en sortir ?
11
11
12
-
Il existe plusieurs méthodes qui couvrent un spectre plus ou moins large des problèmes exposés cidessus. Je vais commencer par vous les expliquer avant de vous présenter la solution que je préfère : `RequireJS`.
12
+
Il existe plusieurs méthodes qui couvrent un spectre plus ou moins large des problèmes exposés ci-dessus. Je vais commencer par vous les expliquer avant de vous présenter la solution que je préfère : `RequireJS`.
Il nous permet de ne pas pourrir notre scope gloable. En Javascript un scope est défini au niveau des fonctions. Pour éviter que nos variables arrivent dans le scope globale, il suffit de wrapper notre code autour d'une fonction et de l'exécuter tout de suite après.
18
+
Il nous permet de ne pas pourrir notre scope globale. En Javascript un scope est défini au niveau des fonctions. Pour éviter que nos variables arrivent dans le scope globale, il suffit de wrapper notre code autour d'une fonction et de l'exécuter tout de suite après.
19
19
20
20
(function(){
21
21
var private = 'I am private, the global scope is free of me !';
@@ -29,7 +29,7 @@ Il nous permet de ne pas pourrir notre scope gloable. En Javascript un scope est
Maintenant que nous savons isolé notre code, nous devons le découper pour éviter de se retrouver avec un seul gros fichier.
32
+
Maintenant que nous savons isoler notre code, nous devons le découper pour éviter de se retrouver avec un seul gros fichier.
33
33
34
34
A partir du moment où l'on découpe notre code, nous allons avoir besoin d'exporter des fonctions et des attributs publiquement dans une variable globale (ça va une seule, on ne crie pas au scandale tout de suite).
35
35
@@ -66,14 +66,14 @@ Attention script2 dépend de script1. Il y a un ordre à respecter au niveau de
66
66
<script src="script1.js"></script>
67
67
<script src="script2.js"></script>
68
68
69
-
Grouper les fichiers js pour la prod
69
+
Grouper les fichiers JS pour la prod
70
70
------------------------------------
71
71
72
-
On se retrouve avec deux fichiers javascripts, pour le développement c'est mieux, mais pour la prod c'est moins bien ! On a augmenté le nombre de ressource à faire télécharger par le navigateur. Maintenant, il faut grouper et minifier ses ressources js avant de les servir en prod. Pour faire ça, nous pouvons utiliser un simple script shell:
72
+
On se retrouve avec deux fichiers JavaScripts, pour le développement c'est mieux, mais pour la prod c'est moins bien ! On a augmenté le nombre de ressources à faire télécharger par le navigateur. Maintenant, il faut grouper et minifier les ressources JS avant de les servir en prod. Pour faire ça, nous pouvons utiliser un simple script shell:
73
73
74
74
cat js/src/* >> js/build/app.js
75
75
76
-
Mais attention, les dépendances risquent d'être cassé. Nous pouvons également utiliser des outils plus évolués :
76
+
Mais attention, les dépendances risquent d'être cassées. Nous pouvons également utiliser des outils plus évolués :
77
77
78
78
*[Wro4J](http://code.google.com/p/wro4j/) qui possède même un plugin Tapestry <https://github.com/lltyk/tapestry-wro4j> ;)
79
79
* le script de build de [html5 boilerplate](https://github.com/h5bp/html5-boilerplate/wiki/Build-script)
@@ -93,7 +93,7 @@ RequireJs va vous permettre de faire :
93
93
* de la modularité
94
94
* de la gestion de dépendances
95
95
* de ne plus écrire d'HTML dans des fichiers JS
96
-
* de l'optimisation d'assests (grouper et minifier les js et les css)
96
+
* de l'optimisation d'assests (grouper et minifier les JS et les CSS)
97
97
98
98
RequireJS est actuellement la solution mise en avant par :
99
99
@@ -141,7 +141,7 @@ RequireJs définie deux notions : `define` et `require`. Simple non :D
141
141
*`define` permet de définir un module avec des dépendances et des choses (fonction ou variable) à exporter.
142
142
*`require` permet de charger dynamiquement des modules.
143
143
144
-
### Definir un module avec `define`
144
+
### Définir un module avec `define`
145
145
146
146
Si nous prenons l'exemple d'un module simple.
147
147
@@ -150,16 +150,16 @@ Si nous prenons l'exemple d'un module simple.
150
150
'underscore',
151
151
'js/myScript',
152
152
...
153
-
], function($, _, myScript, ...){
153
+
], function($, _, myScript, ...){
154
154
155
155
/* your private methods and variable here */
156
156
157
157
return { /* your public variables and functions here */ }
158
158
});
159
159
160
-
Je n'ai pas spécifier l'id, RequireJs va s'en occuper pour moi et je vous conseil de faire de même. Votre code sera réutilisable plus facilement.
160
+
Je n'ai pas spécifier l'ID, RequireJs va s'en occuper pour moi et je vous conseil de faire de même. Votre code sera réutilisable plus facilement.
161
161
162
-
Dans mon module, j'ai spécifié une liste de dépendances.
162
+
Dans mon module, j'ai spécifié une liste de dépendances.
163
163
164
164
[
165
165
'jquery',
@@ -205,11 +205,11 @@ Comme vous l'avez remarqué le premier paramètre de requireJS est un objet de c
205
205
underscore: 'js/libs/underscore-min'
206
206
}
207
207
208
-
Le paramètre `paths` nous permet de definir l'emplacement des librairies utilisés
208
+
Le paramètre `paths` nous permet de définir l'emplacement des librairies utilisées
209
209
210
-
Tout à l'heure je vous est dit, n'utiliser pas d'ID dans vos modules et vous allez maintenant comprendre pourquoi.
210
+
Tout à l'heure je vous ai dit, n'utilisez pas d'ID dans vos modules et vous allez maintenant comprendre pourquoi.
211
211
212
-
jQuery définie dans son [code](https://github.com/jquery/jquery/blob/cae1b6174917df3b4db661f20ef4745dd6e7f305/src/core.js#L949) un `define('jquery', function(){ return jQuery });` Le premier paramètre `jquery` est l'id et nous oblige à utiliser le terme `jquery` pour l'ajouter en tant que dépendance. Vous avez compris, c'est relou, alors ne le faîtes pas :)
212
+
jQuery définie dans son [code](https://github.com/jquery/jquery/blob/cae1b6174917df3b4db661f20ef4745dd6e7f305/src/core.js#L949) un `define('jquery', function(){ return jQuery });` Le premier paramètre `jquery` est l'ID et nous oblige à utiliser le terme `jquery` pour l'ajouter en tant que dépendance. Vous avez compris, c'est relou, alors ne le faîtes pas :)
213
213
214
214
Normalement nous aurions pu faire appel à jquery via son chemin complet :
215
215
`define(['js/libs/jquery-1.7.1.min'], function($){ ... })`, mais à cause de l'ID nous devons faire réference à jquery par son id :`define(['jquery'], function($){ ... })`
@@ -219,7 +219,7 @@ C'est le rôle de la configuration `paths: { jquery: 'js/libs/jquery-1.7.1.min',
219
219
220
220
### Intégrer RequireJS dans notre HTML
221
221
222
-
Il faut rajouter dans le HTML les balises script pour require.js et notre bootstrap.js (celui faisant appel à toute nos dépendances) afin que le navigateur charge notre application.
222
+
Il faut rajouter dans le HTML les balises `script` pour RequireJS et notre bootstrap.js (celui faisant appel à toute nos dépendances) afin que le navigateur charge notre application.
223
223
224
224
<html>
225
225
<head>...</head>
@@ -230,12 +230,12 @@ Il faut rajouter dans le HTML les balises script pour require.js et notre bootst
230
230
</body>
231
231
</html>
232
232
233
-
RequireJs rajoutera les dépendances chargées via des balises script dans
233
+
RequireJS rajoutera les dépendances chargées via des balises script dans
234
234
le head et le navigateur les chargera automatiquement. Si la dépendance
235
-
est nécessaire plusieurs fois, RequireJs à l'intelligence de ne la
235
+
est nécessaire plusieurs fois, RequireJs a l'intelligence de ne la
236
236
récupérer qu'une seule fois.
237
237
238
-
Maintenant lorsque nous naviguons sur notre site, le navigateur télécharge require.js, le bootstrap, et toute les dépendances.
238
+
Maintenant lorsque nous naviguons sur notre site, le navigateur télécharge RequireJS, le bootstrap, et toute les dépendances.
239
239
240
240
241
241
### Optimiser les ressources
@@ -246,30 +246,28 @@ Nous aurions besoin de grouper et minifier l'ensemble de ces fichiers avant de l
246
246
247
247
RequireJS arrive avec un [script de build](https://github.com/jrburke/r.js/) qui a exactement ce rôle là.
248
248
249
-
Si on appelle r.js avec le paramètre -o et en lui spécifiant un fichier de configuration : `r.js -o build.js`
250
-
251
-
r.js va parcourir l'ensemble des scripts et les minifiers, puis va parcourir nos dépendances afin de les grouper. Les fichiers résultant seront placé dans un nouveau répertoire afin de ne pas écraser les sources.
249
+
Si on appelle r.js avec le paramètre -o et en lui spécifiant un fichier de configuration : `r.js -o build.js`. r.js va parcourir l'ensemble des scripts et les minifier, puis va parcourir nos dépendances afin de les grouper. Les fichiers résultant seront placés dans un nouveau répertoire afin de ne pas écraser les sources.
252
250
253
251
({
254
252
appDir: './src', /* Repertoire des sources */
255
253
baseUrl: ".", /* Le repertoire racine */
256
254
dir: "./build", /* Repertoire de destination */
257
255
modules: [ {
258
-
name: 'bootstrap' /* Une dependance vers le fichier appelant le require */
256
+
name: 'bootstrap' /* Une dependance vers un module */
259
257
} ],
260
258
optimizeCss: "standard.keepLines", /* On va même optimiser les CSS */
261
259
dirExclusionRegExp: /node_modules|test|build/ /* on va exclure du processus de build certain repertoires. */
262
260
})
263
261
264
-
Le fichier bootstrap.js du réperoire build contiendra l'ensemble de notre code js minifié.
265
-
262
+
Le fichier bootstrap.js du réperoire build contiendra l'ensemble de notre code js minifié.
266
263
264
+
PS : r.js nécessite node ou Rhino pour fonctionner.
267
265
268
266
### Chargement dynamique de code
269
267
270
268
Il se peut que lors de la construction d'une Single Page Web App vous ayez besoin de définir des ensembles de modules. Par exemple un module qui contient l'ensemble du code JS pour le frontend de votre appli et un autre module qui va contenir le code JS supplémentaire nécessaire pour charger le backend.
271
269
272
-
Vous ne souhaitez pas que les internautes qui accèdent à votre frontend soit ralenti par le télechargement des ressources du backend.
270
+
Vous ne souhaitez pas que les internautes qui accèdent à votre frontend soit ralenti par le téléchargement des ressources du backend.
273
271
274
272
C'est pour répondre à cette problématique que le script de build r.js peut être configuré avec plusieurs modules ayant des options d'include et d'exclude.
275
273
@@ -278,10 +276,10 @@ C'est pour répondre à cette problématique que le script de build r.js peut ê
278
276
279
277
Sur mobile on a toujours des contraintes des tailles. Nous ne voulons surtout pas charger de librairies inutilement. Du fait que nous avons utilisé la structuration AMD (Asynchrnous Module Definition) dans notre code, nous sommes obligé d'utiliser une implementation AMD pour lancer notre application et RequireJs n'est pas la seule implémentation existante.
280
278
281
-
Actuellement il en existe plusieurs dont 3 que j'ai testé personnellement.
279
+
Actuellement il en existe plusieurs dont 3 que j'ai testées personnellement.
282
280
283
-
* Almond la plus petite (mois de 1Ko gzippé) ne fait pas de chargement dynamique. Elle fonctionne très bien en complément du script builder r.js. Comme tout le code est groupé en un seul fichier, Almond peut faire son travail. Almond est la solution privilégiée sur mobile.
284
-
* Curl.js qui est deux fois moins gros que RequireJs mais qui fait également moins de choses. De toute façon RequireJS fait beaucoup beaucoup de chose dont vous n'aurez pas forcement besoin et curl.js peut donc être une bonne alternative si vous avez besoin de chargement dynamique de code.
281
+
* Almond la plus petite (mois de 1Ko gzippé) ne fait pas de chargement dynamique; tous les modules doivent être contenu dans un seul fichier. Elle fonctionne très bien en complément du script builder r.js. Comme tout le code est groupé en un seul fichier, Almond peut faire son travail. Almond est la solution privilégiée sur mobile.
282
+
* Curl.js qui est deux fois moins gros que RequireJs et peut être une bonne alternative si vous avez besoin de chargement dynamique de code.
285
283
286
284
Par contre, sur des projets un peu gros, souvent RequireJS est le seul à s'en sortir.
287
285
@@ -293,7 +291,7 @@ Et voici une comparaisons des implémentations en terme de taille
Si vous utilisez almond qui ne fait pas de dynamique loading, vous aurez besoin en prod de remplacer RequireJS + votre code par un seul fichier minifié contenant tout.
294
+
Si vous utilisez Almond qui ne fait pas de chargement dynamique, vous aurez besoin en prod de remplacer [RequireJS + votre code] par un seul fichier minifié contenant tout.
297
295
298
296
- <script src="require.js"></script>
299
297
- <script src="boostrap.js"></script>
@@ -306,9 +304,9 @@ Pour cela vous pouvez :
306
304
307
305
### Stop au JS dans les HTML et à l'HTML dans les JS
308
306
309
-
Avec requireJs et son plugin text vous avez la chance, de ne plus jamais écrire de Javascript dans des fichiers HTML, ni d'écrire du HTML dans les fichiers Javascript.
307
+
Avec RequireJS et son plugin text vous avez la chance, de ne plus jamais écrire de JavaScript dans des fichiers HTML, ni d'écrire du HTML dans les fichiers JavaScript.
310
308
311
-
Voici un exemple de module RequireJS avec un dépendance texte (regardez
309
+
Voici un exemple de module RequireJS avec une dépendance texte (regardez
312
310
le préfixe text!) :
313
311
314
312
/* bootstrap.js */
@@ -341,7 +339,7 @@ Si on faisait tourner le script de build r.js on obtiendrait dans le même fichi
341
339
342
340
* jQuery
343
341
* undercore
344
-
* le template inliné. Il ressemblerait a ça : define('text!views/template.html', function(){ return '< div class= ....' });
342
+
* le template inliné. Il ressemblerait à ça : define('text!views/template.html', function(){ return '< div class= ....' });
345
343
* et notre bootstrap.js
346
344
347
345
RequireJS possède même des plugins afin de compiler les templates par le script de build r.js : [underscore template](https://github.com/ZeeAgency/requirejs-tpl), [handlebars](https://github.com/SlexAxton/require-handlebars-plugin) . Encore une chose de moins à faire côté client :).
@@ -350,15 +348,16 @@ RequireJS possède même des plugins afin de compiler les templates par le scrip
350
348
Conclusion
351
349
----------
352
350
353
-
Quoi que RequireJs peut paraitre un poil complexe à configurer, RequireJs permet de répondre à pas mal de problématique et pour l'instant je n'ai rien trouvé de mieux pour faire des Single Page Web App.
351
+
Quoi que RequireJs peut paraitre un poil complexe à configurer, RequireJs permet de répondre à pas mal de problématiques et pour l'instant je n'ai rien trouvé de mieux pour faire des Single Page Web App.
354
352
355
-
Pour de la SPA : RequireJS + Backbone c'est un must have. Je l'ai déjà
356
-
cité, mais regardé le livre de Addy Osmani : [Backbone Fondamentals](https://github.com/addyosmani/backbone-fundamentals) il vaut vraiment le coup.
353
+
D'ailleurs, pour de la SPA : RequireJS + Backbone c'est un must have. Je l'ai déjà
354
+
cité, mais regardez le livre de Addy Osmani : [Backbone Fondamentals](https://github.com/addyosmani/backbone-fundamentals) il vaut vraiment le coup.
357
355
358
-
Si vous voulez voir des exemples de code utilisant requireJS, j'ai créé
359
-
un repo pour ça : <https://github.com/Filirom1/requirejs-examples>.
356
+
Si vous voulez voir des exemples de code utilisant RequireJS, j'ai créé
357
+
un repo pour ça : <https://github.com/Filirom1/requirejs-examples> à
358
+
l'occasion d'un talk à [LyonJS](http://lyonjs.org).
360
359
361
-
Si vous souhaitez plus de ressources sur RequireJS :
360
+
Si vous souhaitez plus de ressources sur RequireJS :
362
361
363
362
*[Lisez le site officiel de RequireJS](http://requirejs.org/)
364
363
*[Plongez vous dans la présentation de AMD, CommonJS et des ES imports/exports par Addy Osmani](http://addyosmani.com/writing-modular-js/)
@@ -367,3 +366,4 @@ Si vous souhaitez plus de ressources sur RequireJS :
367
366
*[Sur mobile essayez Almond](https://github.com/jrburke/almond)
0 commit comments