Browserify does not work - why? - javascript

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>

Related

Load a javascript file into a module pattern on Client-side

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();

Browserify --standalone with ES6 modules and multiple source files and exports

I am trying to use Gulp, Browserify, and Babelify to compile and transform multiple ES6 files into a single JavaScript library that can be shared with other developers.
I am trying to use multiple ES6 source files, each of which uses ES6 modules using export. I want them all to be wrapped up into a single class/function like a 'namespace'.
It seems like Browserify's --standalone option is designed to do this, but I can only get it to work when there is a single input file. When there are multiple source files with exports, I can't get them all to be included in the 'namespace' class, and I can't control which source file's exports ultimately gets picked to be in the 'namespace' class.
In this example, a.js and b.js are the source files, and I am expecting them to be bundled together in a 'namespace' class called TestModule.
a.js
export function fromA() {
console.log('Hello from a.js');
}
b.js
export function fromB() {
console.log('Hello from b.js');
}
gulpfile.js
const browserify = require('browserify');
const gulp = require('gulp');
const log = require('gulplog');
const plumber = require('gulp-plumber');
const source = require('vinyl-source-stream');
function minimalExample(done) {
return browserify({
entries: [
'./src/a.js',
'./src/b.js'
],
standalone: 'TestModule' // output as a library under this namespace using a umd wrapper
})
.transform('babelify')
.bundle()
.on('error', log.error)
.pipe(source('minimalExample.js'))
.pipe(plumber())
.pipe(gulp.dest('./dist'));
}
module.exports = {
minimalExample
};
What I want
I want minimalExample.js to have an object named TestModule that has functions fromA() and fromB(), so that I can call both methods. I should be able to run either of these commands from the console:
TestModule.fromA()
TestModule.fromB()
What is actually happening
When I load minimalExample.js in a browser, open the console, and inspect the TestModule object, it exists, but it is missing the function from a.js. It only has the function from b.js:
Am I missing a setting somewhere? Is there a way to get Browserify to include all the exports in the standalone 'namespace' class?
Update 1
Prompted by #Zydnar's discussion, I did the obvious thing and actually looked at the output file, minimalExample.js. I don't understand how the transforms are intended to work or what is going wrong yet; I'm still looking at that. But I do see both input files have been transformed and included in the output.
Here is the actual output, and the same thing but pretty-printed by Chrome.
Thanks to help on the browserify project on Github, I have an answer for this. Renée Kooi pointed me in the right direction. They said:
If you have multiple entry points, all of them are executed, but browserify doesn't merge modules, which could cause bad unexpected behaviour.
The solution is to have a single file that acts as an entry point for Browserify that exports everything you want exported. Use that single file as your input source file in the entries option. Browserify will walk your app's dependency tree and include the dependencies it requires. Anything exported by the entry point file will be included in the exported module as expected.
A complete example follows. main.js is the entry point file.
a.js
export function fromA() {
console.log('Hello from a.js');
}
b.js
export function fromB() {
console.log('Hello from b.js');
}
main.js (This one is new)
export * from './a.js';
export * from './b.js';
gulpfile.js
const browserify = require('browserify');
const gulp = require('gulp');
const log = require('gulplog');
const plumber = require('gulp-plumber');
const source = require('vinyl-source-stream');
function minimalExample(done) {
return browserify({
entries: [
'./src/main.js' // THIS LINE HAS CHANGED FROM THE QUESTION
],
standalone: 'TestModule'
})
.transform('babelify')
.bundle()
.on('error', log.error)
.pipe(source('minimalExample.js'))
.pipe(plumber())
.pipe(gulp.dest('./dist'));
}
module.exports = {
minimalExample
};
Now when you run the minimalExample task with gulp, the file generated will have both TestModule.fromA() and TestModule.fromB() functions.

Packaging-up Browser/Server CommonJS modules with dependancies

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.

How requirejs load commonjs packages?

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.

Why do I see "define not defined" when running a Mocha test with RequireJS?

