🟢 Node - Modules
Node applications are formed from modules that are used with require
. In Node context, all JavaScript files have pre-declared pseudo global module
variable that defines what file "returns" when it's loaded using require
by another JavaScript file.
// hello.js
// Imagine that this line of code exists as the first line of each JS file.
// var exports = module.exports = {};
module.exports.english = function() {
console.log('Hi!');
};
module.exports.finnish = function() {
console.log('Moi!');
};
// goodbye.js
module.exports.english = function() {
console.log('Bye!');
};
module.exports.finnish = function() {
console.log('Hei hei!');
};
// main.js
var hello = require('./hello.js');
var goodbye = require('./goodbye.js');
hello.english();
goodbye.english();
When you are exporting a single constructor, use module.exports
. Basically Node.js doesn't export the object that exports
currently references, but exports the properties of what exports
originally references. Node.js does export the object module.exports
references, allowing you to call it like a function.
// bad
// MyConstructor.js
var MyConstructor = function(options) {
// ...
}
exports = MyConstructor;
// good
// MyConstructor.js
var MyConstructor = function(options) {
// ...
}
module.exports = MyConstructor;
// allows this to work
var MyConstructor = require('./MyConstructor.js');
MyConstructor();
Single module can export multiple modules.
// clothes/Sock.js
var Sock = function(color) {
this.color = color;
}
module.exports = Sock;
// clothes/Shoe.js
var Shoe = function(size) {
this.size = size;
}
module.exports = Shoe;
// clothes/index.js
module.exports = {
Sock: require('./clothes/Sock'),
Shoe: require('./clothes/Shoe');
}
// main.js
var clothes = require('./clothes');
var sock = new clothes.Sock('pink');
var shoe = new clothes.Shoe();
require
searches your project environment for the specified identifier. If no extension was specified, tries to find .js
, .json
and .node
. Also tries to find folder with the same name. Failed load will throw error MODULE_NOT_FOUND
. Requires are cached.
require('./filename'); // load from current directory
require('../filename'); // load from parent directory
require('/Users/eric/node/filename'); // absolute directory path
// 1A. Search for filename.js, filename.json and filename.node in
// the specified directory.
// 2A. Searh for "filename" directory. If found, search it for
// package.json, index.js and index.node.
require('filename');
// 1B. Check if there exists a core module with the name in "node/lib".
// 2B. Check if current file's directory contains "node_modules" directory.
// 3B. If 2B ok, do 1A and 2A in that "node_modules".
// 4B. If 3B not ok, jump to parent directory and do 2B.
Use packages. npm
is the biggest package repository on Earth. If you need to do something specific, there for sure is a package for that. Check that the package is being updated.
You can install modules locally or globally. Local modules can be used inside your project with require()
. Global modules can be run on command line e.g. coffee app.coffee
.
# Will install into local project `node_modules` directory.
npm install request
# Will install into global `node_modules` directory.
npm install coffee-script -g
Use package.json
to define your Node project. When you start a project or a component, you should first create package.json
. Has project settings e.g. dependencies.
// package.json, note that real JSON files cannot have comments
{
"name": "Name" // Unique package/application/library name.
"preferGlobal": false, // If this is an library with command line interface.
"version": "0.1.0", // Package version number.
"description": "A simple statement what this package does."
"main" : "./main.js" // What is required when you use require.
"dependencies": { // List all that is required to run this package.
"connect": "1.8.7"
},
"devDependencies": { // List all that is required to develop this package.
"vows": "0.5.x",
"request": "2.1.x"
},
"license": "MIT", // Good to state the license.
"engines": {
"node": ">=0.6" // What node version this should at least work.
}
}
# Running install in same directory installs dependencies to "node_modules".
# Dependencies' dependencies go to their own "node_modules" subdirectory.
npm install
Don't use asterisks in dependency definitions. These definitions might break your app in the future, be as strict as possible and update dependencies by hand.
BAD:
"dependencies": {
"express": "*"
}
BAD:
"dependencies": {
"express": "4.*"
}
GOOD:
"dependencies": {
"express": "4.0"
}
Use npm shrinkwrap
. Shrinkwrap will lock versions of your dependencies' dependencies using npm-shrinkwrap.json
file. Then following npm installs
will install exactly the same versions. It also helps to limit automatic builds crashing on Windowns because dependency paths get too long.
npm install # or npm update
# test that it works
npm shrinkwrap
Writing Modules
Modules should always expose a callback interface. You can use promises and streams internally but mainstream Node.js ecosystem utilizes callbacks.
Don't place git URLs to package.json
. There are more lurking problems than benefits using them e.g. caching errors, unstable states.
Use internal npm
instance for you company. Then you can share code more easily between internal project, which is really valuable.
Use same modules between your projects. Avoid embedding functionality that might be shared between multiple apps.
Auth module.
Credit cart module.
Bank module.