I follow http://requirejs.org/docs/api.html#packages to learn how RequireJs load CommonJS modules, but I can't get it.
I have below file.
foo/foo.js
main.js
require.js
foo/foo.js with content:
exports.bar = '1234';
exports.xyz = function noop() {};
main.js:
requirejs.config({
packages: [{name:'foo', main: 'foo'}]
});
require(['foo'], function(foo) {
console.log(foo.bar);
});
It said can't read bar of undefined
You've missed an important part of the documentation you link to in your question:
While the packages can have the CommonJS directory layout, the modules themselves should be in a module format that RequireJS can understand. Exception to the rule: if you are using the r.js Node adapter, the modules can be in the traditional CommonJS module format. You can use the CommonJS converter tool if you need to convert traditional CommonJS modules into the async module format that RequireJS uses.
(Emphasis added.)
This is not something that RequireJS understands:
exports.bar = '1234';
exports.xyz = function noop() {};
It would have to be:
define(function(require, exports, module) {
exports.bar = '1234';
exports.xyz = function noop() {};
});
Either you do this conversion manually or you use r.js -convert to do the conversion for you.
Related
I have a simple javascript module pattern that executes client-side.
var module = (function() {
var _privateVariable = 10;
function publicMethod () {
console.log("public method; private variable: " + _privateVariable);
}
return {
publicMethod: publicMethod
};
})();
Let's say I want to load in another module (which also uses a module pattern) from a separate javascript file. How do I do that, i.e. something like:
?? Load other module here ??
var _other_module = ??
var module = (function() {
var _privateVariable = 10;
function publicMethod () {
console.log("public method; private variable: " + _privateVariable);
console.log("public method; other module: " + other_module.publicMethod());
}
return {
publicMethod: publicMethod
};
})();
You can't. To load another module form another file you need to use a Module formats.
It's a long story, i will try to shorten.
Let's talk first about the old way. earlier the developer used to load alle the JS-Files in a certain order in the HTML-Page. If we have 2 JS-Files index.js and variables.js and we want to get a variable from varible.js in index.js, we had load them like that
<script src="variables.js"></script>
<script src="index.js"></script>
But this is not a good way and has many negatives.
The right way is to use a Module formats.
There are many Module formats,
Asynchronous Module Definition (AMD)
CommonJS
Universal Module Definition (UMD)
System.register
ES6 module format
and each format has own Syntax.
For example CommonJS:
var dep1 = require('./dep1');
module.exports = function(){
// ...
}
but the Browsers dont't understand that. so we need a Module bundlers or Module loaders
to convert our code to code which browsers can understand.
Module bundlers: Bundle your inter-dependent Javascript files in the correct order
Browserify
Webpack
Module loaders: a module loader interprets and loads a module written in a certain module format.
RequireJS
SystemJS
This article will help you so much to understand exactly how modules work.
Not sure which context you are doing this.
But. In node.JS this would be typically done by
module1.js
module.exports.publicMethod = function() {}
index.js
const module1 = require('./module1.js');
module1.publicMethod();
or
const {publicMethod} = require('./module1.js');
publicMethod();
Having trouble with WebPack. I have a vendor library (saying ChildVendor), which implements requireJS and commonJS compatibility, so, I need to require it in my WebPack project like var lib = require('./childVendor');. This ChildVendor library has a dependency (saying SuperVendor), and both of them are requirejs- and commonjs-adapted, so, the heading of childVendor.js looks like:
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(["superVendor"], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('superVendor'));
} else {
root.Shepherd = factory(root.SuperVendor);
}
}(this, function(SuperVendor) { /*...*/ }));
The main problem is that I need to include that SuperVendor library globally on html-file manually (so, it is just initialized as window.SuperVendor), because it should be used by other third-party libraries.
To solve this, I have tried webpack.ProvidePlugin, like
plugins: [
new webpack.ProvidePlugin({
'superVendor': 'SuperVendor'
})
],
but an error is still the same (Module not found: Error: Can't resolve 'superVendor' in '...').
ProvidePlugin is not the solution for what you want to do. The configuration you've set with it tells Webpack:
Whenever superVendor is encountered as a free variable in a module, load the module SuperVendor and set the variable superVendor to what exported by SuperVendor.
In other words if you have a module that contains this:
superVendor.someMethod();
Webpack interprets it as if it were:
var superVendor = require("SuperVendor");
superVendor.someMethod();
What you should use it the externals configuration option:
externals: {
'superVendor': 'SuperVendor'
}
This tells Webpack that if the module superVendor is required it should be sought from the external environment with the name SuperVendor.
I have the following code that I browserify to bundle.js, that I include (before loading any other .js file) on my front-end. The file I browserify is simply this this:
var firebase = require('firebase')
I then call authorize() on this variable, in the next file that is included on the front-end, but I get an error saying firebase is not defined?
Browserify is a module bundler that enables you to use CommonJS (Node) modules in your browser. This implies that your project must follow CommonJS conventions to export (exports, module.exports) and import (require) modules. Here is a basic example:
Your module (module.js)
var foo = function () {
console.log('Foo');
};
var bar = function () {
console.log('Bar');
};
module.exports = {
foo: foo,
bar: bar
};
Your entry point (main.js)
var module = require('./module');
module.foo(); // Foo
module.bar(); // Bar
This code will work out-of-the-box with Node, but your browser cannot interpret it. This is where Browserify is useful...
When you run the command browserify main.js -o bundle.js on your entry point, Browserify traverses all your dependencies (here module.js) and loads them in a bundle. This bundle is usable in your browser, so you can now load it in a script tag:
<script src="bundle.js"></script>
Lets say I'm writing a module in JavaScript which can be used on both the browser and the server (with Node). Lets call it Module. And lets say that that Module would benefit from methods in another module called Dependancy. Both of these modules have been written to be used by both the browser and the server, à la CommonJS style:
module.js
if (typeof module !== 'undefined' && module.exports)
module.exports = Module; /* server */
else
this.Module = Module; /* browser */
dependancy.js
if (typeof module !== 'undefined' && module.exports)
module.exports = Dependancy; /* server */
else
this.Dependancy = Dependancy; /* browser */
Obviously, Dependancy can be used straight-out-of-the-box in a browser. But if Module contains a var dependancy = require('dependency'); directive in it, it becomes more of a hassle to 'maintain' the module.
I know that I could perform a global check for Dependancy within Module, like this:
var dependancy = this.Dependancy || require('dependancy');
But that means my Module has two added requirements for browser installation:
the user must include the dependency.js file as a <script> in their document
and the user must make sure this script is loaded before module.js
Adding those two requirements throws the idea of an easy-going modular framework like CommonJS.
The other option for me is that I include a second, compiled script in my Module package with the dependency.js bundled using browserify. I then instruct users who are using the script in the browser to include this script, while server-side users use the un-bundled entry script outlined in the package.json. This is preferable to the first way, but it requires a pre-compilation process which I would have to run every time I changed the library (for example, before uploading to GitHub).
Is there any other way of doing this that I haven't thought of?
The two answers currently given are both very useful, and have helped me to arrive at my current solution. But, as per my comments, they don't quite satisfy my particular requirements of both portability vs ease-of-use (both for the client and the module maintainer).
What I found, in the end, was a particular flag in the browserify command line interface that can bundle the modules and expose them as global variables AND be used within RequireJS (if needed). Browserify (and others) call this Universal Module Definition (UMD). Some more about that here.
By passing the --standalone flag in a browserify command, I can set my module up for UMD easily.
So...
Here's the package.js for Module:
{
"name": "module",
"version": "0.0.1",
"description": "My module that requires another module (dependancy)",
"main": "index.js",
"scripts": {
"bundle": "browserify --standalone module index.js > module.js"
},
"author": "shennan",
"devDependencies": {
"dependancy": "*",
"browserify": "*"
}
}
So, when at the root of my module, I can run this in the command line:
$ npm run-script bundle
Which bundles up the dependancies into one file, and exposes them as per the UMD methodology. This means I can bootstrap the module in three different ways:
NodeJS
var Module = require('module');
/* use Module */
Browser Vanilla
<script src="module.js"></script>
<script>
var Module = module;
/* use Module */
</script>
Browser with RequireJS
<script src="require.js"></script>
<script>
requirejs(['module.js'], function (Module) {
/* use Module */
});
</script>
Thanks again for everybody's input. All of the answers are valid and I encourage everyone to try them all as different use-cases will require different solutions.
Of course you could use the same module with dependency on both sides. You just need to specify it better. This is the way I use:
(function (name, definition){
if (typeof define === 'function'){ // AMD
define(definition);
} else if (typeof module !== 'undefined' && module.exports) { // Node.js
module.exports = definition();
} else { // Browser
var theModule = definition(), global = this, old = global[name];
theModule.noConflict = function () {
global[name] = old;
return theModule;
};
global[name] = theModule;
}
})('Dependency', function () {
// return the module's API
return {
'key': 'value'
};
});
This is just a very basic sample - you can return function, instantiate function or do whatever you like. In my case I'm returning an object.
Now let's say this is the Dependency class. Your Module class should look pretty much the same, but it should have a dependency to Dependency like:
function (require, exports, module) {
var dependency = require('Dependency');
}
In RequireJS this is called Simplified CommonJS Wrapper: http://requirejs.org/docs/api.html#cjsmodule
Because there is a require statement at the beginning of your code, it will be matched as a dependency and therefore it will either be lazy loaded or if you optimize it - marked as a dependency early on (it will convert define(definition) to define(['Dependency'], definition) automatically).
The only problem here is to keep the same path to the files. Keep in mind that nested requires (if-else) won't work in Require (read the docs), so I had to do something like:
var dependency;
try {
dependency = require('./Dependency'); // node module in the same folder
} catch(err) { // it's not node
try {
dependency = require('Dependency'); // requirejs
} catch(err) { }
}
This worked perfectly for me. It's a bit tricky with all those paths, but at the end of the day, you get your two separate modules in different files which can be used on both ends without any kind of checks or hacks - they have all their dependencies are work like a charm :)
Take a look at webpack bundler.
You can write module and export it via module exports. Then You can in server use that where you have module.export and for browser build with webpack. Configuration file usage would be the best option
module.exports = {
entry: "./myModule",
output: {
path: "dist",
filename: "myModule.js",
library: "myModule",
libraryTarget: "var"
}
};
This will take myModule and export it to myModule.js file. Inside module will be assigned to var (libraryTarget flag) named myModule (library flag).
It can be exported as commonJS module, war, this, function
Since bundling is node script, this flag values can be grammatically set.
Take a look at externals flag. It is used if you want to have special behavior for some dependencies. For example you are creating react component and in your module you want to require it but not when you are bundling for web because it already is there.
Hope it is what you are looking for.
Currently, I use a few defines via the Google Closure Compiler along the lines of IS_CJS and IS_BROWSER, and just have different files that get built (browser.myproject.js, cjs.myproject.js, etc).
Is this the standard way of doing things? If not, what is it and what are the advantages?
I've been using the following preamble in all my projects, for libraries that are loaded by both browser and server code:
if (define === undefined) {
var define = function(f) {
require.paths.unshift('.');
f(require, exports, module);
};
}
define(function(require, exports, module) {
...
// main library here
...
// use require to import dependencies
var v = require(something);
...
// use exports to return library functions
exports.<stuff> = { some stuff };
...
});
This works to load the library with a require(<library>) call running on my node server, as well as with a require(<library>) call with RequireJS. On the browser, nested require calls are pre-fetched by RequireJS prior to library execution, on Node these dependencies are loaded synchronously. Since I'm not using my libraries as stand-alone scripts (via a script tag in the html), and only as dependencies for scripts loaded via the script tag, this works well for me.
However, looking at stand-alone libraries, it looks like the following preamble seems to be the most flexible. (cut and paste from the Q promise library
(function (definition, undefined) {
// This file will function properly as a <script> tag, or a module
// using CommonJS and NodeJS or RequireJS module formats. In
// Common/Node/RequireJS, the module exports the Q API and when
// executed as a simple <script>, it creates a Q global instead.
// The use of "undefined" in the arguments is a
// micro-optmization for compression systems, permitting
// every occurrence of the "undefined" variable to be
// replaced with a single-character.
// RequireJS
if (typeof define === "function") {
define(function (require, exports, module) {
definition(require, exports, module);
});
// CommonJS
} else if (typeof exports === "object") {
definition(require, exports, module);
// <script>
} else {
Q = definition(undefined, {}, {});
}
})(function (serverSideRequire, exports, module, undefined) {
...
main library here
...
/*
* In module systems that support ``module.exports`` assignment or exports
* return, allow the ``ref`` function to be used as the ``Q`` constructor
* exported by the "q" module.
*/
for (var name in exports)
ref[name] = exports[name];
module.exports = ref;
return ref;
});
While wordy, it's impressively flexible, and simply works, no matter what your execution environment is.
You can use uRequire that converts modules written in either AMD or CommonJS to either AMD, CommonJS or UMD through a template system.
Optionally uRequire builds your whole bundle as a combinedFile.js that runs in ALL environments (nodejs, AMD or module-less browser < script/>) thats using rjs optimizer and almond under the hood.
uRequire saves you from having to maintain any boilerplate in each module - just write plain AMD or CommonJS modules (as .js, .coffee, .coco, .ls etc) without gimmicks.
Plus you can declaratively add standard functionality such as exporting a module to global such as window.myModule along with a noConflict() method, or have runtimeInfo (eg __isNode, __isAMD) selectively or replace/remove/inject a dependency while building, automatically minify, manipulate module code and much more.
All of these configuration options can be turned on and off per bundle OR per module, and you can have different build profiles (development, test, production etc) that derive(inherit) from each other.
It works great with grunt through grunt-urequire or standalone and it has a great watch option that rebuilds ONLY changed files.
Have you tried this: https://github.com/medikoo/modules-webmake#modules-webmake ?
It's the approach I'm taking, and it works really well. No boilerplate in a code and you can run same modules on both server and client side