I am trying to understand how to develop stand-alone Javascript code. I want to write Javscript code with tests and modules, running from the command line. So I have installed node.js and npm along with the libraries requirejs, underscore, and mocha.
My directory structure looks like this:
> tree .
.
├── node_modules
├── src
│   └── utils.js
└── test
└── utils.js
where src/utils.js is a little module that I am writing, with the following code:
> cat src/utils.js
define(['underscore'], function () {
"use strict";
if ('function' !== typeof Object.beget) {
Object.beget = function (o) {
var f = function () {
};
f.prototype = o;
return new f();
};
}
});
and test/utils.js is the test:
> cat test/utils.js
var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});
requirejs(['../src/utils'], function(utils) {
suite('utils', function() {
test('should always work', function() {
assert.equal(1, 1);
})
})
});
which I then try to run from the top level directory (so mocha sees the test directory):
> mocha
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Calling node's require("../src/utils") failed with error: ReferenceError: define is not defined
at /.../node_modules/requirejs/bin/r.js:2276:27
at Function.execCb (/.../node_modules/requirejs/bin/r.js:1872:25)
at execManager (/.../node_modules/requirejs/bin/r.js:541:31)
...
So my questions are:
Is this the correct way to structure code?
Why is my test not running?
What is the best way to learn this kind of thing? I am having a hard time finding good examples with Google.
Thanks...
[sorry - momentarily posted results from wrong code; fixed now]
PS I am using requirejs because I also want to run this code (or some of it) from a browser, later.
Update / Solution
Something that is not in the answers below is that I needed to use mocha -u tdd for the test style above. Here is the final test (which also requires assert) and its use:
> cat test/utils.js
var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});
requirejs(['../src/utils', 'assert'], function(utils, assert) {
suite('utils', function() {
test('should always work', function() {
assert.equal(1, 1);
})
})
});
> mocha -u tdd
.
✔ 1 tests complete (1ms)
The reason your test isn't running is because src/utils.js is not a valid Node.js library.
According to the RequireJS documentation, in order to co-exist with Node.js and the CommonJS require standard, you need to add a bit of boilerplate to the top of your src/utils.js file so RequireJS's define function is loaded.
However, since RequireJS was designed to be able to require "classic" web browser-oriented source code, I tend to use the following pattern with my Node.js libraries that I also want running in the browser:
if(typeof require != 'undefined') {
// Require server-side-specific modules
}
// Insert code here
if(typeof module != 'undefined') {
module.exports = whateverImExporting;
}
This has the advantage of not requiring an extra library for other Node.js users and generally works well with RequireJS on the client.
Once you get your code running in Node.js, you can start testing. I personally still prefer expresso over mocha, even though its the successor test framework.
The Mocha documentation is lacking on how to set this stuff up, and it's perplexing to figure out because of all the magic tricks it does under the hood.
I found the keys to getting browser files using require.js to work in Mocha under Node: Mocha has to have the files added to its suites with addFile:
mocha.addFile('lib/tests/Main_spec_node');
And second, use beforeEach with the optional callback to load your modules asynchronously:
describe('Testing "Other"', function(done){
var Other;
beforeEach(function(done){
requirejs(['lib/Other'], function(_File){
Other = _File;
done(); // #1 Other Suite will run after this is called
});
});
describe('#1 Other Suite:', function(){
it('Other.test', function(){
chai.expect(Other.test).to.equal(true);
});
});
});
I created a bootstrap for how to get this all working: https://github.com/clubajax/mocha-bootstrap
You are trying to run JS modules designed for browsers (AMD), but in the backend it might not work (as modules are loaded the commonjs way). Because of this, you will face two issues:
define is not defined
0 tests run
In the browserdefine will be defined. It will be set when you require something with requirejs. But nodejs loads modules the commonjs way. define in this case is not defined. But it will be defined when we require with requirejs!
This means that now we are requiring code asynchronously, and it brings the second problem, a problem with async execution.
https://github.com/mochajs/mocha/issues/362
Here is a full working example.
Look that I had to configure requirejs (amd) to load the modules, we are not using require (node/commonjs) to load our modules.
> cat $PROJECT_HOME/test/test.js
var requirejs = require('requirejs');
var path = require('path')
var project_directory = path.resolve(__dirname, '..')
requirejs.config({
nodeRequire: require,
paths: {
'widget': project_directory + '/src/js/some/widget'
}
});
describe("Mocha needs one test in order to wait on requirejs tests", function() {
it('should wait for other tests', function(){
require('assert').ok(true);
});
});
requirejs(['widget/viewModel', 'assert'], function(model, assert){
describe('MyViewModel', function() {
it("should be 4 when 2", function () {
assert.equal(model.square(2),4)
})
});
})
And for the module that you want to test:
> cat $PROJECT_HOME/src/js/some/widget/viewModel.js
define(["knockout"], function (ko) {
function VideModel() {
var self = this;
self.square = function(n){
return n*n;
}
}
return new VideModel();
})
Just in case David's answer was not clear enough, I just needed to add this:
if (typeof define !== 'function') {
var define = require('amdefine')(module);
}
To the top of the js file where I use define, as described in RequireJS docs ("Building node modules with AMD or RequireJS") and in the same folder add the amdefine package:
npm install amdefine
This creates the node_modules folder with the amdefine module inside.
I don't use requirejs so I'm not sure what that syntax looks like, but this is what I do to run code both within node and the browser:
For imports, determine if we are running in node or the browser:
var root = typeof exports !== "undefined" && exports !== null ? exports : window;
Then we can grab any dependencies correctly (they will either be available already if in the browser or we use require):
var foo = root.foo;
if (!foo && (typeof require !== 'undefined')) {
foo = require('./foo');
}
var Bar = function() {
// do something with foo
}
And then any functionality that needs to be used by other files, we export it to root:
root.bar = Bar;
As for examples, GitHub is a great source. Just go and check out the code for your favorite library to see how they did it :) I used mocha to test a javascript library that can be used in both the browser and node. The code is available at https://github.com/bunkat/later.

Categories

Resources