Manage javascript library dependencies via bower in Grails
I loved the way node package manager loads and manage the JS dependencies, thought of doing that in my grails project as well. Until now all our third party JS files used to live with our source code. So loading them the way Maven loads Jar dependencies for us is what we are going to discuss in this blog.
We would need to install node.js, Grunt and bower to make it work the way we just talked about. After going through few write ups, I came up with the few concrete steps to be followed which are given below :
1. Install node.js, if it is not installed.
2. In your project folder create following files:
a. package.json
b. Gruntfile.js
c. bower.json
d. “.bowerrc”
3. Create two scripts files to install grunt and bower preferably under project/scripts folder.
a. InstallGruntAsAdminStep1.sh
b. InstallGruntStep2.sh
4. To update or install new dependencies are they are changed automatically during run-app, update your _Events.groovy to execute grunt tasks.
5. Now go to home folder on your Terminal/Command prompt and execute the following script
InstallGruntAsAdminStep1.sh (Run this as a Admin/sudo user).
6. Now go to project folder on your Terminal/Command prompt and execute the following script
InstallGruntStep2.sh (Run as your regular user).
7. Now try grails run-app command. It should download required dependencies like angularjs etc.
package.json :
[javascript]
{
"name": "ProjectName",
"version": "0.0.0",
"dependencies": {
"bower": "1.3.8",
"grunt": "^0.4.5",
"grunt-shell": "^0.7.0"
},
"scripts": {
"postinstall":"bower install"
},
"main": "Gruntfile.js",
"author": "Amit Jain",
"license": "GPL-2.0"
}
[/javascript]
Gruntfile.js:
[javascript]
module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-shell");
grunt.initConfig({
shell: {
options: {
stdout: true
},
localInstall: {
command: "./node_modules/.bin/bower update –quiet –offline"
},
webInstall: {
command: "./node_modules/.bin/bower update –quiet"
}
}
});
grunt.registerTask("localInstall", [ "shell:localInstall"]);
grunt.registerTask("webInstall", [ "shell:webInstall"]);
grunt.registerTask("default", ["localInstall"]);
};
[/javascript]
bower.json: This file provides the list of required JS dependencies, you may like to update it as per your requirements.
[javascript]
{
"name": "projectName",
"version": "0.0.0",
"dependencies": {
"angular": "1.2.20",
"bootstrap": "3.1.1",
"angular-resource": "1.2.20",
"angular-route": "1.2.20",
"angular-bootstrap": "0.11.0"
}
}
[/javascript]
“.bowerrc” : This file is required only when we want to configure the path where our js dependencies are to be downloaded.
[javascript]
{
"directory" : "web-app/bower-components"
}
[/javascript]
_Events.groovy
To check for any dependencies required to be downloaded, we executed the grunt tasks for the same in _Events.groovy as given below :
[groovy]
eventCompileStart = {kind ->
// Ants Project is available via: kind.ant.project
executeGruntTasks()
// Obtain status and output
}
private void executeGruntTasks(){
println "| Load js dependencies from cache…"
def proc = "grunt".execute() // execute default task to load dependencies from local cache.
proc.waitFor()
if(proc.exitValue()!=0){
println "| Error occured while loading dependencies from local cache : ${proc.err.text}"
println "| Try loading dependencies from web…"
proc = "grunt webInstall".execute()
proc.waitFor() // Wait for the command to finish
println "Output: ${proc.in.text}"
}
}
[/groovy]
InstallGruntAsAdminStep1.sh
[shell]
npm install
npm install -g grunt-cli
npm install -g grunt
npm install -g bower
npm install -g grunt-shell
[/shell]
InstallGruntStep2.sh
[shell]
npm install
npm install grunt
npm install bower
npm install grunt-shell
[/shell]
Hopefully it would have worked after following these steps, incase you face any issue please discuss them as comments. And if anybody has ideas for improvements please share them for everybody’s benefit.
Cheers!
Amit Jain
amit@intelligrape.com
Why do you install all those packages in InstallGruntAsAdminStep1.sh if you already have them in package.json?
sudo npm install should be enough right?
You are right Jorge. It shouldn’t be required in general. The first time I implemented it I had to install it globally otherwise it couldn’t access just “grunt” from _events.groovy. Later on we removed this install script and instead provided the full path to the “grunt” command in _events.groovy which worked. I would update the blog.
Thanks for you suggestions!