Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Your first Node.js module (cnnr.me)
74 points by c_t_montgomery on May 28, 2012 | hide | past | favorite | 23 comments


The error that is thrown towards the end of this example should probably be passed back to the callback as an argument (e.g. callback(error, result)) instead.

Throwing errors in an asynchronous context can have messy results for trying to handle them. http://benno.id.au/blog/2011/08/08/nodejs-exceptions is a good explanation.


Great point. I'll update the gist. Thanks for bringing this up!


It should also be pointed out you rarely need to edit the package.json manually:

npm init: Prompts for basic/common package.json entries

npm install --save: Install a module and place into dependencies

npm install --save-dev: Install a module and place into dev dependencies

npm install --save-optional: Install a module and place into optional dependencies

http://blog.timoxley.com/post/22371787222/handy-new-options-...


I was debating whether or not to put it in there. Since Isaac mentions it in his article that I link to, I figured most people would see it there. Very valid point though. I think I may edit the post and put it up there. Thanks!


...and the post has been updated. Thanks again.


Just for the record, I think you should have used `encodeURIComponent` instead of `encodeURI`. And in `exports.info` as well.


Ah great catch. I just changed it. Thanks!


I liked the part where you encouraged the developer to think about how the API will be consumed by the end user; however even a brief mention of some BDD / Unit tests here would have been nice (:


I agree it would have been nice. Apologies for not including it.


Slightly OT: does anyone have a good explanation for module.exports vs exports and for the expression 'exports = module.exports = someFunction' often found in modules?


Every module will have a `module` variable available to it.

    `module` defaults to {
        id: ...
        exports: {}
        parent:...
        filename:...
        loaded:...
        exited:...
        children:...
        paths:...
    }
Whatever module.exports is at the end of the module is passed to the require statement.

Every file essentially has two lines at the top.

    this = module.exports;
    var exports = module.exports;
The first helps lazy developers by allowing exporting without explicitly saying so. Because of this, the following alone is a valid module that exports {foo:'bar'}

    foo = 'bar'; // can also be written as this.foo = 'bar';
And the second matches the CommonJS standard. So the following CommonJS module will work:

    exports.foo = 'bar';
If you assign module.exports at any time after using `this` or `exports`, module.exports will point to the new object, and anything on the original module.exports object wont be passed to the `require` call.


Reassigning the `exports` variable does not change the return value of `require`.

The return value of `require` is `module.exports`, which may be reassigned.

Initially, the global `exports` variable is set to the same value as `module.exports`. Writing `exports = module.exports = ...` ensures they have the same value as you would expect.


> Writing `exports = module.exports = ...` ensures they have the same value as you would expect.

But where should they have the same value? I thought require returns just module.exports if it exists and ignores exports.


'this' is also the same as exports. Initially, they all have the same value, they all point at the same object. If you assign module.exports to a new object (vs simply adding properties to the existing object) it will ignore the value of exports and this.

It's incredibly confusing and they should have just picked one way to export data, instead of three.


=== hoge.js ===

module.exports = exports = { hello: 'hello', world: 'world' };

exports.yetAnother = 'yet another exports key';

===

and this yield

require('./hoge') -> {

   hello: 'hello',

   world: 'world',

   yetAnother: 'yet another exports key'

 }
But, when hoge.js is

=== hoge.js ===

module.exports = { hello: 'hello', world: 'world' };

exports.yetAnother = 'yet another exports key';

===

require('./hoge') -> // { hello: 'hello', world: 'world' }

or

=== hoge.js ===

exports = { hello: 'hello', world: 'world' };

exports.yetAnother = 'yet another exports key';

===

require('./hoge') -> // {}


So you reassigned module.exports to exports in order to get all objects assigned to both module.exports and exports otherwise objects assigned to module.exports would override those assigned to exports which would stay ignored, right?

But: to get all objects do I have to assign module.exports to exports (so change the order from your first example)?:

exports = module.exports = { hello: 'hello', world: 'world' };


I usually use just `module.export = {...}` in the bottom line when I want to export object by object literal.

To be honest, I'm not quite sure about commonJS require implementation of nodeJS. But as long as I'm understand,

1. Use `module.exports` if you want to assign exports by object literal

2. Use `exports.[key]` if you want to assign exports brick by brick.

3. Use `exports = module.exports = {...}` or `module.exports = exports` if you want to ensure both functionality; you can assign `exports.[key] after assign exports by object literal.


According to the documentation, they are the same:

http://nodejs.org/docs/v0.6.18/api/modules.html#modules_the_...


Also, `this` is exported in modules.


I've noticed that, and have been taking advantage of it. Any downside to using `this`, besides potential scoping issues?


Not that I've experienced. Another cool trick: modules make sense when you use packages, but they feel like PHP 4 when you just try to divide your code to several files.

https://gist.github.com/2692091

This fixes part of the problem, but what happens when you reference './models/user.js' from the file 'auth.js' but then auth grows in size and you decide to divide it and put it in auth/facebook.js, auth/twitter.js, etc. -- well, now you are fucked.


You shouldn't require using the extension.

This gives you the flexibility to transparently change the file into a folder + index.*, then break functionality up into pieces that live inside that folder.


Still, currently you need to require everything with a relative path unless it's inside node_modules.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: