Node js+at+Scale+Vol +1+-+Understanding+the+Node Js+module+system+and+using+npm
Node js+at+Scale+Vol +1+-+Understanding+the+Node Js+module+system+and+using+npm
Node js+at+Scale+Vol +1+-+Understanding+the+Node Js+module+system+and+using+npm
JS AT SCALE
Understanding the Node.js module system and using npm
RisingStack
Table of contents
03
CHAPTER TWO:
SEMVER AND MODULE PUBLISHING
10
Creating a module
Licensing
Semantic versioning
Documentation
Secret files
Encouraging contributions
Publishing
Unpublishing
Private packages
16
RisingStack
npm versions
To get the version of the npm cli you are actively using, you can do
the following:
$ npm --version
2.13.2
npm can return a lot more than just its own version - it can return the
version of the current package, the Node.js version you are using
and OpenSSL or V8 versions:
$ npm version
{ bleak: 1.0.4,
npm: 2.15.0,
ares: 1.10.1-DEV,
http_parser: 2.5.2,
icu: 56.1,
modules: 46,
node: 4.4.2,
openssl: 1.0.2g,
uv: 1.8.0,
v8: 4.5.103.35,
zlib: 1.2.8 }
RisingStack
npm help
As most cli toolkits, npm has a great built-in help functionality as
well. Description and synopsis are always available. These are
essentially man-pages.
NAME
npm-test - Test a package
SYNOPSIS
npm test [-- <args>]
aliases: t, tst
DESCRIPTION
This runs a packages test script, if
one was provided.
To run tests as a condition of
installation, set the npat config to true.
If you use npm init --yes, it wont prompt for anything, just
create a package.json with your defaults. To set these defaults,
you can use the following commands:
RisingStack
RisingStack
If youd like to open the homepage of the module from the cli you can
do:
4. SAVING DEPENDENCIES
Once you found the package you want to include in your project, you
have to install and save it. The most common way of doing that is by
using npm install request.
If youd like to take that one step forward and automatically add it to
your package.json file, you can do:
In case youd like to save the exact version, you can try:
RisingStack
RisingStack
7. NO DEVDEPENENDENCIES IN PRODUCTION
Development dependencies are called development dependencies
for a reason - you dont have to install them in production. It makes
your deployment artifacts smaller and more secure, as you will have
less modules in production which can have security problems.
To install production dependencies only, run this:
$ npm install --production
9. DEVELOPING PACKAGES
When developing packages locally, you usually want to try them out
with one of your projects before publish to npm. This is where
npm link comes to the rescue.
What npm link does is that it creates a symlink in the global folder
that links to the package where the npm link was executed.
RisingStack
RisingStack
CHAPTER TWO:
SEMVER AND MODULE PUBLISHING
In the second chapter of this book, you are going to learn how to
expand the npm registry with your own modules. Well also going to
explain how versioning works.
RisingStack
10
CREATING A MODULE
First lets create a module: npm init -y should take care of it, as
youve learned in the previous chapter.
{
name: npm-publishing,
version: 1.0.0,
description: ,
main: index.js,
scripts: {
test: echo \Error: no test specified\ && exit 1
},
keywords: [],
author: ,
repository: {
type: git,
url: git+https://github.com/author/modulename
},
bugs: {
url: https://github.com/caolan/async/issues
},
license: ISC
}
RisingStack
11
In the repository field, you can see where the code is hosted and
the bugs section tells you where can you file bugs if you find one in
the package. To quickly jump to the bug report site you can use
npm bug modulename.
1. Licensing
Solid license and licenses adoption helps Node adoption by large
companies. Code is a valuable resource, and sharing it has its own
costs.
Licensing is a really hard, but this site can help you pick one that fits
your needs.
Generally when people publish modules to npm they use the
MIT license.
The MIT License is a permissive free software license originating at
the Massachusetts Institute of Technology (MIT). As a permissive
license, it puts only very limited restriction on reuse and has
therefore an excellent license compatibility.
2. Semantic Versioning
Versioning is so important that it deserves its own section.
Most of the modules in the npm registry follow the specification
called semantic versioning.
Semantic versioning describes the version of a software as 3
numbers separated by .-s. It describes how this version number
has to change when changes are made to the software itself.
Given a version number MAJOR.MINOR.PATCH, increment the:
* MAJOR version when you make incompatible API changes,
* MINOR version when you add functionality in a backwards
compatible manner, and
* PATCH version when you make backwards-compatible bug fixes.
Additional labels for the pre-release and the build metadata are
available as extensions to the MAJOR.MINOR.PATCH format.
RisingStack
12
These numbers are for machines, not for humans! Dont assume that
people will be discouraged from using your libraries when you often
change the major version.
You have to start versioning at 1.0!
Most people think that doing changes while the software is still in
beta phase should not respect the semantic versioning. They are
wrong! It is really important to communicate breaking changes to
your users even in beta phase. Always think about your users who
want to experiment with your project.
3. Documentation
Having a proper documentation is imperative if youd like to share
your code with others. Putting a README.md file in your projects
root folder is usually enough, and if you publish it to the registry npm
will generate a site like this one. Its all done automatically and it
helps other people when they try to use your code.
Before publishing, make sure you have all documentation in place
and up to date.
5. Encouraging contributions
When you open up your code to the public, you should consider
adding some guidelines for them on how to contribute. Make sure
they know how to help you dealing with software bugs and adding
new features to your module.
There are a few of these available, but in general you should consider
using githubs issue and pull-request templates.
RisingStack
13
NPM PUBLISH
Now you understand everything thats necessary to publish your first
module. To do so, you can type: npm publish and the npm-cli will
upload the code to the registry.
Congratulations, your module is now public on the npm registry!
You can visit www.npmjs.com/package/yourpackagename
for the public URL.
If you published something public to npm, its going to stay there
forever. There is little you can do to make it non-discoverable. Once it
hits the public registry, every other replica thats connected to it will
copy all the data. Be careful when publishing.
What if you published something that you didnt mean to?
Were human. We make mistakes, but what can be done now? Since
the recent leftpad scandal, npm changed its unpublish policy.
If there is no package on the registry that depends on your package,
then youre fine to unpublish it, but remember all the replicas will
copy all the data - so someone somewhere will always be able to get
it. If it contained any secrets, make sure you change them after the
act, and remember to add them to the .npmignore file for the next
publish.
RisingStack
14
npm enterprise
If youd like to further tighten your security by running a registry
by yourself, you can do that pretty easily. npm has an on-premise
version that can be run behind corporate firewalls. Read more about
setting up npm enterprise.
RisingStack
15
CHAPTER THREE:
HOW THE MODULE SYSTEM,
COMMONJS & REQUIRE WORKS
In the third chapter of Node.js at Scale you are about to learn how
the Node.js module system & CommonJS works and what does
require do under the hood.
// add.js
function add (a, b) {
return a + b
}
module.exports = add
To use the add module we have just created, we have to require it.
// index.js
const add = require(./add)
t.i
RisingStack
console.log(add(4, 5))
//9
16
This is why you can access the global-like variables like require
and module. It also ensures that your variables are scoped to your
module rather than the global object.
Module._load
This function checks whether the module is in the cache already if so, it returns the exports object.
If the module is native, it calls the NativeModule.require()
with the filename and returns the result.
RisingStack
17
Otherwise, it creates a new module for the file and saves it to the
cache. Then it loads the file contents before returning its exports
object.
Module._compile
The compile function runs the file contents in the correct scope or
sandbox, as well as exposes helper variables like require,
module or exports to the file.
use strict
const CONNECTION_LIMIT = 0
function connect () { /* ... */ }
module.exports = {
CONNECTION_LIMIT,
connect
}
RisingStack
18
npm --version
npm v2
npm 2 installs all dependencies in a nested way, where your primary
package dependencies are in their node_modules folder.
npm v3
npm3 attempts to flatten these secondary dependencies and install
them in the root node_modules folder. This means that you
cant tell by looking at your node_modules which packages are
your explicit or implicit dependencies. It is also possible that the
installation order changes your folder structure because npm 3 is
non-deterministic in this manner.
You can make sure that your node_modules directory is always the
same by installing packages only from a package.json.
In this case, it installs your dependencies in alphabetical order,
which also means that you will get the same folder tree. This is
important because the modules are cached using their path as the
lookup key. Each package can have its own child node_modules
folder, which might result in multiple instances of the same package
and of the same module.
RisingStack
19
We can allow Node.js to manage the modules life cycle by using hard
coded module loading. It organizes your packages in an intuitive way,
which makes understanding and debugging easy.
Dependency Injection is rarely used in a Node.js environment,
although it is a useful concept. The DI pattern can result in an
improved decoupling of the modules. Instead of explicitly defining
dependencies for a module, they are received from the outside.
Therefore they can be easily replaced with modules having the same
interfaces.
Lets see an example for DI modules using the factory pattern:
class Car {
constructor (options) {
this.engine = options.engine
}
start () {
this.engine.start()
}
RisingStack
20
NEXT UP
We hope this chapter contained valuable information about the
module system and how require works.
In the next volume of the Node.js at Scale series, we are going to
take a deep dive and learn about the event loop, garbage collection
and about writing native modules.
RisingStack
21