I'm just starting to use require.js and think it's great. However, I would like to use it as much as possible instead of dealing with <script> tags in my HTML files.
To that end, is it possible to work with a 3rd party library that doesn't have any define modules in it? This may be asking much I realize but is there a way to call...
require(["3rd_party"], function(3rd) {
});
...where 3rd_party.js is a script located in a js folder that require knows to look in? I know require has mapping libraries, things like require-jquery but wasn't sure if it's possible to use it out of the box with older utility libraries that weren't built with it in mind.
RequireJS 2.1.0 added the shim config element which allows using non-AMD 3rd party libraries like AMD modules.
In your case it would be something like:
shim: {
'3rd_party': {
exports: '{the-global-name}' // what variable does the library
// export to the global scope?
}
}
This mechanism makes custom-build library wrappers like "require-jquery" pretty much obsolete.
More details in the RequireJS docs
Related
Currently I am using Marionette which registers itself as an AMD module called "marionette". Before it gets loaded into other modules, I want to set some configurations on it. My only thought as of now is to do this:
// configuredMarionette.js
define(["marionette"], function(Marionette) {
// modify Marionette here
return Marionette;
});
Then, in each of my modules that need marionette, I set "configuredMarionette" as the dependency instead of "marionette" so that I get the configured version. Is there any other way around this that is cleaner?
It may be more useful if you rename 'configuredMarionette' to 'marionette' and use 'orignalMarionette' for original one.
It will be easy to use any other module which has a dependency to 'marionette' to use configured one.
I'm trying to just load the event_broker module in the chaplinjs . I am able to to do by doing something like
require(["underscore", "chaplin"], function(_, chaplin)
{
var eventBroker = _({}).extend(chaplin.EventBroker);
});
But, this is not good enough in my case. I need to be able to load the event_broker module synchronously. I know that is what require designed to do. Is there a way to do that?
I know that is what require designed to do.
No, that's not what RequireJS is designed to do. (Did you forget to put "not" in there?) RequireJS is designed to load modules asynchronously.
I would normally suggest loading Chaplin through a script element because that would be synchronous but, after looking at the code of Chaplin, I see that it fails with throw new Error('Chaplin requires Common.js or AMD modules'); if it does not detect a CommonJS or AMD environment.
Almond can be used to load bundles of AMD modules synchronously so this may be an option for you.
I'm working on the project that uses require.js and I was faced with a simple question about declaring libraries as dependencies within every single modules. I saw many examples with require.js and in every of them libraries like Backbone, jquery, underscore etc was declared in every module. And it would be fine if your application consists of only couple of modules. But if your application has 40-50 modules it becomes a bit tedious to define jquery every single time.
On the other hand we can load all libraries into the require() this way:
// Just an example
require.config({
paths: {
jquery: '../bower_components/jquery/jquery',
underscore: '../bower_components/underscore/underscore',
backbone: '../bower_components/backbone/backbone'
}
});
require(['jquery', 'underscore', 'backbone'], function () {
require([
'app',
'bootstrap'
], function (App) {
var app = new App();
document.body.appendChild(app.el);
});
});
And then we can use Backbone, '_' and '$' into the App without declaring them as dependencies.
So I'm trying to understand why we should define them every time. Is it just a strict adherence to the Module pattern or something else?
Thanks.
Having your libraries passed in as arguments to your require factory function is a form of dependency injection. Now, depending on exactly how AMD-friendly your library dependencies are, you may even be able to use several different versions of the library at once in an application. Writing your modules in this way with explicit library dependencies can allow you future flexibility of mixing modules which require jQuery 1.8 and jQuery 2.0, for instance. A different jQuery version can be passed to each module.
When you don’t define all your dependencies explicitly every time, then you’re relying on the global variable (window.$ or window._) created as a side effect of loading the library. In that case, all the modules have to depend on the same version of the library.
I have a built library (concatenated, minified and included before require.js) of several globals (jQuery + plugins, constructor functions, etc ). This library is used as a base on which apps are built on top of, with assumed dependencies. i.e, if I include my app scripts after the library, then I can freely use jQuery and constructors without any issues.
For bigger apps I'm considering using requirejs (to manage the different modules within the app), while still using this built library. How might I add existing globals like jQuery to the dependency list in require?
<script src="pathto/lib.js" type="text/javascript"></script>
<script src="require.js" data-main="../js/app" type="text/javascript"></script>
requirejs.config({
shim: {
'jquery': {
exports: '$'
}
},
// jQuery is already loaded with lib.js, no need for any path...
path : {
jquery : 'jquery.js'
}
});
Is this possible? Or should I just continue with assumptions that certain globals will exist within the app modules because lib.js was included before require / the app js?
Using require to load the lib.js is not possible, because it is part of a CMS.
-- EDIT --
What about using a named module, and just return a handle on the global object, as that is where the lib content sits anyway?
define("lib", function () {
return this;
});
require(["lib"], function (lib) {
// use existing globals found in lib via
lib.jQuery
// or simply
jQuery
});
That allows me to follow the require() convention of naming dependencies, rather than assuming.
I am doing the exact same thing for my project where I load jquery from a CDN, so my path configuration looks like this
path: {
'jquery': '//path/to/the/cdn'
}
In your case, I think you should do as you updated (define and then return), because in some 3rd-party libraries, they might define jquery as the dependencies. If you don't have jquery in your RequireJS configuration, you have to modify the source code of the 3rd party libraries
If I have a module that requires an application namespace, e.g.:
define(["app"], function(App){
[...]
});
... and the namespace requires libraries used by all of my modules, e.g.:
define(["jquery", "underscore", "backbone"], function($, _, Backbone){
[...]
});
... then all of my modules have access to the libraries required by the namespace, i.e. I can use $, _, and Backbone.
I like this behavior because I can avoid being repetitious, but I suspect that I'm cheating somehow, and that I should require libraries in each module.
Can anyone set me straight here?
Yeah, that's kinda hacky. You only have access to jQuery, underscore and backbone because they're also defined onto the global scope. Backbone and undersocre aren't real AMD module, they have to use a shim config. jQuery declare himself on the global scope and as an AMD module so it works everywhere.
So, yes it work like that, but it's not optimal. Real AMD module (non-shimmed) won't work this way as they need to be passed in the define functions arguments, and you won't be able to pull only one module to test it in a separate environment, etc. This way, you cannot load different versions of a scripts to work with different module/app section/page.
The goal of AMD is to bring modularity to your code so every module declare it's own dependencies and will work out of the box it without relying on the global scope (which is a good thing to prevent name collision and conflict with third party/other dev working on the same project).
If you find it's redundant to redeclare everytime your base dependencie, create a boilerplate file that you just copy/paste when creating another module (it's better than nothing). And, maybe some command line tools can build AMD module wrapper for you.
Soooo, yes it works, but it won't scale if your project ever get bigger or need to be updated pieces by pieces.
Hope this help !
good news for the above answer: underscore 1.6.0 now is wrapped as a amd module :)
see "lib.chartjs" for exporting globals in not amd wrapped "shimmed" javascript libraries
requirejs.config({
paths: {
"moment": "PATH_TO/js/moment/2.5.0/moment.min",
"underscore": "PATH_TO/js/underscore/1.6.0/underscore",
"jquery": "PATH_TO/js/jquery/1.10.2/jquery.min",
"lib.jssignals": "PATH_TO/js/jssignals/1.0.0-268/signals.min",
// WORKAROUND : jQuery plugins + shims
"lib.jquery.address": "PATH_TO/js/jqueryaddress/1.6/jquery-address"
"lib.jquery.bootstrap":"PATH_TO/js/bootstrap/3.0.3/bootstrap",
"lib.chartjs": "PATH_TO/js/chartjs/0.2/Chart.min",
},
shim: {
"lib.jquery.address": {deps: ["jquery"]},
"lib.jquery.bootstrap": {deps: ["jquery"]},
"lib.chartjs": {deps: ["jquery"], exports: "Chart"},
}
});