我如何一起使用 requireJS 和 jQuery?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4535926/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I use requireJS and jQuery together?
提问by Naor
I would like to use requireJS and I am using jQuery. I don't want to use the combined version of requireJS and jQuery since I am not using the latest jQuery version. What is the best way for me to work with requireJS?
我想使用 requireJS 并且我正在使用 jQuery。我不想使用 requireJS 和 jQuery 的组合版本,因为我没有使用最新的 jQuery 版本。我使用 requireJS 的最佳方式是什么?
回答by JasonSmith
That is my exact question too! I also must use an older jQuery, but also more "traditional" javascript libraries. What is the best technique to do that? (I may edit your question to make it more broad if you don't mind.) Here is what I learned.
这也是我的确切问题!我还必须使用较旧的 jQuery,但也必须使用更“传统”的 javascript 库。做到这一点的最佳技术是什么?(如果您不介意,我可以编辑您的问题以使其更广泛。)这是我学到的。
RequireJS author, James Burke, explained the advantages of the combined RequireJS + jQuery file. You get two things.
RequireJS 作者 James Burke 解释了RequireJS + jQuery 文件组合的优点。你得到两件事。
A module,
jquery
, is available, and it's the jQuery object. This is safe:// My module depends on jQuery but what if $ was overwritten? define(["jquery"], function($) { // $ is guaranteed to be jQuery now */ })
jQuery is already loaded before any
require()
ordefine()
stuff. All modules are guaranteed that jQuery is ready. You don't even need therequire/order.js
plugin since jQuery was basically hard-coded to load first.
模块 ,
jquery
可用,它是 jQuery 对象。这是安全的:// My module depends on jQuery but what if $ was overwritten? define(["jquery"], function($) { // $ is guaranteed to be jQuery now */ })
jQuery是之前任何已加载
require()
或define()
东西。所有模块都保证 jQuery 已准备就绪。你甚至不需要require/order.js
插件,因为 jQuery 基本上是硬编码的,可以先加载。
To me, #2 isn't very helpful. Most real applications have many.js
files that mustload in the right order—sad but true. As soon as you need Sammy or Underscore.js, the combined RequireJS+jQuery file doesn't help.
对我来说,#2 不是很有帮助。大多数真实的应用程序都有许多.js
文件必须以正确的顺序加载——令人遗憾但真实。只要您需要 Sammy 或 Underscore.js,组合的 RequireJS+jQuery 文件就无济于事。
My solution is to write simple RequireJS wrappers that load my traditional scripts using the "order" plugin.
我的解决方案是编写简单的 RequireJS 包装器,使用“order”插件加载我的传统脚本。
Example
例子
Suppose my app has these components (by dependency).
假设我的应用程序具有这些组件(通过依赖项)。
- My app, greatapp
- greatapp depends on a custom jquery(old version I must use)
- greatapp depends on my_sammy(SammyJS plus all its plugins I must use). These must be in order
- my_sammy depends on jquery(SammyJS is a jQuery plugin)
- my_sammy depends on sammy.js
- my_sammy depends on sammy.json.js
- my_sammy depends on sammy.storage.js
- my_sammy depends on sammy.mustache.js
- 我的应用程序,很棒的应用程序
- greatapp 依赖于自定义jquery(我必须使用旧版本)
- greatapp 依赖于my_sammy(SammyJS 加上我必须使用的所有插件)。这些必须是有序的
- my_sammy 依赖于jquery(SammyJS 是一个 jQuery 插件)
- my_sammy 依赖于sammy.js
- my_sammy 依赖于sammy.json.js
- my_sammy 依赖于sammy.storage.js
- my_sammy 依赖于sammy.mustache.js
In my mind, everything above that ends with .js
is a "traditional" script. Everything without .js
is a RequireJS plugin. The key is: high-level stuff (greatapp, my_sammy) are modules, and at deeper levels, it falls back to traditional .js
files.
在我看来,以上结尾的一切.js
都是“传统”脚本。没有的一切.js
都是 RequireJS 插件。关键是:高层次的东西(greatapp,my_sammy)是模块,在更深层次上,它回退到传统.js
文件。
Booting
开机
It all starts with a booter telling RequireJS how to start.
这一切都始于一个引导程序告诉 RequireJS 如何启动。
<html>
<head>
<script data-main="js/boot.js" src="js/require.js"></script>
</head>
</html>
In js/boot.js
I put only the config and how to start the application.
在js/boot.js
我只放了配置和如何启动应用程序。
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(); }
);
Main Application
主要应用
In greatapp.js
I have a normal looking module.
在greatapp.js
我有一个正常的模块。
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};
}
RequireJS module wrappers around traditional files
RequireJS 模块包装器围绕传统文件
require_jquery.js
:
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
:
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;
}
);
回答by Chris
This question is at least two years old now, but I noticed this is a problem still with RequireJS 2.0 (require-jquery.js uses jQuery 1.8.0, but the latest version is 1.8.2).
这个问题现在至少已经两年了,但我注意到 RequireJS 2.0 仍然存在这个问题(require-jquery.js 使用 jQuery 1.8.0,但最新版本是 1.8.2)。
If you happen to see this question, note that require-jquery.js is now just require.js and jquery.js, mashed together.You can just edit require-jquery.js and replace the the jQuery parts with a newer version.
如果你碰巧看到这个问题,请注意require-jquery.js 现在只是 require.js 和 jquery.js,混合在一起。您可以编辑 require-jquery.js 并用更新的版本替换 jQuery 部分。
Update (May 30, 2013): Now that RequireJS has paths and shim, there is a new way to import jQuery and jQuery plugins, and the old method is no longer necessary nor recommended. Here is an abridged version of the current method:
更新(2013 年 5 月 30 日):现在 RequireJS 有了路径和 shim,导入 jQuery 和 jQuery 插件有了新方法,不再需要也不推荐使用旧方法。这是当前方法的删节版:
requirejs.config({
"paths": {
"jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
}
});
define(["jquery"], function($) {
$(function() {
});
});
See http://requirejs.org/docs/jquery.htmlfor more info.
有关更多信息,请参阅http://requirejs.org/docs/jquery.html。
回答by tkdave
I've found the best approach is to keep jQuery outside of my RequireJS build.
我发现最好的方法是将 jQuery 保留在我的 RequireJS 构建之外。
Just include jquery.min.js in your HTML. Then, make a jquery.js file with something like this...
只需在 HTML 中包含 jquery.min.js。然后,用这样的东西制作一个 jquery.js 文件......
define([], function() {
return window.$;
});
回答by ddotsenko
Found JasonSmith's anwer tremendously helpful, probably more so than the RequireJS's documentation.
发现 JasonSmith 的回答非常有帮助,可能比 RequireJS 的文档更有帮助。
However, there is way to optimize on it to avoid having separate AJAX requests for (tiny) define-declaring modules ("require_jquery" "require_sammy"). I would suspect r.js would do it at optimization stage, but you can do that ahead of time in order not to fight with Path, BaseURI system.
但是,有一种方法可以对其进行优化,以避免对(微小的)定义声明模块(“require_jquery”“require_sammy”)产生单独的 AJAX 请求。我怀疑 r.js 会在优化阶段做到这一点,但你可以提前做到这一点,以免与 Path、BaseURI 系统发生冲突。
index.html:
索引.html:
<html>
<head>
<script data-main="js/loader.js" src="js/require.js"></script>
</head>
</html>
loader.js:
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
finally, myapplication.js:
最后,myapplication.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
}
})
This structure (loosely replaces (duplicates?) RequireJS's Order plugin, but) allows you to prune the number of files you need to AJAX, adding more control to definition of depends and depend tree.
这种结构(松散地替换(重复?)RequireJS 的 Order 插件,但是)允许您修剪 AJAX 所需的文件数量,为依赖树和依赖树的定义添加更多控制。
There is also a large bonus to loading jQuery separately (which usually comes at 100k) - you can control caching at server, or cache jQuery into browser's localStorage. Take a look at AMD-Cache project here https://github.com/jensarps/AMD-cachethen change the define( statements to include "cache!": and it will be (forever :) ) stuck in user's browser.
单独加载 jQuery(通常为 100k)还有一个很大的好处——你可以控制服务器上的缓存,或者将 jQuery 缓存到浏览器的 localStorage 中。在此处查看 AMD-Cache 项目https://github.com/jensarps/AMD-cache然后更改定义(语句以包含“缓存!”:它将(永远:))卡在用户的浏览器中。
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 about jQuery 1.7.x+ It no longer attaches itself to window object, so the above will NOT work with unmodified jQuery 1.7.x+ file. There you must customize your jquery**.js to include this before the closing "})( window );":
关于 jQuery 1.7.x+ 的注意事项 它不再将自身附加到 window 对象,因此上述内容不适用于未修改的 jQuery 1.7.x+ 文件。在那里您必须自定义您的 jquery**.js 以在关闭“})( window );”之前包含它:
;window.jQuery=window.$=jQuery
If you have "jQuery undefined" errors in console, it's a sign jQuery version you are using is not attaching itself to window.
如果您在控制台中有“jQuery 未定义”错误,则表明您使用的 jQuery 版本未将自身附加到窗口。
Code license: Public domain.
代码许可:公共领域。
Disclosures: JavaScript above smells of "pseudo-code" as it is a paraphrasing (hand-pruning) of much more detailed production code. Code as presented above is not guaranteed to work and was NOT tested to work as presented. Audit, test it. Semicolons omitted on purpose, as they are not required per JS spec and code looks better without them.
披露:JavaScript 上面有“伪代码”的味道,因为它是更详细的生产代码的释义(手工修剪)。上面提供的代码不能保证正常工作,也没有经过测试可以正常工作。审核,测试。分号是故意省略的,因为根据 JS 规范不需要分号,而且没有分号代码看起来会更好。
回答by Paul Beusterien
In addition to jhs's answer, see the more recent instructions on the require-jquery github pagefrom the README.md file. It covers both the simplest approach of using a combined jquery/require.js file and also how to use a separate jquery.js.
除了 jhs 的回答,请参阅README.md 文件中require-jquery github 页面上的最新说明。它涵盖了使用组合 jquery/require.js 文件的最简单方法以及如何使用单独的 jquery.js。