Understanding dojo's require in combination with diji/layout - javascript

I'm trying to understand dojo in combination with dijit layouts. More specifically: do I need to require the layout widgets in JS or is using html data attributes enough?
I've read the Layout documentation and it seems like you need 3 things:
JavaScript: require the layout widgets you want to use
HTML markup
CSS
But it's not clear to me why I would need to require the layout widgets in JavaScript with:
require(["dojo/parser", "dijit/layout/BorderContainer", "dijit/layout/ContentPane"]);
Which is stated in this example.
I've created a demo without requiring "dijit/layout/BorderContainer" and "dijit/layout/ContentPane" and that's working fine.
Is it safe to leave these out of the require statement?

You should require your modules rather than letting the parser load them because ideally you want all of your modules loaded before the parser runs so that you can bundle all of your dependant modules into a layer file.
This means that you can create a layer with all of your common modules so that you don't need to have 100s of tiny .js requests hit your server, and instead you can load a bulkier one.
Also, if you have custom modules you should load all of the dependant widgets inside of the custom module instead of letting the parser detect.

dojo/parser loads all dependencies for you, so you don't need to require them programmatically in JavaScript, but you need them there once you decide to build your code, i.e. put all the dependencies into a single file, which is the reason, why parser warns you, when it loads dependencies for you:
This auto-requiring is also the reason, why parser.parse() returns a promise, it's because it might be asynchronously loading dependencies:
parser.parse().then(function(/* Array */ widgetInstances) {
});

Related

What is the "order!" directive for in this requirejs/amd module?

