r.js: Understand requirejs's r.js optimizer - requirejs

im trying to figure out if its a good idea to use r.js from require.js to generate a build.js file out of my javascript files to only load one file on production.
But im wondering if this is a good idea in my case as it seems its simply loading absolutely everything into the DOM using up a lot of memory. Maybe i got it wrong.
Look at one of my backbone based views i implemented using require.js. As i know, r.js will take this file and optimize and put it into the final build.js file with all the others views, models and collections defined the same way.
define(function (require) {
"use strict";
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone'),
tpl = require('text!tpl/start.html'),
Mustache = require('mustache'),
template = Mustache.compile(tpl);
return Backbone.View.extend({
initialize: function () {
},
render: function () {
this.$el.html(template());
return this;
},
events: {
'click #submit': "start"
},
start: function (event) {
// stuff to do ...
}
});
});
I guess the final build.js will simply take my code above and concat them into it, right?
So this means when i update my index.html loading require.js then my build.js file, it will simply load all the views, models and collections into the DOM. Doesn't take that up too much memory, since i don't need everything to be loaded from the beginning.
Does it make sense to call require('path/to/my/view') when its loaded already via the build.js file?

It might indeed not make sense for your application to optimize all modules into one single file. r.js supports this kind of scenario. What you have to do is use the modules option and define as many output files as you need. A generic illustration of this could be:
modules: [
{
name: 'main',
exclude: [ "viewA", "viewB" ],
},
{
name: 'viewA',
exclude: ['core']
},
{
name: 'viewB',
exclude: ['core']
}
]
The setup above assumes that the source to be optimized has modules named main, viewA and viewB. It would create 3 optimized bundles: a core that contains all core modules that would be loaded in any case, viewA which represents a group of modules to be loaded in circumstances so and so, and viewB which represents a group of modules to be loaded in other circumstances.
How you should setup your modules parameter depends on the specifics of your application.

Related

How to inject global variables with Webpack?

I need a specific instance of Map, generated at compile-time, to be made available to the code that I'm bundling with webpack. My use cases if for an instance of Map, but the question holds for any variable, really.
webpack.DefinePlugin won't work because my instance of Map doesn't survive stringification. I could deserialize/serialize, but that seems inefficient.
options.externals won't work because I'm not requireing an external module to be ignored by the bundler.
I've been able to get this working by setting a value on global, but I'm not sure this is the best way to go about this.
Here's a pathetically-contrived example:
webpack.config.js:
const myVar = new Map([
['a test value', () => {}]
]);
// is there a better way?
global.myVar = myVar;
module.exports = {
entry: './entry.js',
output: {
filename: './output.js'
},
target: 'node',
}
entry.js:
console.log(global.myVar) //=> Map { { "a test value", [Function] } }
In my real-world app, my Map value crawls the file system and builds a mapping of regexes and handlers. This should happen at compile time and is a constant mapping, so I want to consume it in my code-to-be-bundled as a constant.
I tried building the Map inside entry.js, but got all sorts of weird "Cannot find module" errors, I think mostly because the function I'm using to build the Map in the first place heavily abuses dynamic requires in a directory tree outside webpack's purview.
Would appreciate any insight.

Intern: DRY Runners for multiple project in one workspace

While realizing that my project setup might be the root cause of my problem, here's what I'd like some help with (moving from another framework to Intern):
I've different (>20) projects in one dev workspace, so I've (>20) different directories with test code. I'd like a project to be testable on itself, but also would like to execute all suites together.
I am specifying to use RequireJS as an AMD loader and where my tests can be found per project (one for nodeJS, one for browsers) through a config file. PLUS I have one overall config file specifying all the files.
You can image there is quite the duplication, what would be a good approach to DRY this up?
Note: it would also be welcome to help to describe my problem better (more generic or less TLDR)!
Since Intern configuration files are just AMD modules you can use the normal dependency loading mechanism to load and combine configuration data from multiple files:
// in your “do everything” master configuration
define([
'projectA/tests/intern',
'projectB/tests/intern',
'projectC/tests/intern',
// …
], function () {
var configs = Array.prototype.slice.call(arguments, 0);
function getCombined(key) {
return Array.prototype.concat.apply([], configs.map(function (config) {
return config[key];
}));
}
return {
suites: getCombined('suites'),
functionalSuites: getCombined('functionalSuites'),
// …
};
});

Specifying common modules and dependency in r.js

