© Elad Elrom 2016

Elad Elrom, Pro MEAN Stack Development, 10.1007/978-1-4842-2044-3_3

3. Node Modules

Elad Elrom

(1)New York, USA

A typical MEAN application can often depend on up to hundreds of packages. These modules are often small and consist of both Node.js and Bower libraries. By combining libraries, you are able to create a mashup of small-shared building blocks and custom apps for the purpose of solving a larger problem.

The ability to harness node is powerful, not just for node-based applications, but for just about any task, regardless of the platform or language you might be using. In this chapter, we will be utilizing npm to install popular node modules, learning how to deploy a Node.js project, and setting up a config file for easy future updates. We will create our first node module and learn how to submit it to npm as an open source project.

npm Node Packages

npm (htttp://npm.com) is the premier location to search for modules. The source code for many of these libraries will usually live on GitHub ( http://github.com ). In fact, as you may recall from Chapter 1, we have already installed a few npm modules, such as Grunt, Gulp, and Bower. Also, we already have Git installed on our local and server environments, so you actually already have everything you will need to install and set your node modules. In this section, we will expand on this subject, help you find what you need, and provide a better understanding of how to install these packages.

npm began as the free and open source node package manager—it eventually became more than that. In fact, it’s been used as package manager for Node.js, JavaScript, Grunt, Gulp, Bower, AngularJS, and much more. These days, npm allows holding private modules and makes it easy to share, update, and reuse code.

Note

Notice that the words “module,” “library,” and “packages” are interchangeable and all mean the same thing: a directory of files with reusable code, capable of solving a specific targeted problem or set of problems.

At the time of this writing, there are over 250,000 open source packages on npm (Figure 3-1). npm has a URL listing the most starred packages:

A416092_1_En_3_Fig1_HTML.jpg
Figure 3-1. npm most popular packages

https://www.npmjs.com/browse/star

Additionally, npm lists stats for downloads in the last day, week, and month, so picking a node module can be based on useful information. In fact, we encourage you to visit the GitHub location of the code and check for the latest update, known errors, and other information to make sure you’re picking a module that can do what you need.

Generally, node packages are one of two types:

  1. Server side modules: as mentioned, npm originated as the node package manager, so you will find many server side packages to support the writing of your node app.

  2. Command line packages: these packages can enhance the capability of the local environment or our server/s. Some notable examples: Grunt and Gulp packages, which we installed back in Chapter 1.

Once you’ve found the npm package you would like to install, all you have to do is open Terminal, and in the command line, simply type:

$ [sudo] npm install [modules]              

Beside npm, you may search through this link farm and discover some usefull Node.js: https://github.com/sindresorhus/awesome-nodejs

You will learn a lot just looking at other people’s code and seeing how they do a particular thing, so go ahead and explore.

Install Node.js Modules

Although it is simple to install node modules, we should be strategic about how we do so to global or local locations. The versions of libraries and the management of updates should all be taken into consideration before we begin installing.

To better understand the different types of installations, we’ll create a dummy project and install few modules. In your favorite IDE, such as WebStorm or Sublime (see Chapter 1 if you haven’t installed any), create a project and name it “Tester.”

Here, we are using WebStorm IDE . From the top menu, select “File” ➤ “New Project…” and set the project name as “Tester,” then select “Empty project” (Figure 3-2).

A416092_1_En_3_Fig2_HTML.jpg
Figure 3-2. Create tester project in WebStorm

Hit “OK,” and now you should have an empty shell project that we can start working with; see Figure 3-3.

A416092_1_En_3_Fig3_HTML.jpg
Figure 3-3. Tester window project in WebStorm

Notice that at the bottom of the project, there is an icon of a command line next to the word “Terminal.” Click that and a Terminal will open up. We can use that Terminal to work in, just as Mac builds in a Terminal—see Figure 3-4.

A416092_1_En_3_Fig4_HTML.jpg
Figure 3-4. Terminal window in WebStorm

If you selected a different IDE than WebStorm, simply open the Mac command line “Terminal” and navigate to the project root directory.

Let’s say we need to manipulate dates and convert them from one format to another. We can create our own daunting library, but there’s no need—npm lists a library called “moment” ( https://www.npmjs.com/package/moment ) that will allow us to parse, validate, and manipulate dates easily. If that library is missing what we need, we can always clone that project, since it’s listed as a GitHub open source project ( https://github.com/moment/moment ), or create our own modules and share them with others (when possible) in case we cannot find what we need at all.

As mentioned, all you have to do is type into the command line Terminal:

$ npm install moment                                                                  

If you type this command, it will create a “node_modules” directory in our project and add a “moment” library. Then, we are ready to continue; see Figure 3-5.

A416092_1_En_3_Fig5_HTML.jpg
Figure 3-5. Installing moment library command line output and project window

npm has installed the library moment at version 2.12.0 locally. However, npm has spit out a warning message: “enoent ENOENT, open '/Users/eli/WebstormProjects/Tester/package.json'” (see Figure 3-5).

What is that all about? npm expects to have a package.json file in order to be able to manage and keep track of locally installed libraries. You can create this on your own; the most minimalistic “JASON” code is this name and version:

{ "name": "tester", "version": "1.0.0" }              

The easiest way to create the package JSON file is to simply type into the command line:

$ npm init              

You may also use the –yes flag to accept all of the default settings:

$ npm init --yes              

We have selected the option without the –yes flag checked. It opens with a quick questionnaire and eventually creates the package JSON file. We have accepted the default settings we want by hitting the “enter” key—see Figure 3-6.

A416092_1_En_3_Fig6_HTML.jpg
Figure 3-6. npm init walk through to create package.json file

The npm init command has generated the package.json file for us automatically in Listing 3-1.

Listing 3-1. Content of package.json file
{
  "name": "Tester",
  "version": "1.0.0",
  "description": "just a tester project",
  "main": "index.js",
  "dependencies": {
    "moment": "^2.12.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
   “keywords”: [],
  "author": "eli",
  "license": "ISC"
}

The file includes the name, version, description, author, and license, which you can edit at any time on your own.

Notice that this package.json file includes the following code:

test": "echo "Error: no test specified" && exit 1"

npm encourages developers to set a test file to ensure changes don’t break the code, which is crucial when you have a project with many contributors. Later on in this chapter, we will show you how to set up a test through npm.

Additionally, sub-objects called “devDependencies ” and “dependencies” have been created. It is also presumed that we installed moment and has added it to the “dependencies” library.

There are two types of packages: “dependencies” and “devDependencies ”:

  • “Dependencies” are packages that are required by your application to work in production.

  • “DevDependencies” are packages that are only necessary for development and testing.

An application can consist of hundreds of small modules, so managing your dependencies efficiently will help a lot in organizing your library and will eventually decrease deployment time, so it’s a good practice to begin doing right away. The following sections discuss the four best options.

Caret Version Option

Notice that “moment” was installed as “^2.12.0”. The “^” caret or circumflex symbol means that it will update to the most recent major version (the first number). ^2.12.0 will match any 2.x.x release, but will hold off on 3.x.x; this is the default setting, but it could potentially cause problems.

If “moment” updated their libraries and had broken previous code and you then fail to update your code, when you do an npm update or deploy, the code will break. Additionally, it is recommended to inspect the script before updating. npm includes security vulnerability scanning, but it is still possible for a package to include worms or unwanted scripts, so in addition to the possibility of breaking a script, it is also a security concern.

Tilde Version Option

In case you want to be more specific, use the tilde version option , which will match the most recent minor version (the middle number). ∼2.12.0 will match all 2.12.x versions but will skip 2.2.x versions. This can help ensure that you only upgrade middle versions; the type will change, but you will bypass major changes.

"moment": "∼2.12.x"

Latest Version Option

You are also able to update to the latest version, but as I said earlier, it may break your library if changes in code were made that were not backward compatible.

"moment": "latest"

Specific Version Option

Lastly, you can specify an exact version, such as “2.12.0,” to ensure nothing breaks. You can limit the version with “>=”, “<=”, “>”, “<”, and so on.

 "moment": "2.12.0"

Install Save Flag

Now that we have the package.json file, moving forward we can use the --save install flag to allow us to add any libraries to the package json file. If we only want to save to the “devDependency” object, we will need to use the --save-dev install flag.

For instance, the command in Listing 3-2 will grant npm as root/Administrator (sudo) in case it needs to update any files or install and save Grunt as a devDependency.

Listing 3-2. Content of package.json file includes Grunt
sudo npm install grunt --save-dev
{
  "name": "tester",
  "version": "1.0.0",
  "description": "just a tester project",
  "main": "index.js",
  "dependencies": {
    "moment": "^2.12.0"
  },
  "devDependencies": {
    "grunt": "^1.0.1"
  },
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "eli",
  "license": "ISC"
}

Global Installation

Another option is installing libraries globally. As we have mentioned, there are two ways to install npm packages: “locally” or “globally.” In order to choose which type of installation is right for you, you will need to think about how you will want to use the package.

If you need the package for more than just your specific project, use the global flag:

$ sudo npm install -g epress

This command will install the Express library globally. Notice that we used “sudo” to allow administration rights and avoid errors, but it’s not always necessary.

npm offers a large collection of docs covering just about anything to do with npm, from getting started to usage to configuration and everything in between. See: https://docs.npmjs.com/

Create Your Own First Node Modules

As I pointed out, there are more than 250,000 modules on npm alone. Creating a module is easy—in this section we will walk you through the process. We recommend that you follow this section as a guideline and create your own unique module so that you fully understand this process.

We chose a simple and minimalistic example so that you can easily grasp the idea. We’ve created a module to log messages in Node.js, but unlike “console.log,” this one will use colors, allowing you to log different types of messages. You can set the type of function you want to log, which allows you to disable the messages from being logged all together.

Create a GitHub Project Repository

We are starting off by creating a Git repository. Log in to GitHub and select the top “+” sign and hit “new repository,” which opens up the “create new repository” page: https://github.com/new and allows us to select the “repository name,” owner, and other settings. Once the repo (repository) has been created, we will be given the Git location and command line instructions—see Figure 3-7:

A416092_1_En_3_Fig7_HTML.jpg
Figure 3-7. Woodenlog repository in GitHub

Notice we have created the repo name “woodenlog” as an example—you can create any name you want to practice publishing a project.

Create a Module Project

To continue, we will create a new project in WebStorm from the “Empty Project” template, following the same process as before:

“File” ➤ “New Project.” For the project name, we’ll be using “woodenlog.” We already checked with npm ( https://www.npmjs.com/ ) to ensure there isn’t already a project with that name; it’s not always easy to find a unique name these days.

Write Your Module Code

Next, we need to create an “index.js” file in the root directory. To create a new file in WebStorm, use the top menu “File” ➤ “New” ➤ “File,” or right click the project and choose “File” ➤ “New.”

The “index.js” file will be the entry point of the library.

We will be using the code in Listing 3-3.

Listing 3-3. Woodenlog index.js file
const style = require('ansi-styles');

var logFunction = console.log,
        logColor = 'green',
        warnColor = 'yellow',
        errorColor = 'red';


module.exports = {

        log: function(object) {
                logFunction(style[logColor].open + object + style[logColor].close);
                return true;
        },


        warn: function(object) {
                logFunction(style[warnColor].open + object + style[warnColor].close);
                return true;
        },


        error: function(object) {
                logFunction(style[errorColor].open + object + style[errorColor].close);
                return true;
        },


        configurate: function(logOutFunction, logColorName, warnColorName, errorColorName) {
                if (logOutFunction) logFunction = logOutFunction;
                logColor = logColorName;
                warnColor = warnColorName;
                errorColor = errorColorName;
                return true;
        }
};

We will be using the “ansi-styles” module. This is a library that uses ANSI escape codes for styling strings in a terminal. You can see the source code here: https://github.com/chalk/ansi-styles

const style = require('ansi-styles');

Next, we need to define the colors we want to use for the log, warn, and error, as well as the type of method we would like to use in order to paste messages.

var logFunction = console.log,
        logColor = 'green',
        warnColor = 'yellow',
        errorColor = 'red';

Notice that we have already set the default values and will be using the good old “console.log” JavaScript function to show the messages.

Now, we’ll define each method, log, warn, and error with the color we will be using:

        log: function(object) {
                logFunction(style[logColor].open + object + style[logColor].close);
                return true;
        },

We have encapsulated the index.js code so it can be utilized in other files by using the “module.exports” variable once a file is required. You will see how it works once we implement the module:

module.exports = {
  // code goes here
}

Run Your Module Code

We can now run our library to ensure that we don’t encounter any errors. To do so, select the caret from the top right corner in WebStorm and select “Edit Configurations…” See Figure 3-8.

A416092_1_En_3_Fig8_HTML.jpg
Figure 3-8. Edit Configurations menu item in WebStorm

The wizard will open up and we will select the “+” sign to add a new configuration. From the drop-down menu, select “Node.js.” See Figure 3-9.

A416092_1_En_3_Fig9_HTML.jpg
Figure 3-9. Add new configration in WebStorm

The program will then allow us to configure the Run/Debug options. We will leave all the default settings as they are, but for the JavaScript file, we’ll select the name of the app, “woodenlog,” and enter the “index.js“ file we created (see Figure 3-10.) Hit “OK” to close this wizard.

A416092_1_En_3_Fig10_HTML.jpg
Figure 3-10. Run/Debug configuration settings for Node.js .

Now, at the top right corner of WebStorm, we can see “woodenlog” added to the top menu, and also a green “play” icon (see Figure 3-11).

A416092_1_En_3_Fig11_HTML.jpg
Figure 3-11. WebStorm top right menu shows “woodenlog” app

Install Dependencies

We could go ahead and run the application by pressing the play button, but we will encounter errors—see Figure 3-12.

A416092_1_En_3_Fig12_HTML.jpg
Figure 3-12. Woodenlog error message in WebStorm

From looking at the errors, we can see that we’re missing some code, so before we can run the code successfully, we need to install the module we are using called “ansi-styles.”

We need our package.json file to store our dependencies before we begin installing the module. Open the Terminal using either WebStorm’s built-in Terminal (bottom right corner) or the Mac built-in Terminal and navigate to the project root.

We want to run “npm init” so it will create the “package.json” file for us, the same as we did for the “Tester” application. In the Terminal, run:

$ npm init

This time, set the package.json file that npm created to read/write permission, so we will be able to manually edit the file, which will be used be as npm when we publish our module. In the command line, type:

$ sudo chmod 777 package.json

Now, we can install “ansi-styles;” in the command line, type:

$ npm install ansi-styles --save

Notice that we have used the –save flag to allow the module to be added to the dependencies list in the package.json file.

Now, hit the green “play” button once again and you should see the following output:

/usr/local/bin/node index.js

Process finished with exit code 0

This means that the code has been run successfully.

Ignore Files

Now that our library is ready and working, we want to prepare to publish to GitHub. We do not want to publish any dependencies, which is what package.json is for. This will allow other users to select “npm install” and thus download npm to all of the libraries, which will decrease any redundancies on the hosting servers.

Also, note that WebStorm has created a hidden “.idea” folder with settings regarding a project that we don’t want to upload either. To achieve this, we want to create a “gitignore” file at the root of the project that will instruct Git to ignore these files.

In the WebStorm or Mac Terminal, create the file using vim or your favorite editor:

$ vim .gitignore

Next, type “i" to insert and paste the following:

node_modules
.idea

Create Test Stubs

If you recall, earlier we showed you the code that npm generates in package.json for testing; the code looked like this:

test": "echo "Error: no test specified" && exit 1"

We will implement this test now. We won’t delve into Test Driven Development (TDD) and Behavior Driven Development (BDD) , since it’s not necessary to sidetrack from the chapter’s main objectives, but feel free to read about it online or in other books. There is a large school of thought that believes writing tests before writing code is superior.

To get started, we need to create a folder in the root of the project and name it “test,” and then add a file call “index.js” inside of that folder. See Figure 3-13.

A416092_1_En_3_Fig13_HTML.jpg
Figure 3-13. Test folder structure in WebStorm

For testing, we will be using “chai” ( http://chaijs.com/ ). Chai is a BDD / TDD assertion library for Node.js and the browser. It can be easily paired with other JavaScript testing frameworks. We will pair it with a test framework called “mocha” ( https://mochajs.org/ ).

Start off by installing “chai” and “mocha.” In the Terminal, type:

$ npm install chai –save-dev
$ npm install mocha –save-dev

Now paste the code from Listing 3-4.

Listing 3-4. Test code for woodenlog module using mocha
var should = require('chai').should(),
        woodenlog = require('../index'),
        log = woodenlog.log,
        warn = woodenlog.warn,
        error = woodenlog.error;


describe('#log', function() {
        it('log message', function() {
                log('message').should.equal(true);
        });
});


describe('#warn', function() {
        it('warn message', function() {
                warn('message').should.equal(true);
        });
});


describe('#error', function() {
        it('error message', function() {
                error('message').should.equal(true);
        });
});

We define “should” and also our methods:

var should = require('chai').should(),
        woodenlog = require('../index'),
        log = woodenlog.log,
        warn = woodenlog.warn,
        error = woodenlog.error;

Then, we are able to define each of our test stubs. In our case, the method returns true once the message has been logged successfully:

describe('#log', function() {
        it('log message', function() {
                log('message').should.equal(true);
        });
});

We have used “log,” “warn,” and “error” as our test stubs naming conventions, however it is common to see the words “test” or “unit” at the end of each test. For example: “logTest” or “logUnit.” It’s a matter of preference.

Configure Package.json File

Now we can configure our package.json file with the repo Git URL location, test script, license, version, and other information. See Listing 3-5.

Listing 3-5. Package.json file configure all changes
{
  "name": "woodenlog",
  "version": "1.0.1",
  "description": "Minimalist log node messages module",
  "main": "index.js",
  "scripts": {
          "test": "./node_modules/.bin/mocha --reporter spec"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/eladelrom/woodenlog.git"
  },
  "keywords": [
    "log",
    "woodenlog",
    "log",
    "messages"
  ],
  "author": "Elad (Eli) Elrom",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/eladelrom/woodenlog/issues"
  },
  "homepage": "https://github.com/eladelrom/woodenlog#readme",
  "dependencies": {
    "ansi-styles": "^2.2.1"
  },
  "devDependencies": {
    "chai": "^3.5.0",
    "mocha": "^2.4.5"
  }
}

Run Test Stubs Using npm

Since we have configured the test field in package.json:

"test": "./node_modules/.bin/mocha --reporter spec"

We will now be able to run our tests. In the Terminal, type the following command:

$ npm test

Once you run this command, you should see a pass message for our three methods and a spit-out of our code in the console, already formatted with our colors (Figure 3-14).

A416092_1_En_3_Fig14_HTML.jpg
Figure 3-14. npm test results in Terminal

Create Markdown Home Page File

Last but not least, we want to create a README.md file. The “.md” file extension stands for “markdown.” Markdown is lightweight syntax for styling your writing on GitHub and other platforms. It uses charcters to instruct styling and it makes styling your document easy.

The README.md file is considered our “home” page; it’s configured by default with the package file and GitHub. We will be using this file automatically as your “home” page for the repository.

The markup language is straightforward. For instance, to highlight code, you’ll wrap code inside ```js opening tags and ``` closing tags (Listing 3-6).

Listing 3-6. Format code in Markdown syntax
```js
var woodenlog = require('woodenlog');
// woodenlog.configurate(null, 'white', 'green', 'red');


woodenlog.log('just log!');
woodenlog.warn('this is a warning!');
woodenlog.error('this is an error!');


```

This will format your code in a nice, easy-to-see box, complete with colors and spacing. See Figure 3-15.

A416092_1_En_3_Fig15_HTML.jpg
Figure 3-15. Format code in Markdown results

To see all your available options and different Markdown syntax, feel free to visit this cheat sheet page: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet

We will be using the following complete code block for our README.md file (Listing 3-7).

Listing 3-7. README.md file content
WoodenLog
=========


Minimalist log node messages module to add colors for console.log for specific type of log.

## Installation

```shell
  npm install woodenlog --save
```


## Usage

```js
var woodenlog = require('woodenlog');
// woodenlog.configurate(null, 'white', 'green', 'red');


woodenlog.log('just log!');
woodenlog.warn('this is a warning!');
woodenlog.error('this is an error!');


```

## Tests

```shell
   npm test
```


## Release History

* 1.0.0 Initial release

The results can be seen in Figure 3-16.

A416092_1_En_3_Fig16_HTML.jpg
Figure 3-16. README.md formatted

Markdown Plugin in WebStorm

WebStorm has a Markdown plugin that helps you display and work with Markdown files. To add the Markdown plugin or any other plugins you want, follow the steps below:

  1. Open the “Preference” window by selecting “command” + “ , ” or top menu “WebStorm” ➤ “Preferences…”

  2. Select “Plugins.”

  3. Search for “Markdown” plugin.

  4. Click “Install.”

Next, toggle between the “Text” and “Preview” tabs to see the code and its results. See Figure 3-17.

A416092_1_En_3_Fig17_HTML.jpg
Figure 3-17. Markdown plugin preview in WebStorm

Publish Module to GitHub

Before we publish to npm, we will publish to GitHub. The first step is to initialize Git, just as we did in Chapter 1.

$ git init

Next, you need to generate GitHub SSH keys on your computer. Follow the instructions in the following link: https://help.github.com/articles/generating-an-ssh-key/

Now we can add the files, commit, and push the changes (Listing 3-8).

Listing 3-8. Publish module to GitHub
$ git add .
$ git commit -m 'init commit'
$ git push --set-upstream origin master

Note that if you didn’t configure your Git with your GitHub credential, it will ask for your username and password.

Username for 'https://github.com': [your user name]
Password for 'https:// [your user name]@github.com':

You will see a confirmation in the Terminal, confirming that the repo was published.

To https://github.com/eladelrom/woodenlog.git                                    
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

You may also visit the GitHub page to see your module README.md file and module files. See Figure 3-18:

A416092_1_En_3_Fig18_HTML.jpg
Figure 3-18. GitHub woodenlog repo home page

Now, we are ready to publish to npm. In order to publish to npm, run the command:

$ sudo npm publish

Just like with GitHub, since we haven’t configured our user, npm will ask for authentication. See message below:

npm ERR! need auth auth required for publishing
npm ERR! need auth You need to authorize this machine using `npm adduser`

As you can see, it has given us the command in an error message. Type the command into the Terminal to add a username:

$ npm adduser                      

Now that the user has been added, we can publish again:

$ npm publish

npm confirms that this publishing was correct:

+ [email protected]

At this point, we can publish the library publically, install it from any computer, and implement the high-level API. To implement, we will use the “Tester” project we created at the beginning of the chapter, add the index.js file, edit and run the configuration and set the index.js file as the JavaScript file, just like we’ve done previously with the woodenlog project.

Inside the index.js file, paste the following code (see Listing 3-9):

Listing 3-9. Implement woodenlog API
var woodenlog = require('woodenlog');
// woodenlog.configurate(null, 'white', 'green', 'red');


woodenlog.log('just log!');
woodenlog.warn('this is a warning!');
woodenlog.error('this is an error!');

Next, install the woodenlog module. In the Terminal, type in:

$ npm install woodenlog --save-dev

This will install woodenlog and update the project’s “package.json” file, just as we did in Chapter 1. Open “package.json” and you can see the module added as a developer dependency:

  "devDependencies": {
    "woodenlog": "^1.0.1"
  }

Run the project and you will see the following results in WebStorm Run Terminal. See Figure 3-19:

A416092_1_En_3_Fig19_HTML.jpg
Figure 3-19. WebStorm Run Terminal results

Summary

In this chapter, we looked at npm popular node modules; learned how to install Node.js; installed dependency modules locally, globally and using different module versions options and flags; and configured an npm package.json file.

We created our own first node modules, learned how to create a GitHub project repository, created our module code and ran the code, learned which files to ignore, and created test stubs using mocha and chai.

We created a Markdown file using the Markdown plugin in WebStorm and published our module to GitHub and npm.

In the next chapter, we will learn how to set up a PhoneGap / Cardova project.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.37.136