coffee -cj overwrites module.exports for each class - javascript

I just can't get my head around how this is supposed to work: As I understand, a pretty common way to define a class/module in CoffeeScript is by using module.exports = class MyClass at the top of the file. I would also guess that the coffee compiler would facilitate this pattern. Take this minimalist example:
# src/Foo.coffee
module.exports = class Foo
# src/Bar.coffee
module.exports = class Bar
Then compile and join the two with:
coffee -cj all.js src
The result is all.js where module.exports is redefined/overwritten for each module:
// Generated by CoffeeScript 1.4.0
(function() {
var Bar, Foo;
module.exports = Bar = (function() {
function Bar() {}
return Bar;
})();
module.exports = Foo = (function() {
function Foo() {}
return Foo;
})();
}).call(this);
If I now try to do this, the result would be an error stating that the Foo module cound not be found, and rightly so because the last module (here: Bar) has redefined module.exports to only contain itself.
Foo = require('foo');
I guess this is quite the noob question but I can't seem to get a good answer anywhere.

This is pretty much the desired behaviour... You're merging two modules into one, and they both want to be at the top level, so one of them has to win.
One possible solution would be as follows:
# src/Foo.coffee
module.exports.Foo = class Foo
# src/Bar.coffee
module.exports.Bar = class Bar
which yields:
# all.js
(function() {
var Bar, Foo;
module.exports.Bar = Bar = (function() {
function Bar() {}
return Bar;
})();
module.exports.Foo = Foo = (function() {
function Foo() {}
return Foo;
})();
}).call(this);
And then you can use (in CoffeeScript)
{Foo, Bar} = require "all"
to get at the classes contained therein

Related

How to force TypeScript exports to the end of the JS output?

I use a lot of export statements like the following, usually to cumulate a module's exports at the bottom of the file:
export { foo1 as bar1, foo2 as bar2, ... }
Lately I have learned that...
let foo : number = 0;
export { foo as bar }
...is not at all the same as...
let foo : number; foo = 0;
export { foo as bar }
...because the latter delivers undefined in exports.bar. This happens because the compiled JavaScript has the export statement of exports.bar = foo before the assignment. I find this hardly intuitive. I read over the TypeScript module pages, but I seem to miss the description of this behaviour. Is it there?
Is there a way to force the output's export statements to be at the bottom rather than right after declaration? Thanks.
This sounds more like a bug in TypeScript. For future reference, TypeScript 1.8 compiles the following code:
let foo : number; foo = 0;
export { foo as bar }
into this JavaScript:
"use strict";
var foo;
exports.bar = foo;
foo = 0;
I tried it with TypeScript 2.0 beta, and it seems like that fixes it:
"use strict";
var foo;
exports.bar = foo;
exports.bar = foo = 0;

Does ES2015 exported class create a closure?

As it's currently compiled via Babel + Webpack, module's exported class will create a closure: variables created inside the module will be shared between class instances.
bar.js:
let foo;
export default class Bar {
set foo(value) {
foo = value;
}
get foo() {
return foo;
}
}
app.js:
import Bar from './bar.js';
var barOne = new Bar();
var barTwo = new Bar();
barOne.foo = 'quux';
console.assert(barTwo.foo === 'quux');
I wonder if this behavour correct according to the spec.
I wonder if this behavour correct according to the spec.
Yes. JavaScript has lexical scope. That doesn't change with classes.
Keep in mind that classes are more or less just syntactic sugar for constructor function + prototype. Would you have had the same question if you wrote
let foo;
function Bar(){};
Bar.prototype = {
set foo(value) {
foo = value;
}
get foo() {
return foo;
}
};
module.exports = Bar;
instead?

passing a default argument to a browserify module

I'm refactoring a javascript codebase and am implementing, but I'm new to node. I might run into some code like this:
foo.js
var foo = {};
foo.bar = function(baz) {
$('body').append(baz)
}
which i would then refactor into the following:
foo.js
var $ = require('jquery')(window);
var foo = {};
foo.bar = require('./bar');
bar.js
module.exports = bar = function(baz) {
$('body').append(baz);
}
What's the correct way to pass the jQuery object from foo.js to bar.js without interfering with the baz parameter when foo.bar(baz) is called?
Just add var $ = require('jquery')(window) to each module that needs jQuery!
Calls to require that resolve to the same path will return a cached copy of the module:
http://nodejs.org/api/modules.html#modules_caching

How to export an object with Browserify?

I started using Browserify and not sure if I completely understand how to use it.
I have a file with some functions bundled in one object in foo.js
var foo = {
f1: function(){...}
f2: function(){...}
}
module.exports = function () {
return foo;
};
And I want to export them to a variable in the main.js file, so I tried doing this:
var bar = require('/foo')();
The goal is to be able to do bar.f1().
Without executing require('/foo') I get only a function definition, so I have to execute it. Am I doing something wrong?
Just export the object:
var foo = {
f1: function(){...}
f2: function(){...}
};
module.exports = foo;

JavaScript design patterns: Injecting a dependency that is not yet created

I have a CommonJS module:
// main-module
module.exports = function () {
var foo,
someModule = require('other-module')(foo);
// A value is given to foo after other-module has been initialised
foo = "bar";
}
As you can see, this requires other-module:
// other-module.js
module.exports = function (foo) {
function example() {
console.log(foo);
// > "bar"
}
}
I would like the example function inside of other-module to be aware of the foo variable inside of main-module, even though is it established after the module is required.
When other-module runs, foo will not be undefined. However, the point is that by time my example function runs, foo will have been given a value of bar.
The pattern above obviously does not work. What design pattern do I need to implement?
I'm not super-familiar with CommonJS, so this might not be the idiomatic way to do it, but using a function instead of a variable should work:
// main-module
module.exports = function () {
var foo,
someModule = require('other-module')(function() { return foo; });
foo = "bar";
}
// other-module.js
module.exports = function (fooFn) {
function example() {
console.log(fooFn());
}
}
The foo value (a string) will be passed by value, so it's undefined inside other-module. You could use an options object that is passed by reference:
var options = {},
someModule = require('other-module')(options);
options.foo = "bar";

Categories