Managing different builds of your Cordova application is relatively easy using hooks.
I actually have a number of deployment environments, all built from my local source tree.
- web development, which lets me crank out the non cordova specific look and feel
- test, which runs qunit/sinon unit tests
- ripple development, which lets me run in the browser, but still test cordova specific events (online/offline, for example)
- staging, which is used to build a phone distributable binary, but runs against our QA servers
- production, the same as stage, but against our production servers
The first two don’t require a cordova prepare
but the last three do. The first three let you make changes in files and reload your web browser, where the last two require a phone or emulator to run.
For a while I was switching between these manually, but eventually it became a pain, so I automated it. The automation is driven off an environment variable, which is accessed by a after_prepare
hook: TARGET=stage cordova build android
sets target to stage
, and process.env.TARGET
is the nodejs code in the hook script that can access that environment variable.
There is a config directory in the top level of the project and in there is a project.json file that contains project specific configuration for each target environment, like the server hostname.
One wrinkle that took me some time to figure out was how to have code that was in the www directory ‘just work’ out of the version control system, so I could do quick web development. In the end, I have code like this in my javascript files
App.config = {}; App.config.datahostname = /*REP*/'qa-host.com'/*REP*/;
and then this regular expression to replace it with the value from the configuration file when file is being prepared:
function replace_string_in_file(filename,to_replace,replace_with) { var data = fs.readFileSync(filename, 'utf8'); var result = data.replace(new RegExp(to_replace,"g"), replace_with); fs.writeFileSync(filename, result, 'utf8'); } ... // iterate over files to be updated with config info replace_string_in_file(fullfilename,"/\\*REP\\*/'qa-host.com'/\\*REP\\*/",configobj[target].datahostname);
Note that I don’t read/write files async–this happens rarely enough that the performance increase isn’t worth some of the weirdness you will see if more than one hook acts on your file, or if you edit the file right after running the hook.
Since /*REP*/stuff/*REP*/
isn’t likely to match anything inadvertently, you could probably parse all your files, but my configuration is limited to 3-4 files, so it is easier just to name them explicitly.
Note that if during development, your javascript needs to access data served by a different web server (an API somewhere, for example), you’ll need to set up CORS correctly. We’ll set that up in the next blog post.