I am using requirejs and since the number of javascript files is growing, we are planning to use the requirejs optimizer.
Since there are few 3rd party js like (jquery,angular,bootstrap) which is used by all the pages, I thought its a better idea to put all the dependency to the same file.
Say we have 2 files, employee.js and manager.js and what I did in my build.js was
modules[{
name:"person",
include:["jQuery",
"angular",
"bootstrap"
]
},
{
name:"manager",
include:["jQuery",
"angular",
"bootstrap"
]
}]
is it possible to put the list of included modules in a common place and make this use this.
The other question is how do I specify dependencies in this case? say Angular is dependent on jQuery.
In requirejs, there was a configuration file where I can specify the deps.
You can use a bundle or you can create a common module as per the official multipage example depending on what exactly you wish to achieve. You can use variables in your build.js to save yourself from typing the same dependencies over and over.
See also the mainConfigFile option for using the same configuration for build as you did for runtime.
Here's an example of a bundle definition:
requirejs.config({
bundles: {
'primary': ['main', 'util', 'text', 'text!template.html'],
'secondary': ['text!secondary.html']
}
});
require(['util', 'text'], function(util, text) {
//The script for module ID 'primary' was loaded,
//and that script included the define()'d
//modules for 'util' and 'text'
});
Here's the most relevant part of the build file in the multipage example (but you should study the example in full):
modules: [
//First set up the common build layer.
{
//module names are relative to baseUrl
name: '../common',
//List common dependencies here. Only need to list
//top level dependencies, "include" will find
//nested dependencies.
include: ['jquery',
'app/lib',
'app/controller/Base',
'app/model/Base'
]
},
//Now set up a build layer for each page, but exclude
//the common one. "exclude" will exclude
//the nested, built dependencies from "common". Any
//"exclude" that includes built modules should be
//listed before the build layer that wants to exclude it.
//"include" the appropriate "app/main*" module since by default
//it will not get added to the build since it is loaded by a nested
//require in the page*.js files.
{
//module names are relative to baseUrl/paths config
name: '../page1',
include: ['app/main1'],
exclude: ['../common']
},
{
//module names are relative to baseUrl
name: '../page2',
include: ['app/main2'],
exclude: ['../common']
}
]

Require.js Optimizer incorrectly ordering shim dependencies

I have a web application that uses Require in order to load dependencies. I have a set of JS libraries that are included using the Require config.shim object.
Two such example libraries are:
require.config({
shim: {
"libs/leaflet": {
exports: "L"
}
"libs/leaflet-dvf": {
deps: ["libs/leaflet"],
exports: "L"
}
}
The second library, leaflet-dvf requires the first, leaflet. The second is a plugin to the first that depends on the global scope variable L that the first library defines.
When I run the application using Require normally, everything works fine. I can include either library from the shim, and everything works great. No problems.
The problem comes when I run this code through the Require r.js Optimizer. The Optimizer, when it builds the single optimized JS file, will incorrectly order the dependencies. In the built file, the leaflet-dvf code will come before the leaflet code. This causes a JS runtime error because the dependant plugin cannot find the L global scope variable that is required.
My build config looks like:
({
baseUrl: "../js",
paths: {
"requireLib": "../js/libs/require"
},
include: ["requireLib"],
name: "Main",
out: "bin/Main-built.js",
optimize: "none",
wrapShim: true
})
When I run the Optimizer, using Rhino, it builds my output file. In the Main-built.js file, the code for the plugin will come before the required library. This causes an L undefined error.
How do I get the Optimizer to respect the dependency order of my Shims, in order to properly order the library files in my Optimized JS file?
I had a similar problem a while back with knockout extensions and shim didn't work correctly. This is how we solved it.
Create a module called: leafletLib
define(["libs/leaflet","libs/leadleft-dvf"],function(leftlet,dvf){
return leaflet;
});
LeafletLib has the main library and all of the extensions. On modules that have leaflet or leaflet-dvf as a dependancy you call leafletLib. It is kind of hacky but it might work for you.
define(["leafletLib"],function(leafletLib){});

JamJS - Still pulls for dependencies separately when compiled - Underscore not loaded for context?

A am relatively new to JamJS, and struggle to make it work properly.
I've got a very simple project based on Backbone and RequireJS, where I use JamJS to manage dependencies, namely: Backbone, _, Less, $, modernizr, underscore, bootstrap.
I tend to follow the method used by Backbone Boilerplate.
This is the code I use to get the Jam-compiled requireJS config file, together with my application-specific require config:
in html:
< script data-main="/assets/js/app/config" src="/assets/js/jam/compiled.min.js"> < /script>
'Compiled.min.js' is obviously the 600kb minified file generated by Jam.
The '/app/config' file is my Require.js configuration file where I'm planning to include all my project-specific code, not managed by the dependency manager.
Here's app/config.js:
require.config({
baseUrl:'/assets/js/',
deps: ['less','modernizer','bootstrap-jam','app/main'],
paths: {
'homeView': 'app/views/homeView'
// Use the underscore build of Lo-Dash to minimize incompatibilities.
,'lodash': '../jam/lodash/dist/lodash.underscore.min'
},
map: {
},
shim: {
}
});
(the files in deps are the ones I need on every page + my main.js - kind of a router.
The problem is that, in my homeView (which is initialized by main.js), I do this sort of thing:
define(['backbone'], function (Backbone) {
return Backbone.View.extend({
el:$('#homepageWrapper'),
initialize: function () {
this.$('#subTitle').text('This text is generated by homeView - the default Backbone View.');
}
})
});
As you can see I want Backbone to be available in this view. I assume that it's available through the compiled Jam code, however when I look in the Network panel in the Web Inspector, I see that this dependency is pulled in separately- this happens to any resource I try to use, not just Backbone.
I suspect that it might be something to do with the error I get as well, which I haven't been able to figure out. When using the compiled jam config, I get:
Uncaught Error: Module name "underscore" has not been loaded yet for
context: _. Use require([])
I'd really appreciate help with this
Thanks.

Resources