RequireJS




Julien Roche

Human Talks Grenoble – le 13/11/2012
Speaker


     Julien Roche                            @rochejul



     Ingénieur d’étude et formateur sur Java, Web et Web
      Mobile pour Objet Direct

     Ancien commiter du projet OpenSource “wiQuery”




     Expérience Web Mobile depuis 2 ans

     Auteur de formations sur HTML5 et le Web Mobile
     Référent HTML5 et Web Mobile

2
La grande question sur la vie, l'univers et le
    reste


        Comment devons-nous charger nos fichiers
         JavaScripts ?
           ●Dans la balise HEAD ?

           ●En bas de la balise BODY ?

           ●En utilisant les attributs async (HTML5) ou defer
            ?
              • Async: chargement asynchrone
              • Defer: chargement asynchrone avec garantie que le
                « document ready » soit déclenché à la fin du chargement des
                fichiers


           ●Via JavaScript, en injectant un nœud ?

           ●Via JavaScript, en injectant un nœud, au
            moment de l’événement « Load », en utilisant
            « defer » ?
3
La réponse


    Cela dépend de l’application, du besoin …




                                                … mais le dernier point semble être le bon


http://blog.blary.be/analyse-diff%C3%A9rentes-fa%C3%A7ons-dint%C3%A9grer-un-script-javascript

4
Et si on allait plus loin ?


     Ne pourrions nous pas avoir un framework qui fasse du
      chargement asynchrone
       ●Chargement optimisé

     Mais également
       ●Une gestion de dépendances ?
       ●Un chargement des templates ?
       ●Une gestion de l’internalisation ?

     Et qui soit léger ?

     Une solution: RequireJS




5
RequireJS


     Github: https://github.com/jrburke/requirejs
     Documentation: http://requirejs.org/

     Compatible sur la quasi-totalité des navigateurs
       ●IE6+
       ●Firefox 2+
       ●Safari 3.2+, Chrome 3+
       ●Opera 10+


     Repose sur l’AMD:
       ●Asynchronous Module Definition
          • https://github.com/amdjs/amdjs-api/wiki/AMD

       ●Repose sur deux méthodes:
          • Define
          • Require



6
Déclencheur et configuration


     Pour utiliser RequireJS, nous devons le placer dans le
      header de la page HTML …
    <script data-main="javascripts/app" src="javascripts/frameworks/require.min.js"></script>




     … tout en précisant le fichier JavaScript de configuration
     Un exemple de contenu:

    /* First, we define shortcuts */
    require.config({
        paths: {
            "Model":            "./require-model",
            "View":             "./require-view"
        }
    });

    /* Now, the core of our application */
    require(
        ["Model", "View"],
        function(Model, View){
            // Do something
        }
    );

7
Define


     Permet de définir un module

     La méthode va contenir entre deux et trois paramètres
             ●Un tableau de dépendances, et le corps du module
             ●Un nom, un tableau de dépendances et le corps du module
                  • Bonne pratique: mettre le nom du module en minuscule !
                  • Le tableau de dépendances peut
                       – soit utiliser des raccourcis,
                       – soit être un chemin relatif vers le fichier JavaScript (en omettant à la fin le ‘.js’).

     Le corps du module peut renvoyer un objet.
             ●Quand celui-ci sera appelé, il sera passé en paramètre du corps
              du module.
    define(
        "mymodule"
        ["mypreviousmodule", "myanotherpreviousmodule"],
        function(a, b){
            // Do something

             // Return something
             return { "a": "a" };
         }
    );

8
Require


     Permet d’exiger le chargement immédiat des modules

     Prend en paramètre un tableau de dépendances et un
      corps de module
    require(
        ["Underscore", "jquery", "Backbone", "Model", "View", "Bootstrap"],
        function(_, $, Backbone, Model, View){
            // Do something
        }
    );




     Il est à noter que nous ne sommes pas obligés de faire une
      application entièrement en RequireJS.
          ●Nous pouvons n’utiliser que RequireJS pour charger des fichiers



