Over a million developers have joined DZone.

NPM for Everything

· DevOps Zone

Download “The DevOps Journey - From Waterfall to Continuous Delivery” to learn learn about the importance of integrating automated testing into the DevOps workflow, brought to you in partnership with Sauce Labs.

The JS ecosystem is famous for its wide range of packages and tools. Besides the default package manager, which comes with Node.js – NPM (node package manager), there are Bower.js, Jam.js and many more.

For a quite long period, my default setup was NPM for all server-side components and Bower.js for client-side stuff. It worked quite good together, especially in conjunction with Require.js.

But recently, I switched to NPM only setup. That allowed me to use CommonJS style both front and back ends and got rid of task runners as Grunt and Gulp.

CommonJS

Doing a lot of back-end coding I really got used to the CommonJS style, which is simple, practical and powerful. CommonJS modularization is plain as,

var module = {
};
// export the module
module.exports = module;

and

// use the module
var module = require('./module');

Node.js highly popularized the Common.js approach. And NPM appeared to be one of the best package managers ever developed.

But for front-end, NPM was not that suitable. First of all, because of browsers do not understand Common.js style of modules. Second, npm modules are being placed to ./node_modules folder, with is typically the root of project, that made things complicated to refer those scripts from index.html and configure server to server static resources from ./node_modules folder.

Browserify came to change this.

Browserify

Browserify is JavaScript transpiling tool, with allows to:

  1. Use Common.js style for front-end applications.
  2. Allowed to use various npm packages directly in a browser.

A lot of pure front-end frameworks and libraries were published to npm. In fact, it’s more and more used for front-end libraries as according to NPM developers.

Of cause, nothing comes for free. The cost of Browserify is a build step. You have to introduce to transform Common.js application into a bundle which is loaded and executed by a browser.

Moreover, some packages are still being hosted on Bower. Even, it’s possible to use Bower packages together with NPM packages (by means of debowerify transformation) I quickly realized, that this approach is very unpractical.

So, during the last few months my main contributions on GitHub was adopting of some front-end packages, to be conformant to Common.js and publishing them on NPM after.

The setup

The NPM now is the only one package manager to use, both for front-end and backend.

All dependencies are mentioned on one file package.json instead of several files.. and you will never forget to run bower install, since npm install will do install everything.

  "dependencies": {
    "async": "^0.9.0",
    "babelify": "^5.0.4",
    "body-parser": "^1.9.0",
    "colors": "^1.0.2",
    "cors": "^2.4.2",
    "envify": "^3.4.0",
    "express": "^4.9.5",
    "method-override": "^2.2.0",
    "moment": "^2.8.3",
    "morgan": "^1.3.2",
    "node-logentries": "^0.1.4",
    "react": "^0.13.1",
    "respawn": "^1.0.1"
  }

The server side code,

var express = require('express');
// configurations...
app.listen(port, function () {
    logger.info('editor-app listening on port ' + port + ' ' + env);
});

The client side code,

var React = require('react');
var Component = React.create({
});
module.exports  = Component;

The same style, feels nice and clean.

No task runners

NPM is not only package manager. It’s also very simple task runner (or scripts runner). There is a special section, called scripts responsible for that. Originally it’s been used to run some package related tasks (run tests, perform pre/post install configurations).

Traditionally Grunt.js and Gulp.js are ones that used dealing with compiling static assests. But CLI interface of many tools and stream piping could replace them.

As example, I’ll show pretty typical setup:

  • build JavaScript with browserify and apply minification
  • build Sass with node-sass and apply minification
  • run watcher and rebuild changed assets

Building JavaScript

The browserify need to be installed globally,

$ npm install -g browserify

In package.json, in scripts section, will add such script,

  "scripts": {
    "build-js": "browserify public/js/app.js -o public/build/app.js",

Since I also use several transformations in my applications, the Browserify have to properly configured for that. It check’s if package.json contains browserify section, and if it does – will use it contents as own options.

  "browserify": {
    "transform": [
      "babelify",
      "envify"
    ]
  },

Building Sass

As with Browserify, node-sass need to be installed globally,

$ npm install -g node-sass

Then package.json changes,

  "scripts": {
    "build-js": "browserify public/js/app.js -o public/build/app.js",
    "build-sass": "node-sass public/sass/main.scss public/build/main.css",

Minification

Now, let’s minify both assets using one of the best concepts ever – Unix pipes.

We need two packages additionally, uglifyjs and cleancss.

$ npm install -g uglifyjs clean-css

And corresponding scripts,

  "scripts": {
    "build-js": "browserify public/js/app.js -o public/build/app.js",
    "build-sass": "node-sass public/sass/main.scss public/build/main.css",
    // minifying
    "build-min-js": "browserify public/js/app.js | uglifyjs -o public/build/app.min.js",
    "build-min-sass": "node-sass public/sass/main.scss | cleancss -o public/build/main.min.css",

Watching

Now, let’s apply watching. One of the watchers I use for several years already, that works best for me is nodemon.

nodemon is not only able to watch file changes and restart node processes if necessary, but also running custom commands.

  "scripts": {
    "build-js": "browserify public/js/app.js -o public/build/app.js",
    "build-sass": "node-sass public/sass/main.scss public/build/main.css",
    "build-min-js": "browserify public/js/app.js | uglifyjs -o public/build/app.min.js",
    "build-min-sass": "node-sass public/sass/main.scss | cleancss -o public/build/main.min.css",
    // watching
    "watch-js": "nodemon -e js -w public/js -x 'npm run build-js'",
    "watch-sass": "nodemon -e scss -w public/sass -x 'npm run build-sass'",

Complex tasks

Typically, you need to run few tasks simultaneously, e.g. build all scripts or watch all application. We can combine commands, by running background tasks,

"build": "npm run build-js & npm run build-sass",
"watch": "npm run watch-js & npm run watch-sass",

To build full app,

$ npm run build

or to watch it,

$ npm run watch

Using dev-dependencies

Global packages are not cool, cause they might be missing on developers box there application is cloned. Moreover, dependency management becomes a bit more complex, if you need to work on different projects depending on different tools versions. As @bcomnes very correctly noticed, all tools as browserify, uglify etc. can be installed as local dev-dependency, which are fetched during npm install and will be available to call inside project folder as global commands,

$ npm install --save-dev browserify uglifyjs node-sass clean-css

So, the package.json got such update,

"devDependencies": {
  "browserify": "^9.0.7",
  "clean-css": "^3.1.9",
  "node-sass": "^2.1.1",
  "uglifyjs": "^2.4.10"
},
Takeaways
  • Once you implement front end library, consider UMD so your modules are reusable in any environment.
  • Embrace CommonJS, use Browserify/Webpack/Whatever to use CommonJS (or ES6) on client.
  • For many cases, you really don’t need Grunt or Gulp, all is easily doable with NPM scripts.

As example, please refer to brick, the project I currently use as boilerplate for new applications.

Discover how to optimize your DevOps workflows with our cloud-based automated testing infrastructure, brought to you in partnership with Sauce Labs

Topics:

Published at DZone with permission of Alexander Beletsky, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}