Build Configurations in Cordova using Hooks
When working with Cordova or Phone Gap, you might need a way to configure your dev build differently from your production build. For example, you might have a set of web services to be used for development, and another for production. This simple Cordova Hook loads the configuration appropriate to the build.
Hooks are a well documented mechanism in Cordova which executes the developer’s custom scripts at certain points in the build process. The best example I have found is this post by Dan Moore.
In this example, all settings for a given configuration are in one file. The appropriate files is substituted in when you build (or “prepare”) your project. This is written in node.js for portability.
- Wire up your code so that all “switchable” settings are in one file, config.js. Here’s an example:
var config = { oneSvc: "http://www.example.com/ws/MyService.svc/MyService", anotherSvc: "http://www.example.com/ws/YourService.svc/YourService" }
…then use config.oneSvc and config.anotherSvc to access the settings in your code. Remember to include config.js in your index.html.
- Create an alternate config file in your config directory, called config-prod.js or config-test.js.
- In your development environment, set a variable called TARGET with the appropriate value (e.g. “prod” or “test”). If this variable is not set, config.js will be used as-is.
- Place the following code in your .cordova/hooks/after_prepare directory.
- Build the project as usual.
#!/usr/bin/env node /** * Created by Michael on 5/13/2014. * * Detect the current build by looking at the TARGET env variable. * If TARGET does not exist, make no change. * Otherwise, replace config.js with config/config-xxxx.js (where TARGET=xxxx) * If config-xxxx.js doesn't exist, execution will fail. * * Before running this, set the target as: * export TARGET=prod * */ var fs = require("fs"); var path = require("path"); var rootdir = process.argv[2]; console.log("Running hook: "+path.basename(process.env.CORDOVA_HOOK)); if (process.env.TARGET) { var srcfile = path.join(rootdir, "config", "config-"+process.env.TARGET+".js"); //do this for each platform var configFilesToReplace = { "android" : "platforms/android/assets/www/js/config.js" ," ios" : "platforms/ios/www/js/config.js" }; for(var platform in configFilesToReplace) { console.log("Modifying config for platform "+platform+", TARGET="+process.env.TARGET); var destfile = path.join(rootdir, configFilesToReplace[platform]); if (!fs.existsSync(srcfile)) { throw "Missing config file: "+srcfile; } else { console.log("copying "+srcfile+" to "+destfile); fs.createReadStream(srcfile).pipe(fs.createWriteStream(destfile)); } } } else { console.log("TARGET environment variable is not set. Using default values."); }
Great article! Thanks for sharing. This is exactly the approach I was about to implement. I already have a “config.js” file so now I just need to use your approach to swap the target files appropriately.
Hi Michael, I’m seeing similar code in so many tutorials but I can’t access the rootdir, I don’t seem to be able to use
var rootdir = process.argv[2];
I only have indexes 0 and 1 in process.argv:
console.log(process.argv);
[ 'node',
'/path/to/my/project/hooks/before_build/my-hook.js' ]
Any idea why I don’t get that [2] array item?
Hi Pete, it looks like you’re running the hook directly using node. Instead, the hook should run automatically when you run “cordova build” from the command line.
Pete thanks for this article, but I am new to phonegap so I am not sure where to set this “variable called TARGET” Where am I setting this?
note to anyone as green as me that comes along (long time windows dev, but totally uneducated in mac, and cordova, for that matter):
after much head banging, i found i needed to a) chown my project’s platform dir, and b) chmod to 755 the hook script.
thanks for the great post though!