Je voudrais utiliser requireJS et j'utilise jQuery. Je ne veux pas utiliser la version combinée de requireJS et jQuery puisque je n'utilise pas la dernière version de jQuery. Quelle est la meilleure façon pour moi de travailler avec requireJS ?
Réponses
Trop de publicités?C'est aussi ma question ! Je dois aussi utiliser un ancien jQuery, mais aussi des bibliothèques javascript plus "traditionnelles". Quelle est la meilleure technique pour faire cela ? (Je peux modifier votre question pour la rendre plus large si cela ne vous dérange pas.) Voici ce que j'ai appris.
L'auteur de RequireJS, James Burke, a expliqué le principe de la avantages du fichier combiné RequireJS + jQuery . Vous obtenez deux choses.
-
Un module,
jquery
est disponible, et c'est l'objet jQuery. C'est sûr :// My module depends on jQuery but what if $ was overwritten? define(["jquery"], function($) { // $ is guaranteed to be jQuery now */ })
-
jQuery est déjà chargé avant toute
require()
odefine()
truc. Tous les modules sont garantis que jQuery est prêt. Vous n'avez même pas besoin durequire/order.js
puisque jQuery a été codé en dur pour se charger en premier.
Pour moi, le numéro 2 n'est pas très utile. La plupart des applications réelles ont beaucoup de .js
les fichiers qui doit le chargement dans le bon ordre - triste mais vrai. Dès que vous avez besoin de Sammy ou de Underscore.js, le fichier combiné RequireJS+jQuery ne vous aide pas.
Ma solution est d'écrire de simples wrappers RequireJS qui chargent mes scripts traditionnels en utilisant le plugin "order".
Ejemplo
Supposons que mon application comporte les composants suivants (par dépendance).
- Mon application, super application
- greatapp dépend d'une jquery (ancienne version que je dois utiliser)
- greatapp dépend de ma_sammy (SammyJS plus tous ses plugins que je dois utiliser). Ces doit être en ordre
- my_sammy dépend de jquery (SammyJS est un plugin jQuery)
- my_sammy dépend de sammy.js
- my_sammy dépend de sammy.json.js
- my_sammy dépend de sammy.storage.js
- my_sammy dépend de sammy.mustache.js
Dans mon esprit, tout ce qui est au-dessus se termine par .js
est un script "traditionnel". Tout ce qui est sans .js
est un plugin RequireJS. La clé est la suivante : les éléments de haut niveau (greatapp, my_sammy) sont des modules, et à des niveaux plus profonds, on retombe sur le traditionnel .js
des fichiers.
Démarrer
Tout commence par un booter qui dit à RequireJS comment démarrer.
<html>
<head>
<script data-main="js/boot.js" src="js/require.js"></script>
</head>
</html>
En js/boot.js
Je n'ai mis que la configuration et comment démarrer l'application.
require( // The "paths" maps module names to actual places to fetch the file.
// I made modules with simple names (jquery, sammy) that will do the hard work.
{ paths: { jquery: "require_jquery"
, sammy : "require_sammy"
}
}
// Next is the root module to run, which depends on everything else.
, [ "greatapp" ]
// Finally, start my app in whatever way it uses.
, function(greatapp) { greatapp.start(); }
);
Application principale
En greatapp.js
J'ai un module d'apparence normale.
define(["jquery", "sammy"], function($, Sammy) {
// At this point, jQuery and SammyJS are loaded successfully.
// By depending on "jquery", the "require_jquery.js" file will run; same for sammy.
// Those require_* files also pass jQuery and Sammy to here, so no more globals!
var start = function() {
$(document).ready(function() {
$("body").html("Hello world!");
})
}
return {"start":start};
}
Des enveloppes de modules RequireJS autour de fichiers traditionnels
require_jquery.js
:
define(["/custom/path/to/my/jquery.js?1.4.2"], function() {
// Raw jQuery does not return anything, so return it explicitly here.
return jQuery;
})
require_sammy.js
:
// These must be in order, so use the "order!" plugin.
define([ "order!jquery"
, "order!/path/to/custom/sammy/sammy-0.6.2-min.js"
, "order!/path/to/custom/sammy/plugins/sammy.json-0.6.2-min.js"
, "order!/path/to/custom/sammy/plugins/sammy.storage-0.6.2-min.js"
, "order!/path/to/custom/sammy/plugins/sammy.mustache-0.6.2-min.js"
]
, function($) {
// Raw sammy does not return anything, so return it explicitly here.
return $.sammy;
}
);
Cette question date d'au moins deux ans maintenant, mais j'ai remarqué que c'est un problème qui se pose toujours avec RequireJS 2.0 (require-jquery.js utilise jQuery 1.8.0, mais la dernière version est 1.8.2).
Si vous voyez cette question, notez que require-jquery.js est maintenant juste require.js et jquery.js, mélangés ensemble. Vous pouvez simplement modifier le fichier require-jquery.js et remplacer les parties relatives à jQuery par une version plus récente. .
Mise à jour (30 mai 2013) : Maintenant que RequireJS dispose de paths et de shim, il y a une nouvelle façon d'importer jQuery et les plugins jQuery, et l'ancienne méthode n'est plus nécessaire ni recommandé . Voici une version abrégée de la méthode actuelle :
requirejs.config({
"paths": {
"jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
}
});
define(["jquery"], function($) {
$(function() {
});
});
Véase http://requirejs.org/docs/jquery.html pour plus d'informations.
J'ai trouvé la réponse de JasonSmith extrêmement utile, probablement plus que la documentation de RequireJS.
Cependant, il existe un moyen d'optimiser ce système pour éviter d'avoir des requêtes AJAX séparées pour les (petits) modules de déclaration de définition ("require_jquery" "require_sammy"). Je soupçonne r.js de le faire au stade de l'optimisation, mais vous pouvez le faire à l'avance afin de ne pas vous battre avec le système Path, BaseURI.
index.html :
<html>
<head>
<script data-main="js/loader.js" src="js/require.js"></script>
</head>
</html>
loader.js :
// We are going to define( dependencies by hand, inline.
// There is one problem with that through (inferred from testing):
// Dependencies are starting to load (and execute) at the point of declaring the inline
// define, not at the point of require(
// So you may want to nest the inline-defines inside require(
// this is, in a way, short replacement for Order plug in, but allows you to use
// hand-rolled defines, which the Order plug in, apparently does not allow.
var jQueryAndShims = ['jquery']
if(window.JSON == null){
jQueryAndShims.push('json2')
define(
'json2'
, ['js/libs/json2.min.js']
, function() {
return window.JSON
}
)
}
// will start loading the second we define it.
define(
'jquery'
, ['js/libs/jquery_custom.min.js']
, function() {
// we just pick up global jQuery here.
// If you want more than one version of jQuery in dom, read a more complicated solution discussed in
// "Registering jQuery As An Async-compatible Module" chapter of
// http://addyosmani.com/writing-modular-js/
return window.jQuery
}
)
// all inline defines for resources that don't rely on other resources can go here.
// First level require(
// regardless of depends nesting in 'myapp' they will all start downloading
// at the point of define( and exec whenever they want,
// async in many browsers. Actually requiring it before the nested require makes
// sure jquery had *executed and added jQuery to window object* before
// all resolved depends (jquery plugins) start firing.
require(jQueryAndShims, function($) {
// will start loading the second we define it.
define(
'sammy_and_friends'
, ['jquery','js/libs/jquery_pluginone.min.js','js/libs/jquery_plugintwo.min.js','js/libs/sammy.min.js']
, function($) {
// note, all plugins are unaltered, as they are shipped by developers.
// in other words, they don't have define(.. inside.
// since they augment global $ (window.jQuery) anyway, and 'jquery' define above picks it up
// , we just keep on returning it.
// Sammy is attached to $ as $.sammy, so returning just Sammy makes little sense
return $
}
)
// second level require - insures that Sammy (and other jQuery plugins) - 'sammy_and_friends' - is
// loaded before we load Sammy plugins. I normally i would inline all sammy plugins i need
// (none, since i use none of them preferring jQuery's direct templating API
// and no other Sammy plug in is really of value. ) right into sammy.js file.
// But if you want to keep them separate:
require(['sammy_and_friends'], function() {
// will start loading the second we define it.
define(
'sammy_extended'
, ['sammy_and_friends','js/libs/sammy_pluginone.min.js','js/libs/sammy_plugintwo.min.js']
, function($) {
// as defined above, 'sammy_and_friends' actually returns (globall) jQuery obj to which
// Sammy is attached. So we continue to return $
return $
}
)
// will start loading the second we define it.
define(
'myapp'
, ['sammy_extended', 'js/myapplication_v20111231.js']
, function($, myapp_instantiator) {
// note, myapplication may, but does not have to contain RequireJS-compatible define
// that returns something. However, if it contains something like
// "$(document).ready(function() { ... " already it MAY fire before
// it's depends - 'sammy_extended' is fully loaded.
// Insdead i recommend that myapplication.js returns a generator
// (app-object-generating function pointer)
// that takes jQuery (with all loaded , applied plugins)
// The expectation is that before the below return is executed,
// all depends are loaded (in order of depends tree)
// You would init your app here like so:
return myapp_instantiator($)
// then "Run" the instance in require( as shown below
}
)
// Third level require - the one that actually starts our application and relies on
// dependency pyramid stat starts with jQuery + Shims, followed by jQuery plugins, Sammy,
// followed by Sammy's plugins all coming in under 'sammy_extended'
require(['jquery', 'myapp'], function($, myappinstance) {
$(document).ready(function() {myappinstance.Run()})
})
}) // end of Second-level require
}) // end of First-level require
enfin, monapplication.js :
// this define is a double-wrap.
// it returns application object instantiator that takes in jQuery (when it's available) and , then, that
// instance can be "ran" by pulling .Run() method on it.
define(function() {
// this function does only two things:
// 1. defines our application class
// 2. inits the class and returns it.
return function($) {
// 1. defining the class
var MyAppClass = function($) {
var me = this
this._sammy_application = $.sammy(function() {
this.raise_errors = true
this.debug = true
this.run_interval_every = 300
this.template_engine = null
this.element_selector = 'body'
// ..
})
this._sammy_application.route(...) // define your routes ets...
this.MyAppMethodA = function(blah){log(blah)} // extend your app with methods if you want
// ...
// this one is the one we will .Run from require( in loader.js
this.Run = function() {
me._sammy_application.run('#/')
}
}
// 2. returning class's instance
return new MyAppClass($) // notice that this is INITED app, but not started (by .Run)
// .Run will be pulled by calling code when appropriate
}
})
Cette structure (remplace vaguement (duplique ?) le plugin Order de RequireJS, mais) vous permet d'élaguer le nombre de fichiers dont vous avez besoin pour AJAX, en ajoutant plus de contrôle à la définition des dépendances et de l'arbre de dépendance.
Il y a également un avantage important à charger jQuery séparément (qui vient généralement à 100k) - vous pouvez contrôler la mise en cache sur le serveur, ou mettre jQuery en cache dans le localStorage du navigateur. Jetez un œil au projet AMD-Cache ici. https://github.com/jensarps/AMD-cache puis changez les instructions define( pour inclure "cache !": et il sera (pour toujours :) ) bloqué dans le navigateur de l'utilisateur.
define(
'jquery'
, ['cache!js/libs/jquery_old.min.js']
, function() {
// we just pick up global jQuery here.
// If you want more than one version of jQuery in dom, read a more complicated solution discussed in
// "Registering jQuery As An Async-compatible Module" chapter of
// http://addyosmani.com/writing-modular-js/
return window.jQuery
}
)
Note sur jQuery 1.7.x+ Il ne s'attache plus à l'objet window, donc ce qui précède ne fonctionnera PAS avec un fichier jQuery 1.7.x+ non modifié. Vous devez personnaliser votre fichier jquery**.js pour inclure ceci avant la fermeture "})( window ) ;":
;window.jQuery=window.$=jQuery
Si vous avez des erreurs "jQuery undefined" dans la console, c'est un signe que la version de jQuery que vous utilisez ne s'attache pas à la fenêtre.
Code licence : Domaine public.
Divulgations : Le code JavaScript ci-dessus sent le "pseudo-code" car il s'agit d'une paraphrase (élagage manuel) d'un code de production beaucoup plus détaillé. Le code présenté ci-dessus n'est pas garanti de fonctionner et n'a PAS été testé pour fonctionner comme présenté. Audit, testez-le. Les points-virgules ont été volontairement omis, car ils ne sont pas requis par la spécification JS et le code est mieux sans eux.
En plus de la réponse de jhs, voir les instructions plus récentes sur le site de la Commission européenne. page github de require-jquery du fichier README.md. Il couvre à la fois l'approche la plus simple, qui consiste à utiliser un fichier jquery/require.js combiné, et la manière d'utiliser un fichier jquery.js distinct.