Converting CommonJS to AMD - node.js

I have a simple CommonJS module published on NPM and Bower that basically just looks like this:
function Foo(){}
module.exports = new Foo();
now the easiest way to convert to AMD format would be just to publish a second version that was AMD compatible like so:
define(function (require, exports, module) {
function Foo(){}
module.exports = new Foo();
});
but I thought there was a way you can shim the CommonJS module using requirejs.config like so:
requirejs.config({
paths:{
'foo':'assets/vendor/foo'
},
shim:{
'foo' :{
exports: 'Foo'
}
}
});
but this doesn't seem to work. I figure that the shim tool does the wrapping that I did above for you, but I am not entirely sure.

The Problem
shim cannot do as much as you want it to do. When RequireJS evaluates the symbol you give in exports, it evaluates it in the global space. So using exports works fine if you can access the variable you want to export from the global space. If library foo exports Foo into the global space, that works fine.
What you are trying to do is have a module that exports its API through module work with a shim. This cannot work because RequireJS cannot guess that the module being loaded requires that a global module object be already available to the module being loaded. In the simplest case, loading such module will result in a ReferenceError because module does not exist. There would be ways to fake the module.exports thing that would work in the most trivial cases but it would not work as a general solution.
A Solution
You can use r.js to convert files that are written in the CommonJS format to what RequireJS needs. It is documented here. The documentation gives the following synopsis:
node r.js -convert path/to/commonjs/modules/ path/to/output
You should also read this part of the README for some caveats.

Related

Re-declaring libraries as dependencies within every single module

I'm working on the project that uses require.js and I was faced with a simple question about declaring libraries as dependencies within every single modules. I saw many examples with require.js and in every of them libraries like Backbone, jquery, underscore etc was declared in every module. And it would be fine if your application consists of only couple of modules. But if your application has 40-50 modules it becomes a bit tedious to define jquery every single time.
On the other hand we can load all libraries into the require() this way:
// Just an example
require.config({
paths: {
jquery: '../bower_components/jquery/jquery',
underscore: '../bower_components/underscore/underscore',
backbone: '../bower_components/backbone/backbone'
}
});
require(['jquery', 'underscore', 'backbone'], function () {
require([
'app',
'bootstrap'
], function (App) {
var app = new App();
document.body.appendChild(app.el);
});
});
And then we can use Backbone, '_' and '$' into the App without declaring them as dependencies.
So I'm trying to understand why we should define them every time. Is it just a strict adherence to the Module pattern or something else?
Thanks.
Having your libraries passed in as arguments to your require factory function is a form of dependency injection. Now, depending on exactly how AMD-friendly your library dependencies are, you may even be able to use several different versions of the library at once in an application. Writing your modules in this way with explicit library dependencies can allow you future flexibility of mixing modules which require jQuery 1.8 and jQuery 2.0, for instance. A different jQuery version can be passed to each module.
When you don’t define all your dependencies explicitly every time, then you’re relying on the global variable (window.$ or window._) created as a side effect of loading the library. In that case, all the modules have to depend on the same version of the library.

Why do I need to add a "shim" for AngularJS when using Require.js?

