Voici un exemple plus concret.
Je travaille dans un projet avec 60 fichiers. Nous avons 2 modes de fonctionnement différents.
Chargez une version concaténée, 1 gros fichier. (Production)
Charger les 60 fichiers (développement)
Nous utilisons un chargeur, nous n'avons donc qu'un seul script dans la page Web
<script src="loader.js"></script>
Par défaut, le mode n ° 1 (chargement du seul gros fichier concaténé). Pour exécuter le mode # 2 (fichiers séparés), nous définissons un indicateur. Ça pourrait être n'importe quoi. Une clé dans la chaîne de requête. Dans cet exemple, nous faisons simplement ceci
<script>useDebugVersion = true;</script>
<script src="loader.js"></script>
loader.js ressemble à quelque chose comme ça
if (useDebugVersion) {
injectScript("app.js");
injectScript("somelib.js");
injectScript("someotherlib.js");
injectScript("anotherlib.js");
... repeat for 60 files ...
} else {
injectScript("large-concatinated.js");
}
Le script de construction est juste un fichier .sh qui ressemble à ceci
cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js
etc...
Si un nouveau fichier est ajouté, nous utiliserons probablement le mode # 2 puisque nous faisons du développement, nous devons ajouter une injectScript("somenewfile.js")
ligne à loader.js
Ensuite, pour la production, nous devons également ajouter somenewfile.js à notre script de construction. Une étape que nous oublions souvent et que nous recevons ensuite des messages d'erreur.
En passant à AMD, nous n'avons pas à modifier 2 fichiers. Le problème de la synchronisation de loader.js et du script de construction disparaît. En utilisant r.js
ou webpack
il peut simplement lire le code pour construirelarge-concantinated.js
Il peut également gérer les dépendances, par exemple nous avons eu 2 fichiers lib1.js et lib2.js chargés comme ceci
injectScript("lib1.js");
injectScript("lib2.js");
lib2 a besoin de lib1. Il contient du code qui fait quelque chose comme
lib1Api.installPlugin(...);
Mais comme les scripts injectés sont chargés de manière asynchrone, il n'y a aucune garantie qu'ils se chargeront dans le bon ordre. Ces 2 scripts ne sont pas des scripts AMD mais en utilisant require.js nous pouvons lui dire leurs dépendances
require.config({
paths: {
lib1: './path/to/lib1',
lib2: './path/to/lib2',
},
shim: {
lib1: {
"exports": 'lib1Api',
},
lib2: {
"deps": ["lib1"],
},
}
});
I notre module qui utilise lib1 nous faisons ceci
define(['lib1'], function(lib1Api) {
lib1Api.doSomething(...);
});
Maintenant, require.js va injecter les scripts pour nous et il n'injectera pas lib2 tant que lib1 n'aura pas été chargé puisque nous lui avons dit que lib2 dépend de lib1. Il ne démarrera pas non plus notre module qui utilise lib1 tant que lib2 et lib1 ne seront pas chargés.
Cela rend le développement agréable (pas d'étape de construction, pas de souci pour l'ordre de chargement) et cela rend la production agréable (pas besoin de mettre à jour un script de construction pour chaque script ajouté).
En prime, nous pouvons utiliser le plugin babel de webpack pour exécuter babel sur le code des anciens navigateurs et encore une fois, nous n'avons pas non plus à maintenir ce script de construction.
Notez que si Chrome (notre navigateur de choix) a commencé à prendre en charge import
pour de vrai, nous passerions probablement à cela pour le développement, mais cela ne changerait vraiment rien. Nous pourrions toujours utiliser webpack pour créer un fichier concaténé et nous pourrions l'utiliser pour exécuter babel sur le code pour tous les navigateurs.
Tout cela est gagné en n'utilisant pas de balises de script et en utilisant AMD