9
Ordre


      Parfois, il est important de charger des modules dans un
       certain ordre
           ●Par exemple, pour le framework BackboneJS, il faut que
            UnderscoreJS et jQuery soient chargés avant

      Etant donné que le chargement se fait habituellement de
       manière asynchrone (non garant de l’ordre), il faut
       l’obliger en utilisant la propriété « shim »
     require.config({
         paths: {
             "jquery":            "./frameworks/jquery-1.8.1.min",
             "Underscore":        "./frameworks/underscore.min",
             "Backbone":          "./frameworks/backbone.min"
         },
         // To force ordered loading. See https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim
         shim: {
             "Backbone": {
                  deps: ["Underscore", "jquery"], //These script dependencies should be loaded before loading Backbone
                  exports: "Backbone" //Once loaded, use the global 'Backbone' as the module value.
             },
             "Underscore": { exports: "_" },
             "jquery": { exports: "jQuery" }
         }
     });


10
Système à base de plugins


      Il est possible d’écrire un plugin pour RequireJS

      Il en existe certains de base, comme
           ●« text », pour importer le contenu de fichier
                 • Utile pour le templating


           ●« i18n », pour l’internalisation

      Exemple d’utilisation
     require.config({
         paths: {
             "template":         "../templates",
             "text":             "../frameworks/text.min"
         }
     });

     require(
         ["text!../template/view-main.html"],
         function(templateMain){
             // Do what you want
         }
     );



11
Rendre son framework compatible AMD


      Pour rendre son framework compatible amd, il suffit de
       détecter que
           ●« define » soit bien une fonction
           ●Et que « define.amd » soit bien définie


      Un exemple concret:
     (function(){
         function myModule($){
             return { "a": "a" };
         };

         if (typeof define === "function" && define.amd ) {
             define(
                 "mymodule",
                 ["jquery"],
                 myModule
             );

         } else if(window.jQuery) {
             myModule(jQuery);
         }
     })();




12
Optimisation


      RequireJS a un plugin NodeJS permettant
          ●De concaténer et de minifier les fichiers JavaScripts
          ●http://requirejs.org/docs/optimization.html

      Et cela en respectant l’ordre de chargement des modules
       et de leurs dépendances
          ●https://github.com/jrburke/r.js

      Il suffit alors de l’installer
     > npm install -g requirejs




      Et de le lancer soit sur le module qui nous intéresse, soit
       sur toute l’application
     > node ../../r.js -o baseUrl=. paths.requireLib=../../require name=main include=requireLib out=main-built.js




13
Intérêts de RequireJS


               Maintenabilité

               Gestion de dépendances

               Industrialisation
                 ● tests unitaires

                 ●Passage du mode dev au mode
                  production




14