I'm looking into what appears to be a case of javascript loading out of order in a legacy application. The application uses Require.js to load several modules, and one of our company's modules is executing prior to its dependencies being loaded.
My experience with Require.js and AMDs is very limited, and in researching I noted that in some areas dependencies are prefixed with an order! string, such as:
define(['order!jquery', ...
Whereas in other areas the prefix isn't used:
define(['jquery', ...
So far I can't find documentation of this directive. What's its effect?
Full information copied from here
Normally RequireJS loads and evaluates scripts in an undetermined
order. However, there are some traditional scripts that depend on
being loaded in a specific order. For those cases you can use the
order plugin. Download the plugin and put it in the same directory as
your app's main JS file. Example usage:
require(["order!one.js", "order!two.js", "order!three.js"], function () {
//This callback is called after the three scripts finish loading.
});
Scripts loaded by the order plugin will be fetched asynchronously, but
evaluated in the order they are passed to require, so it should still
perform better than using script tags in the head of an HTML document.
The order plugin is best used with traditional scripts. It is not
needed for scripts that use define() to define modules. It is possible
to mix and match "order!" dependencies with regular dependencies, but
only the "order!" ones will be evaluated in relative order to each
other.
Notes:
The order! plugin only works with JavaScript files that are cacheable by the browser. If the JS file has headers that do not
allow the browser to cache the file, then the order of scripts will
not be maintained.
Do not use the order! plugin to load other plugin-loaded resources. For instance. 'order!cs!my/coffescript/module' is not recommended.
You will get errors in some versions of IE and WebKit. This is due
to the workarounds the order plugin needs to do for those browsers
to ensureordered execution.

Bundling a durandal single page application into one HTML page

I have a very strange requirement that I need to bundle everything together in one HTML page with my Durandal Single Page application. I can make this away with my dependencies as I am defining them with a name:
define("models.mapper", [], function() {
});
However, it seems like it will not be possible to bundle durandal stuff as it defines modules without names:
define(['require', 'jquery'], function(require, $) {
// ....
}
This is fine when you want to make it work with path references but it seems like this will make it hard to inline this into HTML. Any ideas or suggestions on this?
Require.JS requires you to have only one anonymous define per file so that it can use the file path+name relative to the base path to give it a name. If you would like to have the durandal source inline on your page as well then you'll need to update their define lines to give them the appropriate names (i.e. define('durnadal/system', ......).
An easier approach may be to just build your source code in the structure of a normal durandal project and then use the RequireJS optimizer (http://requirejs.org/docs/optimization.html) to build them into a single JS file - if you configure this correctly without minification then you can just paste the file contents into a script tag on your page and it'll still be legible!
If you really wanted to you could then just continue developing in the single HTML file however you really should look at automating all of this into a grunt workflow and it shouldn't be too hard and you'll have much easier to manage code. Note that you may even be able to use the durandal grunt task to do this, but I'm not sure what options it allows you to provide but you can definitely use the requirejs grunt task and build it into your workflow without minification. With some templating task you could then inject that output into your final HTML page.

Avoid loading DOM relient modules while testing

I'm using the intern for testing javascript in a project. The javascript we are trying to test does not require the DOM, and should be able to be run within a node process without trouble. However, the modules that I'm loading for the test also load jquery (as an example), which hits the dom on load.
//file.js
require([..., 'jquery'], function(..., $) {
// non-jquery code to test
})
//intern test
require(['intern!object', 'file'], function(registerSuite, file) {
registerSuite({
...
Loading jquery in the module causes intern to break immediately when run in a node process, even though I want to test something completely different. Is there a correct way to get around this? I tried just pointing the jquery module to an empty file, but this doesn't work for all cases.
Thank you.
If any code has a hard dependency on the complete, pre-built copy of jQuery, then it must run in a DOM environment, as jQuery is a DOM library. If the code itself doesn’t require a DOM, then it shouldn’t have jQuery as a dependency, at which point it will load fine in Node.js.
If you need a non-DOM utility library, try Dojo or Lo-Dash or something else that isn’t a DOM library like jQuery.
If you have a module that may use the DOM, Dojo comes with the dojo/has module that can be used as an AMD loader plugin to conditionally load DOM dependencies only when the module is loaded in a browser.
Finally, note that any AMD module (like file.js in your example) should contain a define call, not a require call.

How do I instantiate require.js modules on different pages, partials with codeigniter?

I'm trying to update the javascript on a large scale, php/codeigniter based website. It has many, many php partials for code being loaded onto certain pages, but only one footer, header. Most of the partials have inline script tags in them for loading javascript. This needs to be fixed and because the site is very modular with components being used multiple times across pages, require.js seems like a pretty good solution.
So, it's instantiate javascript, we typically do this.
<script type="javascript" src="../js/scriptname.js">
<script type="javascript">
DP.scriptname.init(parameters)
</script>
I'd like to get away from this and just have a have a single entry point for the js using require.
My question is this: what's the best way to instantiate javascript for certain pages using require? Do I need I need to continue including my scripts in the partial and then do something like writing a require module for that specific page and then wrap it all in my data-main script like this? We're planning on using Backbone and Marionette as well, but I won't be able to use the Backbone router to do anything like setting hash URLs. Should I use the URLs to instantiate my require modules perhaps?
Ok, hope someone can help. My experience has typically been in building single page websites. This is different. Thanks
Cam
Well, if I understand your question correctly, you can use Require JS in such way.
First of all, write a config in which you can describe mapping between module names and concrete files. For example:
requirejs.config({
baseUrl: 'js/modules' // by default load any module using this path
});
After that you should refactor your existing module and adjust it to the AMD format (see http://requirejs.org/docs/whyamd.html)
As a result of this step you will have something like this (let's say in file 'js/modules/scriptname.js'):
// module has the same name as the file, which contains it - "scriptname"
define(function () {
// define the module value by returning a value
return function () {};
});
And as a final step you can refactor your inline script and use this module in such way:
<script type="javascript">
// when we place name of the module as a first argument of the "define"
// function, Require JS find file that contains it and load it asynchronously
define(["scriptname"], function (scriptname) {
// "scriptname" now contains value that we recieve from the module definition
scriptname.init(parameters);
});
</script>
Hope this helps.
Note. My solution based on this section of official Require JS documentation: http://requirejs.org/docs/api.html#jsfiles
This question seems to come up a lot, so I'll point you to some resources that may help:
How does RequireJS work with multiple pages and partial views? - https://stackoverflow.com/a/10816983/617615
Modular HTML components with RequireJS - http://simonsmith.io/modular-html-components-with-requirejs/
Example RequireJS-based project that has multiple pages that share a common set of modules - https://github.com/requirejs/example-multipage

AMD: what is the purpose in javascript context?

Regarding AMD (Asynchronous Module Definition ) I read the phase like this:
The AMD format comes from wanting a module format that was better than
today's "write a bunch of script tags with implicit dependencies that
you have to manually order" and something that was easy to use
directly in the browser.
What is the the purpose in javascript context? Can you make some example? pro et contro of using AMD?
Long before JavaScript gained a native module system, the only way to put scripts onto a page were <script> elements. These executed in sequence, in the order they appear on the HTML. This means that if your script relied on jQuery, then jQuery's <script> has to come before your script's <script>. Otherwise, it blows up.
It's not uncommon to logically split an app into multiple files, especially as the app grows. But using this system of manually ordering scripts becomes a nightmare quickly. Your scripts have implicit dependencies whose management is defined elsewhere. This is where AMD comes in.
AMD is a module specification and RequireJS is an implementation of such system. Simply put, it's a wrapper around your code that 1) keeps your script inert until invoked, 2) allows your script to explicitly define its dependencies and, 3) allows the module system to work out which dependencies execute in what order.
Here's a rough example:
// your-app.js
define(['jquery', 'underscore'], function($, _){
// Your script sits in this "wrapper" function.
// RequireJS now knows app.js needs jquery and underscore.
// It loads and executes them first before your script.
})
// jquery.js
define('jquery', [], function(){
// jQuery stuff
return jQuery
})
// underscore.js
define('underscore', [], function(){
// underscore stuff
return underscore
})
// Then on your HTML, load up your app.
<script data-main="path/to/app.js" src="path/to/require.js"></script>
It's common for Javascript libraries that depend on each other to require that they are loaded in a specific order. For example, the script tag that includes the jQuery library has to come before the script tag that includes the jQuery UI library.
If the libraries were using AMD, they could be included in any order. The AMD library would take care of initialising the libraries in the correct order, because you specify which library depenends on which.
(Somewhat ironically, the script tag that includes the AMD library of course has to come before the code that include any libraries using AMD...)

Categories