I have developed JavaScript based web applications in the past and am now trying to understand RequireJS.
Almost all web apps have pages which would require some common JS and some page specific JS. I want to organize the entire web app using RequireJS.
So my question is can we do the same using RequireJS. If yes, how exactly is the breakup of JS done?
Let's say I have an app.build.js as follows;
({
appDir: "../",
baseUrl: "js",
dir: "../../appdirectory-build",
paths: {
jquery: 'libs/jquery/jquery-1.8.2',
underscore: 'libs/underscore/underscore-1.4.4',
backbone: 'libs/backbone/backbone-0.9.10',
templates: '../templates',
app: 'app'
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
},
modules: [
{
name: "main"
}
]
})
Can we have multiple "modules" defined here (like we have the 'main'). Please provide more details.
Also RequireJS is said to be AMD. So what exactly is asynchronous over here?
Thank you.
Over the past few months I've thrown together a few example Mimosa built apps that bundle many modules for use in an app.
This one has nested main modules, 3 built files altogether: https://github.com/dbashford/MimosaNestedMains
It is a rather naive example, but you can see how one could portion out their app into small pieces and build each individually. To see the r.js run configs that Mimosa builds and uses, run mimosa build -oD. That will spew the debug logs to the console and that includes the r.js configs for each file.
Getting started with Mimosa: http://mimosajs.com/started.html
Related
I'm using requirejs for multipage project. Each page is an App. All of the apps have some common dependencies, i.e. jquery, backbone, underscore etc.
I want to move all this dependencies to the one single file.
That's how the js folder structure looks like:
js
base-app-require-configuration.coffee
app
homepeage
init.coffee
build.js
application.coffee
app1
init.coffee
build.js
application.coffee
app2
init.coffee
build.js
application.coffee
Homepage application example:
js/base-app-require-configuration.coffee
define ->
requirejs.config
urlArgs: "bust=#{ new Date().getTime() }"
# yep, tricky paths here
paths:
jquery: '../../jquery.min'
underscore: '../../underscore-min'
backbone: '../../backbone.min'
js/app/homepage/init.coffee
define [
'../../base-app-require-configuration'
], (
baseRequireConfig
) ->
requirejs.config
paths:
'jquery.alphanum': '../../jquery.alphanum'
shim:
'jquery.alphanum':
deps: ['jquery']
require [
'jquery'
'application'
], (
$
Application
) ->
$ -> new Application
js/app/homepage/build.js
({
mainConfigFile: ['../../base-app-require-configuration.js', 'init.js'],
wrapShim: 'true',
baseUrl: './',
name: 'init',
findNestedDependencies: true,
out: 'init.js'
})
My data-name is init.js
The thing works pretty well for multiple apps with the common dependencies moved to one sigle file - base-app-require-configuration.coffee, except one thing: the only way to compress/optimize this using r.js is to set the flag findNestedDependencies to true, because otherwise r.js won't see requirejs.config calls nested into define/require.
My questions are:
Is using findNestedDependencies a good practice?
Is there a prettier way to organize my dependencies without repeating?
If there is such a way - will it be compatible with r.js?
Let me share this solution with you.
I'm also looking for the similar solution with requirejs (how to organize the multipage project without repetitions of a long configuration, with a "shim" feature), and I have found the following one (I would be glad if this snippet can help you):
Inside HTML:
...
<script src="js/lib/require.js"></script>
<script>
//Load common code that includes config, then load the app
//logic for this page. Do the requirejs calls here instead of
//a separate file so after a build there are only 2 HTTP
//requests instead of three.
requirejs(['./js/common'], function (common) {
//js/common sets the baseUrl to be js/ so
//can just ask for 'app/main1' here instead
//of 'js/app/main1'
requirejs(['app/main1']);
});
</script>
...
where "common.js" contains the common configuration of requirejs for your project. This sample is from: https://github.com/requirejs/example-multipage-shim/blob/master/www/page1.html.
The full code of a sample project is here: https://github.com/requirejs/example-multipage-shim. The sample "build.js" file also providen, I see there is no necessity in "findNestedDependencies" in this case.
Sure, there is a bit more code inside HTML, but I think this is not significant downside.
Is using findNestedDependencies a good practice?
Not sure. the only thing i know, is that this option can slow down the bundling process quite a lot:
Is r.js dependency tracing significantly slower since v2.1.16? Or is it just me?
Is there a prettier way to organize my dependencies without repeating?
If there is such a way - will it be compatible with r.js?
this is a great article out organising backbone modules using r.js:
https://cdnjs.com/libraries/backbone.js/tutorials/organizing-backbone-using-modules
I will try to simplify my problem. I've got a main application (single page app essentially) that requires javascript files based on its own config file.
The json config file looks like this (that config file is not related to requirejs, it is the app own config file):
"modules": [
{
"categories": "categories/main"
}
]
The main application is basically loading its config json file, and requiring the modules on runtime, something like:
function loadModule(id, modulePath) {
require([modulePath], function(module) {
// modulePath is categories/main
});
}
I've got an AMD config that looks like that:
require.config({
'paths': {
'categories':'js/app/modules/categories',
The module looks like this:
define('categories/main', [
'categories/data/navigation'
], function (
navigation
) {
'use strict';
var CategoriesModule = function() {
};
CategoriesModule.id = 'categories';
return CategoriesModule;
});
So this is working all fine with non-minified version.
Note that even though I dynamically load the modules in my app, I still want the modules to be minified inside the only one minified file that I have in my app. I do not want to make an http request at runtime to load the module.
For this I have included the module in my optimization build:
require.config({
include: [
'app/modules/categories/main'
This works just fine as well, but here is what I am trying to do.
If you look back at the module, it requires another file: 'categories/data/navigation'.
And this file is not minified because apparently r.js has no way of following the dependencies of files that are loaded at runtime.
I kind of expected r.js to follow the dependencies of what I have "included" in this optimization build config.
So to solve the problem, I would need to do the following in my optimization build config:
require.config({
include: [
'app/modules/categories/main',
'app/modules/categories/data/navigation'
In other words, list of the files that the module is using, which is what I'm trying to avoid.
I thought findNestedDependencies would solve the problem but it doesn't. Here is my r.js config for information:
options: {
paths: {
'main': 'js/main'
},
logLevel: 0,
baseUrl: 'public',
mainConfigFile: ['build/optimization/require.config.js', 'public/js/app/config/amd.js'],
generateSourceMaps: false,
preserveLicenseComments: true,
name: 'main',
out: 'public/js/main.min.js',
removeCombined: true,
findNestedDependencies: true,
uglify: {
beautify: false,
mangle: false
}
}
This app is fairly large and it is important for me to limit the required work needed when creating a module, a "plug and play" module is what I am after.
Listing all the files the module is using for minification is something I'd like to find a solution for.
Any hint? Any idea?
Why is r.js not able to follow the dependencies of my module when I include the main file of the module in the optimization config?
Any help appreciated.
Cheers.
I will answer my own question. r.js wasn't able to follow the dependencies of the modules because I included the full path of the module in the build optimization config. Using the path shortcut, which is also the defined name of the module, r.js is then able to follow the dependencies.
I'm not sure why but I guess it probably makes sense.
Rather that using:
require.config({
include: [
'app/modules/categories/main'
The include should be:
require.config({
include: [
'categories/main'
Probably because of the require config path:
require.config({
'paths': {
'categories':'js/app/modules/categories'
Hope that will help someone with the same kind of problem!
I have an Ember application using require.js which is working correctly in the browser before optimization, but when I try to run it through r.js for optimization, I'm receiving an error from Ember: "Error: Could not find module jquery".
I looked a little deeper and it seems like the jQuery and $ global variables aren't defined by the time r.js attempts to eval() Ember.
It's failing when Ember is being required from a handlebars plugin that I've slightly modified to use Ember.Handlebars instead of regular Handlebars (modified version of this: https://github.com/epeli/requirejs-hbs/blob/master/hbs.js)
My current build configuration is:
({
name: 'main',
out: 'main.min.js',
optimize: 'uglify2',
baseUrl: '../static/js/',
paths: {
jquery: 'lib/jquery-1.11.0',
handlebars: 'lib/handlebars-1.3.0',
ember: 'lib/ember-1.5.1',
hbs: 'plugin/hbs',
text: 'plugin/text-2.0.12',
},
shim: {
handlebars: {
exports: 'Handlebars'
},
ember: {
deps: [ 'jquery', 'handlebars' ],
exports: 'Ember'
}
},
hbs: {
templateExtension: '.html',
}
})
The full error from r.js is:
Error: Could not find module jquery
In module tree:
main
app/App
app/view/MainView
hbs
at t (eval at <anonymous> (r-2.1.11.js:25343:38), <anonymous>:10:374)
I've also tried including "wrapShim: true" in my build config, but with no success...
Edit:
I tried removing 'ember' from the dependencies in my hbs plugin, and found an issue with the "include" line I had in my build config, so I removed that line and was able to build successfully. However, adding 'ember' back into the deps for hbs still caused the original issue to come back...
Edit 2:
It appears that node and r.js do not load jQuery. I assume this is why Ember is unable to find jQuery at build-time. The issue is referenced here:
https://github.com/jrburke/r.js/issues/85
I may need to find a way to stub out the jQuery dependency so I can use Ember's Handlebars compiler at build time without it...
Does anybody know how I can resolve this issue?
I know it's a bit late, but have you tried to great a shim for jQuery?
shim:{
'jquery': {
deps: [],
exports: 'jQuery'
},
...
}
Cheers,
Johannes
I have been battling with this for a while (even used some Ant-based workarounds), even posted a question that went unanswered: older similar/related question.
Require.js allows to build several modules using the same profile/config file. For example:
({
appDir: 'some/path',
baseUrl: 'some/base/path',
dir: 'some/other/path',
optimize: 'none',
paths: {
...
},
modules: [
{
name: 'someModule',
},
{
name: 'someOtherModule'
}]
})
Which works fairly well. Additionally, Require.js provides an option to override any option for the build for a specific module: Require/js example build configuration, like this :
({
appDir: 'some/path',
baseUrl: 'some/base/path',
dir: 'some/other/path',
optimize: 'none',
paths: {
...
},
modules: [
{
name: 'someModule',
},
{
name: 'someModule',
override : {
optimize: 'uglify'
}
}]
})
or so I understood it. The purpose is to use the same build configuration file on the same application, but have it both non-minified and minified. This doesn't work.
EDIT
The error I am getting is (cleaned up, since it is part of a larger Ant build):
Error: ENOENT, no such file or directory 'some/other/path/someModule.js-temp'
Any help, suggestions (on both questions) are greatly appreciated.
The listing of modules: config does not allow duplicates for the name value. I suspect that is the source of the problem. It is an array just to allow proper sequencing of build layers that may be excluded in other build layers -- using an object hash would not work since key iteration on an object does not guarantee order.
If you want to do a build that has the layer in non-minified and minified format, I suggest driving the build via a node script, then manually requiring uglify and doing a copy of the built file and minification of that copy after the build.
Here is an example of a node script that drives the build:
https://github.com/jrburke/r.js/blob/master/build/tests/tools/override/override.js
That one is replacing the version of uglify used, but you could use it and do the file copy/manual minification in the callback function passed to requirejs.optimize().
I have a feeling that the title just might not be explanatory :)
Setup
Suppose that I have the following structure:
where app.js files are main bootstrapping/entry modules for the applications that look like this:
app01
require.config({});
require([
'app/component1.js'
],
function(component){
// do something with component1
});
app02
require.config({});
require([
'app/component2.js'
],
function(component){
// do something with component2
});
which both work with appropriate index.html files.
I have a RequireJS build configuration file (assume correct placement related to the paths) for app01:
({
appDir: 'apps/app01',
baseUrl: '.',
dir: 'built_apps/app01',
optimize: 'closure',
paths: {
},
modules: [
{
name: 'app'
}
]
})
which works just fine. Similar file (replacing app01 with app02) works just fine for app02.
Problem/target
Now I want to be able to run RequireJS build tool (using Google Closure with Rhino under Ant, not that it really matters in this case) for both app01 and app02 applications using the same build configuration file and, preferably, without actually listing all the apps by name (since the number and names may vary over time).
Basically I expect (or rather hope) to have something like this:
({
appDir: 'apps',
baseUrl: '.',
dir: 'built_apps',
optimize: 'closure',
paths: {
},
modules: [
{
name: 'app*/app' // notice the wildcard
}
]
})
which would run over built_apps directory, find all apps under app*/app and optimize each one of them.
I know I can use Ant to create such build configuration file on the fly per app, run build against it and then clean up, but I'd rather have RequireJS solution.
Is there a way to do something like this with RequireJS?
There's no built-in wildcarding configuration for RequireJS. One way or another, you'll need code to do this. I'll observe that what you're asking for here amounts to translating a wildcard into some kind of implicit iteration on the module objects, akin to what mustache.js provides for its templates. IMO, that's a fairly brittle and limited approach in this context.
Instead, I recommend generating your modules array programmatically in JavaScript right in the build config. Recall, the build config is JavaScript not just a JSON data structure. This gives you sophisticated scripting capabilities there.
I've done this kind of scripting in the build config for the requirejs-rails gem. Here's an example gist that shows what r.js would see at build time.