Converting an existing Backbone.js project to Require.js
ozkatz.github.io
ozkatz.github.io
Instead, RequireJS yielded a fairly verbose and error-prone header* coupled with large and distinct JS downloads for each and every page. Add in Backbone's verbosity and it's boilerplate and hand-wiring all the way down. Just the kind of thing for when you want to handcraft an artisan website, but not so great for cranking out code.
* Good luck catching typos when you're pulling in 20 modules and you lose synchronization between the strings and the vars. Here's a simple example:
define([
'jquery',
'handlebars',
'backbone',
'mymodel',
'mycontrolleranimals',
'mycontrollerpeople',
'myview_cats',
'myview_dogs',
'myview_birds'
],
function(
$,
Handlebars,
Backbone,
MyModel,
MyControllerAnimals,
MyControllerPeople,
MyViewDogs,
MyViewCats,
MyViewBirds) {
Sure, you caught the error because you were looking for it, but what happens in a RequireJS application is that you get weird errors in your application because you were trying to use the MyViewDogs, but myview_cats was actually bound to that variable.To be perfectly honest, I didn't build the system, so don't that it was configured correctly.
define(function(require) {
var $ = require('jquery'),
Handlebars = require('handlebars'),
Backbone = require('backbone'),
MyModel = require('mymodel'),
MyControllerAnimals = require('mycontrolleranimals');
Also require.js comes with an optimizer that automatically concatenates all required files (and no more!) minifies them and you don't have to worry about script order. Also using the text plugin you can package templates (text files) along with the rest of the scripts.What's interesting is that requireJS pulls a move very similar to Angular and reads Function.prototype.toString() to pull those definitions back up into the define() call, so it still works if an async call needs to be made. That's really fantastic. As we've seen with Angular, there are some quirks (old browsers, mainly), but code like this will be optimized out by r.js so there will be no problems in production.
Thanks for the pointer, I may just change all of my definitions after seeing this.
define(function (require) {
'use strict';
var Backbone = require('backbone');
var Handlebars = require('lib/handlebars/handlebars');
var someTemplate = require('text!component/templates/some-template.hbs');
http://requirejs.org/docs/whyamd.html#sugarThe pain point you describe is not a pain point for my team, and even if it was a pain point, it is perfectly possible to abstract the repetition[1], which you are of course aware of since you use Angular. FWIW, we have not felt the need to have any modules with 20 includes.
[1] http://www.dustingetz.com/2013/05/13/javascript-dependency-i...
> Care must be taken that the $inject annotation is kept in sync with the actual arguments in the function declaration.
> This method of annotation is useful for controller declarations since it assigns the annotation information with the function.
For example:
angular.module('app').controller('someController', function ($scope, ModelService, AuthService) {
$scope.something = 'Blah';
});
Works just fine as long as it isn't minimized, and ngmin would turn it into something like: angular.module('app').controller('someController', ['$scope', 'ModelService', 'AuthService', function ($scope, ModelService, AuthService) {
$scope.something = 'Blah';
}]);
Which is then safe to run through a minimizer.You should look into Dojo Toolkit source code, which now is almost entirely built on AMD.
Regarding "distinct JS downloads for each and every page": again, look at Dojo Toolkit source code and its build system.
define(function() {
var $ = require("jquery");
});
This will require one module per file and either define aliases inside config.js or using full path to the modules, but will not push you to define any dependencies upfront.Also as a bonus, when you use r.js optimizer, which will concatenate your .js file into one giant file, it automatically resolve dependencies and rewrite header for you.
Also minor gotcha I had to deal with - since requirejs literally parse JS code for any require("..") calls, you can not put module name into variable and do require(variable_name) unless this code already loaded in the current context. So try always put actual name into require("...") call.
disclaimer: working on quite large require.js powered app - https://www.myedu.com/ - not entire app is converted into require.js, but you can already checkout My Jobs page to get an idea of what is possible - e.g. async loading of various submodules when needed depending on current route.
In my experience, requirejs has been nothing but one over-complicated under-documented and inflexible mess
Alex Sexton's handlebars plugin is a great example of what sets this apart: https://github.com/SlexAxton/require-handlebars-plugin
- The javaScript code only sees the compiled template function
- Handlebars partials and helpers are automatically discovered and registered as needed
- The optimizer can be used to precompile all template code, makes for fast page loads
I've been using this with an i18n solution that folds in the MessageFormat.js project as well, which makes for a nice pluralization system even if you don't need true localization.
I develop JS primarily for the frontend, and I use Grunt, a global namespace, and concat (or similar tooling) to piece things together.
Doesn't r.js execute dependency resolution code at run time? Can all references to r.js be fully compiled out? Even a wrapper like Almond seems to leave behind this kind of extra cruft. I don't want any dependency resolution code in the production build, because that's a problem that needs to be solved at compile time.
The god-file approach to development leads to things like lots of search and replace when something needs renamed, name collision, and duplicated utility code everywhere.
"possibilistic" said dependency resolution must be done at compile time:
> I don't want any dependency resolution code in the production build, because that's a problem that needs to be solved at compile time.
We had faced poor load time performance because of this.