Aperçu de RequireJS

  • 1.
    RequireJS Julien Roche Human TalksGrenoble – le 13/11/2012
  • 2.
    Speaker  Julien Roche @rochejul  Ingénieur d’étude et formateur sur Java, Web et Web Mobile pour Objet Direct  Ancien commiter du projet OpenSource “wiQuery”  Expérience Web Mobile depuis 2 ans  Auteur de formations sur HTML5 et le Web Mobile  Référent HTML5 et Web Mobile 2
  • 3.
    La grande questionsur la vie, l'univers et le reste  Comment devons-nous charger nos fichiers JavaScripts ? ●Dans la balise HEAD ? ●En bas de la balise BODY ? ●En utilisant les attributs async (HTML5) ou defer ? • Async: chargement asynchrone • Defer: chargement asynchrone avec garantie que le « document ready » soit déclenché à la fin du chargement des fichiers ●Via JavaScript, en injectant un nœud ? ●Via JavaScript, en injectant un nœud, au moment de l’événement « Load », en utilisant « defer » ? 3
  • 4.
    La réponse Cela dépend de l’application, du besoin … … mais le dernier point semble être le bon http://blog.blary.be/analyse-diff%C3%A9rentes-fa%C3%A7ons-dint%C3%A9grer-un-script-javascript 4
  • 5.
    Et si onallait plus loin ?  Ne pourrions nous pas avoir un framework qui fasse du chargement asynchrone ●Chargement optimisé  Mais également ●Une gestion de dépendances ? ●Un chargement des templates ? ●Une gestion de l’internalisation ?  Et qui soit léger ?  Une solution: RequireJS 5
  • 6.
    RequireJS  Github: https://github.com/jrburke/requirejs  Documentation: http://requirejs.org/  Compatible sur la quasi-totalité des navigateurs ●IE6+ ●Firefox 2+ ●Safari 3.2+, Chrome 3+ ●Opera 10+  Repose sur l’AMD: ●Asynchronous Module Definition • https://github.com/amdjs/amdjs-api/wiki/AMD ●Repose sur deux méthodes: • Define • Require 6
  • 7.
    Déclencheur et configuration  Pour utiliser RequireJS, nous devons le placer dans le header de la page HTML … <script data-main="javascripts/app" src="javascripts/frameworks/require.min.js"></script>  … tout en précisant le fichier JavaScript de configuration  Un exemple de contenu: /* First, we define shortcuts */ require.config({ paths: { "Model": "./require-model", "View": "./require-view" } }); /* Now, the core of our application */ require( ["Model", "View"], function(Model, View){ // Do something } ); 7
  • 8.
    Define  Permet de définir un module  La méthode va contenir entre deux et trois paramètres ●Un tableau de dépendances, et le corps du module ●Un nom, un tableau de dépendances et le corps du module • Bonne pratique: mettre le nom du module en minuscule ! • Le tableau de dépendances peut – soit utiliser des raccourcis, – soit être un chemin relatif vers le fichier JavaScript (en omettant à la fin le ‘.js’).  Le corps du module peut renvoyer un objet. ●Quand celui-ci sera appelé, il sera passé en paramètre du corps du module. define( "mymodule" ["mypreviousmodule", "myanotherpreviousmodule"], function(a, b){ // Do something // Return something return { "a": "a" }; } ); 8
  • 9.
    Require  Permet d’exiger le chargement immédiat des modules  Prend en paramètre un tableau de dépendances et un corps de module require( ["Underscore", "jquery", "Backbone", "Model", "View", "Bootstrap"], function(_, $, Backbone, Model, View){ // Do something } );  Il est à noter que nous ne sommes pas obligés de faire une application entièrement en RequireJS. ●Nous pouvons n’utiliser que RequireJS pour charger des fichiers 9
  • 10.
    Ordre  Parfois, il est important de charger des modules dans un certain ordre ●Par exemple, pour le framework BackboneJS, il faut que UnderscoreJS et jQuery soient chargés avant  Etant donné que le chargement se fait habituellement de manière asynchrone (non garant de l’ordre), il faut l’obliger en utilisant la propriété « shim » require.config({ paths: { "jquery": "./frameworks/jquery-1.8.1.min", "Underscore": "./frameworks/underscore.min", "Backbone": "./frameworks/backbone.min" }, // To force ordered loading. See https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim shim: { "Backbone": { deps: ["Underscore", "jquery"], //These script dependencies should be loaded before loading Backbone exports: "Backbone" //Once loaded, use the global 'Backbone' as the module value. }, "Underscore": { exports: "_" }, "jquery": { exports: "jQuery" } } }); 10
  • 11.
    Système à basede plugins  Il est possible d’écrire un plugin pour RequireJS  Il en existe certains de base, comme ●« text », pour importer le contenu de fichier • Utile pour le templating ●« i18n », pour l’internalisation  Exemple d’utilisation require.config({ paths: { "template": "../templates", "text": "../frameworks/text.min" } }); require( ["text!../template/view-main.html"], function(templateMain){ // Do what you want } ); 11
  • 12.
    Rendre son frameworkcompatible AMD  Pour rendre son framework compatible amd, il suffit de détecter que ●« define » soit bien une fonction ●Et que « define.amd » soit bien définie  Un exemple concret: (function(){ function myModule($){ return { "a": "a" }; }; if (typeof define === "function" && define.amd ) { define( "mymodule", ["jquery"], myModule ); } else if(window.jQuery) { myModule(jQuery); } })(); 12
  • 13.
    Optimisation  RequireJS a un plugin NodeJS permettant ●De concaténer et de minifier les fichiers JavaScripts ●http://requirejs.org/docs/optimization.html  Et cela en respectant l’ordre de chargement des modules et de leurs dépendances ●https://github.com/jrburke/r.js  Il suffit alors de l’installer > npm install -g requirejs  Et de le lancer soit sur le module qui nous intéresse, soit sur toute l’application > node ../../r.js -o baseUrl=. paths.requireLib=../../require name=main include=requireLib out=main-built.js 13
  • 14.
    Intérêts de RequireJS  Maintenabilité  Gestion de dépendances  Industrialisation ● tests unitaires ●Passage du mode dev au mode production 14