Use prepublish script to automate bower

Developers are lazy with a purpose. The goal is to make your life easier and automate things. One common task when developing your application is to install bower dependencies right after running npm install. You’re thinking where should you automate this? Package.json has few candidates but you’re not sure which one to use.

“Package.json has postinstall and prepublish scripts but I’m not sure where things like running bower should go.”

It turns out one of the them is exactly the right place.

Prepublish and postinstall lifecycle events

To understand the roles of prepublish and postinstall scripts we need to look at how modules are published.

Publishing a module to the npm repository works in few steps. What gets published is not identical to what is available in your git repo. There is additional step included - the prepublish lifecycle event.

The prepublish script is dedicated to creating artifacts that are not dependent on target architecture. They can be created once on the developer’s machine during the process of publishing. They are then stored over at npm repository and can be used every time they are needed. They are compiled once and then used everywhere.

Postinstall script, on the other hand, is run every time the module is installed. It is run on the target machine. It is dedicated to compiling code dependent on the target system. Usually this performed using node-gyp.

Diagram
Figure 1. Relationship between prepublish and postinstall lifecycle events.

Prepublish script is run once and postinstall script run every time the package is installed.

Prepublish is included in local npm install

You are developing an application that will never be published to npm. How does this fit into your situation?

The prepublish script is also run when running local npm install without any arguments. This is exactly what we are after. We can follow the same guidelines with package.json scripts in our own application as with published modules.

The lifecycle scripts called during local npm install are:

1 preinstall
2 install
3 postinstall
4 prepublish

Presence of devDependencies

For separating runtime dependencies from development time dependencies package.json has dedicated sections for each.

Development time dependencies or devDependencies are normally present only when you are developing something locally. In other cases such as production deployments they are omitted. This also includes the dependencies of your project.

In other words, the devDependencies are not installed for anything you have under node_modules. Therefore postinstall scripts depending on devDependencies such as bower, grunt or gulp will fail.

Postinstall script is clearly a bad choice for automating these tools. Although it will work for local modules, since postinstall is run for local npm install without arguments, it is better to follow the same principles than for published modules. In fact, postinstall script is gaining less friends and has been subject of getting the boot.

Executables are in path

Executables contained in dependencies are linked to the node_modules./bin directory during npm install. When running the lifecycle scripts in package.json, npm extends the path to include this directory. This allows us to write simple commands without directory prefixes.

1 "prepublish": "bower install"
2 
3 (instead of)
4 
5 "prepublish": "node_modules/.bin/bower install"

Conclusion

Use prepublish script for normal build related tasks that are not dependent on platform architecture. Transpiling to JavaScript, compiling SASS, minifying, running grunt, running gulp and friends all belong to prepublish. If you need to compile platform dependent code, then look into node-gyp. Postinstall script is rarely needed at all.

Asynchronous calls - the surest way
to get lost with Node.js
Asynchronous Call Tree
What if you could turn any spec into working code?
GET FREE LESSON
Share article: