How to set up simple, easy-to-use build scripts in NPM/Node (without Grunt or Gulp)
Even though a language like JavaScript doesn't require any sort of compiling "out of the box", there are a LOT of necessary tools out there, even for "pure" JavaScript developers, that require a "build step" before they actually do anything useful.
Here are some examples that you may have used or heard of:
- Typescript and Coffeescript both need to be compiled down to JavaScript.
- Browserify is an AWESOME tool that let's you use
require
statements in front-end code, and bundles all your code together automatically into one big file. - Any CSS preprocessor (like SCSS, Less, Stylus) needs to be compiled into raw CSS
The point is, if you're serious about building web applications, you need to have some level of comfort with setting up build scripts in your applications.
Unfortunately, learning how to do this can be a bit daunting. There are build tools out there like Grunt and Gulp that have their own learning curves, and all of the above packages (Browserify
, Typescript
, etc) have their own documentation that tells you how to compile/use them from your command line.
Good news. You don't need to use Grunt
or Gulp
(though they both work great, and I'm certainly not saying you shouldn't use them). It's really easy to set up build scripts directly in the package.json
file of any Node application.
Walkthrough
Browserify is awesome, so I'll show you how to set up your app to use browserify in this example. However, keep in mind that this general approach should work for any tool that requires a build/compile step.
Step 1: Set up your application
Hopefully if you're here, you're familiar with npm
and node
.
From the command line, run npm init
. This will create a package.json
file in your app's directory.
Step 2: Go check out the docs for whatever tool you're using
Since we're trying to set up Browserify
in this example, we'll head over to http://browserify.org/.
Scrolling down a bit, we see that if we install browserify
globally via npm
, we can run browserify main.js -o bundle.js
to compile all the JavaScript files required in a file named main.js
, and output the result to a file called bundle.js
.
Step 3: Try things out from the command line
Ok, let's do that just so we can see how everything works.
npm install -g browserify
- Create a file named
main.js
and put the following code inside
var objectFromAnotherFile = require('./otherfile.js');
console.log(objectFromAnotherFile.message);
- Create a file name
otherfile.js
and put the following into it:
module.exports = {
message: 'This is a message'
};
Ok, at this point, if you want to run this code inside an html
file or on a website, you would need to include both of the above JavaScript files in their own <script>
tags.
However, if you now run browserify main.js -o output.js
, you can mash both of these files into just one file (output.js
). (and actually, this will work even if you require()
20 files in main.js
).
At any rate, the important part is that we've confirmed that we can run browserify
from the command line when it's already been installed globally. BUT, now let's set it up so we can run it using npm
and without installing browserify globally.
Step 4: Modify package.json to do the work for you
So, in the previous paragraph I said we actually didn't need browserify
to be installed globally. So, if you like, feel free to run npm uninstall -g browserify
(though it's not necessary).
Next:
Run
npm install --save browserify
. This will install the package locally to the directory you're in, and will also addbrowserify
to the list of packages inpackage.json
- Technically speaking, you should run
npm install --save-dev browserify
, since this is a dev dependency, but it doesn't make much difference for this tutorial. Either command will work.
- Technically speaking, you should run
Add an entry to the
scripts
section ofpackage.json
that mimics the command you just tested in the previous step.
Your package.json
file might look something like this now (note, depending on what command you ran earlier, the browserify package might be in dev-dependencies):
{
"name": "example-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle-js": "browserify main.js -o bundle.js"
},
"author": "Greg Trowbridge (http://gregtrowbridge.com)",
"license": "ISC",
"dependencies": {
"browserify": "^10.2.4"
}
}
Step 5: Run it!
Now that this script is set up in npm, you can now run browserify by running the command npm run build-js
.
Step 6: So what?
At this point, it's pretty reasonable to think "So what?".
Here's why all this matters:
- For starters, you no longer need to remember the
browserify
command. You can just run things directly throughnpm
. - More importantly, you can also follow this same process for all your build and compile scripts, and then run them ALL with a single command.
If you do this, your package.json
file might end up looking something like this (notice how I "combine" multiple commands into one command by using &
):
{
"name": "example-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle-js": "browserify main.js -o bundle.js"
"build-css": "[some command to compile all your CSS]"
"build": "npm run bundle-js & npm run build-css"
},
"author": "Greg Trowbridge (http://gregtrowbridge.com)",
"license": "ISC",
"dependencies": {
"browserify": "^10.2.4"
}
}
Now you can bundle your JavaScript and compile your css by just running npm run build
.
- Finally, this now means that it's easier to deploy your application to, for example, Heroku. For example, if you want to automatically bundle your JavaScript and compile your CSS whenever
npm install
is run, you can add those instructions topostinstall
:
{
"name": "example-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle-js": "browserify main.js -o bundle.js",
"build-css": "[some command to compile all your CSS]",
"build": "npm run bundle-js & npm run build-css",
"postinstall": "npm run build"
},
"author": "Greg Trowbridge (http://gregtrowbridge.com)",
"license": "ISC",
"dependencies": {
"browserify": "^10.2.4"
}
}
Set up like this, when Heroku (or anyone) runs npm install
, npm
will know to also run the postinstall
instructions as well.
Next time you need your app to be able to bundle JavaScript, compile CSS, migrate a database, or ANYTHING else, consider setting things up directly in package.json
.