Cordova

Cordova: CLI Hooks

I recently did a code review of a Cordova project for a student team. Surprisingly, things looks pretty clean with the code, but I informed the team that they needed to properly setup their Cordova hooks to automate their build process. Some of my recommendations included the following:

  • Automatically add the necessary plugins that your app uses on the “after_platform_add” event.
  • Cleanup and remove any debug, map or non-minified JavaScript or CSS files in your platform assets folder on the “after_prepare”.
  • Automatically setup the ant.properties file for Android to specify the key to use for signing your release.

With Cordova, it’s recommended to write these script files in JavaScript and use the node.js interpreter to execute them.

The following example script I created will go through the WWW folder and remove any “extra” files to help minimize the size of your package.

#!/usr/bin/env node
var fs = require('fs-extra');

//
// This hook removes the specified javascript files (non-minified)
//

var folders = [
  'assets/www/lib/css/ionic.css',
  'assets/www/lib/js/ionic.js',
  'assets/www/lib/js/ionic.bundle.js',
  'assets/www/lib/js/ionic-angular.js',
  'assets/www/lib/js/underscore.js',
  'assets/www/lib/js/angular/angular.js',
  'assets/www/lib/js/angular/angular.min.js.map',
  'assets/www/lib/js/angular/angular-animate.js',
  'assets/www/lib/js/angular/angular-animate.min.js.map',
  'assets/www/lib/js/angular/angular-cookies.js',
  'assets/www/lib/js/angular/angular-cookies.min.js.map',
  'assets/www/lib/js/angular/angular-loader.js',
  'assets/www/lib/js/angular/angular-loader.min.js.map',
  'assets/www/lib/js/angular/angular-resource.js',
  'assets/www/lib/js/angular/angular-resource.min.js.map',
  'assets/www/lib/js/angular/angular-route.js',
  'assets/www/lib/js/angular/angular-route.min.js.map',
  'assets/www/lib/js/angular/angular-sanitize.js',
  'assets/www/lib/js/angular/angular-sanitize.min.js.map',
  'assets/www/lib/js/angular/angular-scenario.js',
  'assets/www/lib/js/angular/angular-touch.js',
  'assets/www/lib/js/angular/angular-touch.min.js.map',
  'assets/www/lib/js/angular-ui/angular-ui-router.js'
];

var rootdir = process.argv[2];
var platforms = (process.env.CORDOVA_PLATFORMS || '').split(',');
folders.forEach(function(folder) {
  (platforms || []).forEach(function(platform) {
    var filename = rootdir+'/platforms/'+platform+'/'+folder;
    fs.delete(filename, function(err) {
      if (err) {
        return(console.log('Failed to remove file "'+filename+'". Error: '+err));
      }
      console.log('Successfully removed folder/file "'+filename +'"');
    });
  });
});

Works For Me…

The team quickly replied back that they were getting an error when trying to write their own scripts. The script wasn’t running with the following command line output:

cmd.exe /s /c "<path to project root>\hooks\<event name>\<hook script>" "<project root>"

We checked Cordova versions (4.3) and everything was the same between machines. I tested their project with one of my scripts and it worked as expected. However, when running their script, I was getting the same error. Looking over their hook script, everything looked fine.

However, when comparing the shell output between a working script and a failing script. I discovered that the wrong interpretor was being run. Node.js was not being called to process the file. Below is a successful call:

Running command: "C:\Program Files\nodejs\node.exe" "<project root>\hooks\after_prepare\010_purge.js" "<project root>"

I began to suspect that file encoding was the problem. The #! at the beginning of the file wasn’t being honored. To verify, I copied and pasted the contents of my working script into their script file and it failed. If I copied and pasted the contents of their file into my working script file it would work. Although that might have been a work-around for the problem, I wanted to know why this wasn’t working.

Not knowing how the file was originally created or what editor was used by the team, I created a new file with Notepad++ and pasted their contents into that file. Saved it and it ran with no problem. So my suspicions were confirmed. Whatever editor they saved the file with didn’t use the right text encoding.

I sent my findings back to the students where they verified that the file had been created with Visual Studio. Further comparison of the files showed that Visual Studio was saving the file with byte-order mark (BOM). Removing the BOM from the file when saving allows the CLI tools on Windows to select the proper shell (node.js).