I have seen several examples that use this:
main.js
/*global require*/
'use strict';
require.config({
paths: {
angular: './angular',
app: './Content/app',
ngAnimate: './Scripts/angular-animate',
uiRouter: './Scripts/angular-ui-router'
},
shim: {
angular: {
exports: 'angular'
}
}
});
require(['angular', 'app'], function (angular) {
angular.bootstrap(document, ['app']);
});
Can someone explain to me why the shim is needed? My application uses other modules such as angular-ui router, jQuery etc. Do I need to do something similar and add a shim for these?
The rule is pretty simple: if a library/script/package/plugin is AMD-aware, then you don't need a shim. (Actually, you must not use a shim for it.) If it is not AMD-aware, then you need a shim.
A library/etc is AMD-aware if it detects that an AMD loader is present and calls define to make itself known to the loader.
jQuery from about 1.8 onwards has not needed a shim because it calls define. Angular, on the other hand, does not call define.
To know whether a specific piece of code needs a shim, you can read its documentation or if the documentation is not clear on this, then you can check the source code for a call to define. For instance jQuery 1.11.0 has this code:
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
});
}
How it looks like will vary from one case to the other but the basic think you want to look for is the check that define exists, is a function, has the amd property set and the call to define.
(Note that jQuery is a special case where they decided to hard code the name of the module in the define call (first parameter: jquery). Generally the name of the module won't be present in the define call but will be left for RequireJS to infer on the basis of the file name.)

Write a module that works both in nodejs and requirejs

I wrote a small parser that currently works in node app, but wondering if there is a way that I can make a module that will work both in NodeJS app and client side app that uses requirejs?
path/to/lib/index.js
function someRandom(strings) {
// we are doing something here
return strings
}
exports.someRandom = someRandom;
Right now I'm getting this in client-side
Uncaught ReferenceError: exports is not defined
I know that I can use node requirejs and then change the structure to use define but is there other way without adding node requirejs?
This is my js/main.js file
require(["path/to/lib/index"], function(something) {
// will do something here
});
The way I prefer to do it is to write all my modules in the AMD syntax (use define) and use amd-loader to load them in Node. Note that this solution is not using RequireJS, even though the AMD syntax is used.
However, there's a way to do it without having to use the AMD syntax. You can use r.js to wrap your Node modules. For instance, if you put your tree of Node modules in in, you can do:
$ r.js -convert in out
This will create in out a tree of files that correspond to those in in but wrapped with the define call. You can then load these in the browser using RequireJS. There are limitations. Some are obvious, like not being able to use the Node modules that depend on the Node runtime (like fs, child_process, etc.). Some are more subtle, like the fact that you can't use require(foo) where foo is a variable (RequireJS will handle only string literals there). See the documentation for the details.

Typescript/RequireJS having issues with an MVC application

I have the following code in Visual Studio, in an MVC application;
/scripts/bin/models/ViewModel.ts
export class ViewModel {
// view model code
}
Now, I have downloaded requirejs, and set the build mode for typescript to AMD type, so that its output looks such as....
define(["require", "exports"], function(require, exports) {
And so on ...
So then I declare my app/config.js file like so;
require.config({
baseUrl: '/scripts/bin'
});
And I try to load this up, I have requirejs loaded into the scripts, and attempt to call it...
require(['models/ViewModel'], function (viewModel) {
console.log("test");
});
And I am simply told that it is an invalid call. No other details. The path that it shows is completely correct, too. Is there some kind of additional configuration required? The requirejs documentation is extremely vague about this.
SOLUTION
This turned out to have nothing to do with requirejs, but instead had to do with IIS.
By default, IIS has a rule known as hiddenSegments. It does not allow you to bring in any code from a folder with bin in the path. I simply renamed the folder from bin to something else, and it worked fine.
Using require.js with TypeScript is a combination of your .html, require.config, module exports and imports.
For a step-by-step guide on moving from CommonJs TypeScript to AMD and require.js, have a look here.
Have fun.
The TypeScript compiler doesn't have any knowledge of your require.config - so when you use paths relative to that baseUrl they look invalid to the compiler.
Until something is done to bridge that slight mismatch (i.e. make the compiler super-clever so it can look for require.config sections and use them to check paths) it is easier not to set a baseUrl and use the full path in your import statements:
import vm = require('./scripts/bin/models/ViewModel');
Are you sure that the require call is done with [] and not just
require('models/ViewModel', function (viewModel) { // this is an error
console.log("test");
});
See : http://requirejs.org/docs/errors.html#requireargs

Do RequireJS modules "inherit" dependencies?

If I have a module that requires an application namespace, e.g.:
define(["app"], function(App){
[...]
});
... and the namespace requires libraries used by all of my modules, e.g.:
define(["jquery", "underscore", "backbone"], function($, _, Backbone){
[...]
});
... then all of my modules have access to the libraries required by the namespace, i.e. I can use $, _, and Backbone.
I like this behavior because I can avoid being repetitious, but I suspect that I'm cheating somehow, and that I should require libraries in each module.
Can anyone set me straight here?
Yeah, that's kinda hacky. You only have access to jQuery, underscore and backbone because they're also defined onto the global scope. Backbone and undersocre aren't real AMD module, they have to use a shim config. jQuery declare himself on the global scope and as an AMD module so it works everywhere.
So, yes it work like that, but it's not optimal. Real AMD module (non-shimmed) won't work this way as they need to be passed in the define functions arguments, and you won't be able to pull only one module to test it in a separate environment, etc. This way, you cannot load different versions of a scripts to work with different module/app section/page.
The goal of AMD is to bring modularity to your code so every module declare it's own dependencies and will work out of the box it without relying on the global scope (which is a good thing to prevent name collision and conflict with third party/other dev working on the same project).
If you find it's redundant to redeclare everytime your base dependencie, create a boilerplate file that you just copy/paste when creating another module (it's better than nothing). And, maybe some command line tools can build AMD module wrapper for you.
Soooo, yes it works, but it won't scale if your project ever get bigger or need to be updated pieces by pieces.
Hope this help !
good news for the above answer: underscore 1.6.0 now is wrapped as a amd module :)
see "lib.chartjs" for exporting globals in not amd wrapped "shimmed" javascript libraries
requirejs.config({
paths: {
"moment": "PATH_TO/js/moment/2.5.0/moment.min",
"underscore": "PATH_TO/js/underscore/1.6.0/underscore",
"jquery": "PATH_TO/js/jquery/1.10.2/jquery.min",
"lib.jssignals": "PATH_TO/js/jssignals/1.0.0-268/signals.min",
// WORKAROUND : jQuery plugins + shims
"lib.jquery.address": "PATH_TO/js/jqueryaddress/1.6/jquery-address"
"lib.jquery.bootstrap":"PATH_TO/js/bootstrap/3.0.3/bootstrap",
"lib.chartjs": "PATH_TO/js/chartjs/0.2/Chart.min",
},
shim: {
"lib.jquery.address": {deps: ["jquery"]},
"lib.jquery.bootstrap": {deps: ["jquery"]},
"lib.chartjs": {deps: ["jquery"], exports: "Chart"},
}
});

Resources