I'm trying out AMD-way of handling scipts and my choise fell upon requirejs. In this project I use MDL (front-end framework; for those who haven't heard of it think of it as bootstrap 3) which should be included as:
<link rel="stylesheet" href="/bower_components/material-design-lite/material.min.css">
<script src="/bower_components/material-design-lite/material.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
I am not interested in js API that this framework is providing (if it provides any), I need this script only for UI to work properly when I attach framwerk-specific classes to elements.
According to requirejs philosophy I need only one script file to be included with a script tag on my page - the entry point. I understand that in that main script I need to require dependencies. And if it was say jQuery or underscore i.e. the library I actually require and my code depends on, I would write something like:
require(
['jquery'],
function($) {
$('body').append(...);
}
);
But how do I roll if it's not an actual dependency but I still need it to be loaded in my page and, in this particular case, I need it to be loaded first.
What do I do? My guess is I remove the script tag from my head and specify it in square brackets in my entry point script (as I did for jquery in snippet above) but just don't use it. Is it correct?
But how do I roll if it's not an actual dependency but I still need it to be loaded in my page and, in this particular case, I need it to be loaded first.
RequireJS only guarantees the relative order in which modules are loaded. If a module must absolutely be loaded first, then the chain of dependencies must be such that everything else depends on it, directly or indirectly. RequireJS does not provide a method to say "load this before everything else". You can get this effect only through dependencies. (Sometimes people think the deps configuration option guarantees that some modules will load first. It does not. Or they think that the order of dependencies in a require or define call sets an order for loading beyond what the dependencies set. It does not. If A and B have no dependencies of their own then require(['A', 'B'], ... and require['B', 'A'], ... are both free to load the modules in any order.)
What do I do? My guess is I remove the script tag from my head and specify it in square brackets in my entry point script (as I did for jquery in snippet above) but just don't use it. Is it correct?
In theory there's no problem with doing this. I say "in theory" because I do not use MDL so I don't know if MDL has any need that would prevent it from working. You've compared MDL with Bootstrap 3. What you describe is how I load Bootstrap with RequireJS. I tend to use the CommonJS idiom so modules that need Bootstrap look something like this:
define(function (require, exports, module) {
'use strict';
require("bootstrap");
There's no need to do something like var bootstrap = require("bootstrap"); because the value would be undefined anyway because the JS code of Bootstrap installs itself as jQuery plugins.
Related
When using RequireJS, what's the difference between including your script with
<script data-main="scripts/main" src="scripts/require.js"></script>
and
<script src="scripts/require.js"></script>
i.e. what does the data-main attribute change about loading in a script? I've read through the docs on this, and the different isn't entirely clear to me.
You will typically use a data-main script to set configuration options and then load the first application module. Note: the script tag require.js generates for your data-main module includes the async attribute. This means that you cannot assume that the load and execution of your data-main script will finish prior to other scripts referenced later in the same page.
The documentation mentions that you'll typically use a data-main script to set configuration options and load the first application module — but can't you also do that via a plain old script tag? Is there a benefit to doing configuration loading the application module with a data-main attribute?
Is the only different with data-main the asynchronous loading? Or is there something more?
data-main is just another way to perform the initial require call of your application. To illustrate... this:
<script data-main="scripts/main" src="scripts/require.js"></script>
is equivalent to this:
<script src="scripts/require.js"></script>
<script>require(["scripts/main"])</script>
The two forms are both asynchronous. This is really all there is to it. Considerations about how many entry points you have or where the RequireJS configuration is going to be located are completely orthogonal to the use of data-main. To put it differently, these considerations play a role in your use of data-main to the exact same extent that they play a role in your use of require(["scripts/main"]).
The part of the documentation you quoted is just obscuring things by mentioning that the script loaded with data-main creates a script element in the head element with the async attribute set, because this is not different from loading any script through RequireJS. Every single script loaded by RequireJS will have a script element created for it, in the head, and have the async attribute set.
It is common to use data-main for applications that have only a single entry point, and to put RequireJS' configuration in the module specified in data-main, but it is not required by any means. For instance, this is a perfectly valid use:
<script>
require = {
// RequireJS config here...
};
</script>
<script data-main="scripts/main" src="scripts/require.js"></script>
<script>
require(["foo"], function (foo) {
foo.something();
});
</script>
The configuration is given to RequireJS by setting require in the global space before loading RequireJS. (If require is defined before RequireJS is loaded, it will take require's value as its configuration.) Besides kicking off the application by loading scripts/main, this code also loads foo and calls a method on it: two entry points.
data-main is for when you want to have a single entry point to your application. That single script line will load RequireJS along with scripts/main.js and kick off your app.
The result of
<script data-main="scripts/main" src="scripts/require.js"></script>
is that <script async src="scripts/main.js"></script> is appended to the document at runtime; this is the script that will contain your require.config() block and pull in your first application script. If you don't specify a data-main, then you're only loading Require and none of your app scripts, unless you explicitly load a config file and the first module.
What do you think Require will load if you don't tell it to load anything?
If you do not use data-main, you must provide an entry point after loading Require (this is how I have always done it, for no good reason other than that's how I learned it.) Read about the configuration options to see how you would do this.
I use this pattern in development:
<script src="js/lib/require.js"></script>
<script src="js/config.js"></script>
<script>
// same as data-main
require.config({baseUrl : 'js'});
require(['js/main']);
</script>
As a single entry point, the contents of config.js and the subsequent require(['js/main']) call would be in whichever script is referenced as data-main.
If you use the static optimizer to build a production bundle, none of this matters because you just load the bundle.
data-main is the script that require.js will process. As the documentation says, it is common to set configuration options in that script. But there are other ways to do that. In many cases it is the easiest and most effective place. But not always.
The script pointed to by data-main will also list the dependencies for the code that the file defines. The dependencies are where the meat is. It is typical, though not required, to have this first module load and execute what is ultimately the actual application.
Addendum in response to the comment:
There are some concepts you need to be aware of that will help make sense of this approach.
First is that there isn't a single (or a couple, or even a few) script(s). This type of loader is designed to handle lots and lots of very small scripts. Each with a very specific and often (preferably) single purpose. Call these scripts modules (or units).
Any given module might depend on any number of other modules in order to function. The AMD pattern allows the dependencies for each module to be listed within that module's definition.
RequireJS will sort out who needs what and in what order and not let scripts execute until all the modules they depend on are loaded and ready.
So this is not at all like putting a script link (or multiple links) in a page as we all grew up doing. It is a much different approach to javascript development. Once you get your head around it and figure out how to breakdown your code into discreet units of functionality it really is quite slick.
<script data-main="scripts/main.js" src="scripts/vendor/requirejs/require.js"></script>
src will load "scripts/vendor/requirejs/require.js" first. Then data-main attribute will execute "scripts/main.js".
define(["jquery","bootstrap","jquery.min"],function($){
var inittest = function(){
alert("hello");
}
var init = function(){
inittest();
};
return {
init: init
}
});
It's not working. How to use jQuery to define array?
You need to do two things here (the details are in the useful thread I linked you to, so please read).
Configure requirejs so that when you declare modules (e.g. "jquery", "bootstrap"), requirejs can resolve them to actual files, minified or otherwise.
Shim bootstrap by specifying jquery as its dependency, so that jquery is loaded before it.
To accomplish these, make a call to requirejs.config({...}) with the appropriate options (here is an example). The use case there is exactly the same as yours: jquery is specified as a bootstrap dependency by shimming bootstrap. There you will also see an example of how to tell requirejs where your files are (this is accomplished via the paths property). Note how the .js extension is not explicitly specified there; do the same.
Needless to say, configuring requirejs can get complicated, but the basic idea is there, configure it by specifying the base directory and where the files are to be found, then shim non-AMD modules. An important thing to be aware of is that bootstrap is going to be what's called a declarative module, which means that it's only used for its side-effects (viz. for what changes it makes to $).
I've set up a single html page that uses three dojo widgets and I'm trying to create a custom build from it using dojo 1.7.5. The build succeeds leaving me with a dojo.js that includes the files I need using this build file:
var dependencies = {
action: "release",
selectorEngine: "acme",
stripConsole: "none",
cssOptimize: "comments.keepLines",
layers: [
{
name: "dojo.js",
dependencies: [
"dijit.form.ValidationTextBox",
"dijit.form.DropDownButton",
"dijit.form.Button",
"dijit.form.Form",
"dijit._base",
"dijit._Container",
"dijit._HasDropDown",
"dijit.form.ComboButton",
"dijit.form.ToggleButton",
"dijit.form._ToggleButtonMixin",
"dojo.parser",
"dojo.date.stamp",
"dojo._firebug.firebug"
]
}, {
name: "../test/test.js",
dependencies: [
"test.test"
]
}
],
prefixes: [
[ "dijit", "../dijit" ],
[ "dojox", "../dojox" ],
[ "ourpeople", "../ourpeople" ]
]
};
The questions I can't seem to find an answer to:
I'm using cssOptimize, I was expecting a single css file in which all the used css files were imported. However I can't find such a file. Is this the way dojo compresses it's css or are my expectations wrong? If so where can I find it in my release folder?
My test.js contains a function test1() if I call it from my built js it states test1 is not defined. I call that function directly without dojo. I'm assuming that building custom js only works if it is a dojo class using declare?
Final question, I needed to include several dojo files in the build manually such as dojo._firebug.firebug since after my initial build it was still using xhr calls to get those files. After including the files manually I still see xhr calls from dojo to specific resources: dojo/nls/dojo_ROOT and dijit/form/nls/validate.js. Those files are created during the build process and therefore can't be included in the dependencies in the build profile. Anyone any thoughts on this matter since I'm looking to distribute dojo in a single file.
I'm fairly new to the dojo build system and (especially) so perhaps I'm expecting things that the dojo build system isn't designed to do or maybe om going about this the wrong way if so any tips or suggestions are more than welcome.
Cheers!
Test.js:
function test1() {
console.log("test1");
}
Index.php:
<script type="text/javascript" src="js/release/dojo/dojo/dojo.js"></script>
<script type="text/javascript" src="js/release/dojo/test/test.js"></script>
<script type="text/javascript">
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.Form");
dojo.ready(function() {
test1();
});
</script>
I'm using cssOptimize, I was expecting a single css file in which all the used css files were imported. However I can't find such a file. Is this the way dojo compresses it's css or are my expectations wrong? If so where can I find it in my release folder?
When you use cssOptimize, the Dojo build optimizes and flattens CSS files in place. So for example, if you're using Dijit's Claro theme, when you load dijit/themes/claro/claro.css from source, it contains a series of #import statements which in turn load more files. When you load claro.css from a build with cssOptimize, it is one file containing all of the styles previously referenced via those separate files.
My test.js contains a function test1() if I call it from my built js it states test1 is not defined. I call that function directly without dojo. I'm assuming that building custom js only works if it is a dojo class using declare?
Dojo doesn't expect every JS file to be a "class" using declare but it does expect each file to be a module which doesn't implicitly define globals (since globals should be avoided in modules anyway). When the build process encounters a module that it thinks or knows isn't AMD, it assumes it's a legacy Dojo module and wraps it in a boilerplate to convert it to AMD. This boilerplate ends up encapsulating your globals into a function scope, so they are no longer globals.
Given that you're using Dojo 1.7, you should ideally be using the AMD format to define and consume modules. dojotoolkit.org has a tutorial introducing AMD modules, and if you're migrating from Dojo 1.6 or earlier, there's also a tutorial to help you transition.
Final question, I needed to include several dojo files in the build manually such as dojo._firebug.firebug since after my initial build it was still using xhr calls to get those files. After including the files manually I still see xhr calls from dojo to specific resources: dojo/nls/dojo_ROOT and dijit/form/nls/validate.js. Those files are created during the build process and therefore can't be included in the dependencies in the build profile. Anyone any thoughts on this matter since I'm looking to distribute dojo in a single file.
I'm not sure why you're seeing dojo/_firebug/firebug being automatically loaded, but based on what you've said/shown above I would immediately suggest the following:
Convert your modules/code to AMD format
Add async: true to your dojoConfig which will cause the loader to operate in asynchronous mode, which means:
It loads modules through script injection instead of synchronous XHR
It won't unconditionally load all of dojo/_base
Add customBase: true to your dojo/dojo layer which will prevent the build from defaulting to include all of dojo/_base
As for the nls modules, to an extent it's normal to still see NLS files requested, though if your build is configured properly there would ordinarily just be one NLS file per layer and that's it (the fact that you're seeing a separate request for validate leads me to think you haven't covered all of your dependencies). The reason NLS remains separate is because there is one NLS bundle per locale, and it doesn't make sense to build all locales into one layer - that would force people to pay for resources in 20 languages they don't care about.
I was wondering if anyone had experience using require.js with the Adobe CQ5 platform. I'm writing a Chaplin.js(backbone-based) single page app that will be integrated into the rest of CQ5-based site we're working on. Chaplin requires the use of a module system like AMD/Common.js and I want to make sure my compiled javascript file will usable within CQ5's clientlibs. Is it as simple as adding require.js as a dependency in clientlibs prior to loading in my javascript modules? Someone's insight who has experience in doing this would be greatly appreciated.
I've implemented this as a solution of organize in a better way all the modules such as:
//public/js/modules/myModule.js
define('myModule',[ /* dependencies */] ,function( /* stuff here */ ))
and in the components such:
<% //components/component.jsp %>
<div>
<!-- stuff here -->
</div>
componentJS:
//components/component/clientlibs/js/component.js
require(['modules/myModule']);
and finally I've configured require (config.js) and I've stored the JSs modules in a new different design folder. Located the compiled JS after close </body> to guarantee the JS is always located at the bottom after the HTML.
<!-- page/body.jsp -->
...
<cq:includeClientLib js="specialclientlibs.footer"/>
</body>
solving with this the issue of have "ready" all the content before the JS is executed. I've had some problems to resolve with this async stuff managed for the clienlibs compilation tool, in production the problem was different, however, in development, the order in what CQ compiles the JS has produced me some lacks in terms of order of the JS. The problem really was a little bit more complex than the explanation because the number of JS was really big and the team too, but in simple terms it was the best way I've discovered so far..
The Idea
I think you can compile your Chaplin.js with one of the AMDShims to make it self contained, wraps every dependencies it needs inside a function scope, expose an entry point as global variable (which is a bad practise, but CQ do it all the time...) and then use the compiled.js inside a normal clientlib:
AMD Shims
https://github.com/jrburke/requirejs/wiki/AMD-API-Shims
Example
Here is an example of how we make the one of our libs self-contained:
https://github.com/normanzb/chuanr/blob/master/gruntfile.js
Basically, in source code level the lib "require"s the other modules just as usual. However after compiled, the generated chuanr.js file contains everything its needs, even wrapped a piece of lightweight AMD compatible implementation.
check out compiled file here: https://github.com/normanzb/chuanr/blob/master/Chuanr.js
and the source code: https://github.com/normanzb/chuanr/tree/master/src
Alternative
Alternatively rather than compile every lib you are using to be independent/self-contained, what we do in our project is simply use below amdshim instead of the real require.js. so on cq component level you can call into require() function as usual:
require(['foo/bar'], function(){});
The amd shim will not send the http request to the module immediately, instead it will wait until someone else loads the module.
and then at the bottom of the page, we collect all the dependencies, send the requirements to server side handler (scriptmananger) for dynamic merging (by internally calling into r.js):
var paths = [];
for (var path in amdShim.waiting){
paths.push(path);
}
document.write('/scriptmananger?' + paths.join(','));
The amdShim we are using: https://github.com/normanzb/amdshim/tree/exp/defer
I want to determine at runtime whether a YUI module has been defined (i. e. whether someone has called YUI.add() for that module).
Based on reading the YUI code, it seems like YUI.Env.mods[moduleName] will do the trick, but I can't find any documentation for this property so I'm not sure if it's meant to be used/works in all cases. Is there a preferred way to do this?
EDIT: here's what I'm trying to accomplish:
We are switching from a system where most assets are manually loaded via link/script tags in the HEAD to one where we depend more on the YUI loader. To support legacy code, I want to make sure that modules preloaded in the HEAD will not get loaded again by YUI (some things like jQuery have issues when loaded twice).
The preloaded modules are a mix of YUI-style and non-YUI-style modules.
So far, I'm emitting code like the following:
<head>
<!-- bunch of script/link tags -->
<script>
var modules = // list of preloaded modules
, i;
for (i = 0; i < modules.length; ++i) {
if (!ISMODULEALREADYDEFINED(modules[i])) {
YUI.add(modules[i], function (Y) { }, '');
}
}
</script>
</head>
The reason I need the ISMODULEALREADYDEFINED check is that if some of the pre loaded modules are YUI-style modules, then YUI might still be loading up their dependencies asynchronously when we run the above script. If that happens, then the noop module definition I'm adding prevents the original module definition callback from ever running.