Throughout the book, I’ve tried to show you as much as I can about the Cordova project, tools, APIs, mobile SDKs, and more. In this last chapter, I show you some additional tools you can use with your Cordova application projects. Herein I show you tools you can use to find errors in your JavaScript code before you even begin to test your applications, highlight some Cordova-aware code editors, introduce you to some Cordova development productivity enhancement tools, and demonstrate how to use build tools to optimize your Cordova applications.
There is a wide range of tools available to Cordova developers; I am only going to cover some tools I use myself or thought were interesting enough to learn about (so I could write about them here).
If you’re like me, you like to know whether there are errors in your Cordova applications’ JavaScript code before you try to test them on simulators or physical devices. If you’re using an HTML or JavaScript-aware IDE to code your application’s JavaScript, you’ll know right away when there are problems. Early on in the book I told you that you could use any code editor you want, and many of them may have an awareness of the language, but some do not.
When I worked on Apache Cordova 3 Programming, I used the open-source Aptana IDE to edit my sample application JavaScript code. I selected this tool because it allowed me to automatically format the code in such a way that it was easy to paste it into the manuscript. It is JavaScript aware, more or less, but didn’t show me the errors in my code. Late in the process, I discovered JSLint and JSHint, command-line tools I could use to validate my code and point out any errors therein. I’ll describe each of these tools in the following sections.
You can manually execute either one of these tools as part of your development process but can also use the hooks capabilities of the Cordova CLI (described in Chapter 6, “Automation and the Cordova CLI”) to have them execute automatically during the prepare process.
As cool as these command-line tools are, though, I’ll show you later how you can make executing them an automatic part of saving your code in Adobe Brackets.
One of the early JavaScript validators is a program called JSLint (www.jslint.com) by Douglas Crockford. The program is available through a web interface, or you can install it as a Node module. Since Cordova uses Node and we want to be able to run this program from the command line, we’ll install the Node module. To install JSLint on a Windows system, open a terminal window and execute the following command:
npm install –g jslint
On Macintosh OS X you will need to execute this command:
sudo npm install –g jslint
With the installation completed, you can navigate to a folder containing JavaScript files and validate them using the following command:
jslint <javascript_file_name>
For one of my sample applications, I could validate the application’s index.js using the following command:
jslint index.js
JSLint will load, process the file, and update the console with the list of errors it found in the file:
index.js
#1 Missing 'use strict' statement.
alert("onBodyLoad"); // Line 6, Pos 3
#2 Expected 'document' at column 5, not column 3.
document.addEventListener("deviceready", onDeviceReady, false); // Line 9, Pos 3
#3 'onDeviceReady' was used before it was defined.
document.addEventListener("deviceready", onDeviceReady, false); // Line 9, Pos 44
#4 Missing 'use strict' statement.
console.log("Entering onDeviceReady"); // Line 13, Pos 3
#5 Expected 'console' at column 5, not column 3.
console.log("Cordova: " + device.cordova); // Line 14, Pos 3
#6 'device' was used before it was defined.
console.log("Cordova: " + device.cordova); // Line 14, Pos 29
#7 Expected 'navigator' at column 5, not column 3.
navigator.notification.alert("Cordova is ready", null, "Device Ready", btnText);
// Line 16, Pos 3
#8 Expected 'console' at column 5, not column 3.
console.log("Leaving onDeviceReady"); // Line 17, Pos 3
#9 Missing 'use strict' statement.
function makeListItem(textStr) { // Line 22, Pos 3
#10 Expected 'return' at column 9, not column 5.
return '<li class="topcoat-list_ _item">' + textStr + '</li>'; // Line 23, Pos 5
JSLint found 44 errors in my short little file, then quit before finishing with the rest of the file. It didn’t quit because it failed somehow. It basically figured that if the file had that many errors, it didn’t need to keep going until I’d fixed most of them. The idea is that you should fix the errors, then repeat the process until all errors have been addressed.
From what I’ve read, Crockford believes in a very specific format for JavaScript code, and the terminal output proves it. For my manuscript, I configured my code formatter to use two spaces for indentation. JSLint, on the other hand, expects four spaces, so the linter is going to spit out an error for every indented line in my code. For this reason, and because JSLint is not as configurable as many people would like, the project was forked and JSHint was created as an alternative. I describe this tool in the following section.
JSHint (http://jshint.com/) started as a fork of JSLint, designed to be more tolerant and more configurable than JSLint. To install JSHint on a Windows system, open a terminal window and execute the following command:
npm install –g jshint
On Macintosh OS X you will need to execute this command:
sudo npm install –g jshint
With the installation completed, you can navigate to a folder containing JavaScript files and validate them using the following command:
jshint <javascript_file_name>
For one of my sample applications, I could validate the application’s index.js using the following command:
jshint index.js
In this file, the same file I used in the previous section, JSHint found only five errors:
index.js: line 6, col 22, Missing semicolon.
index.js: line 10, col 2, Unnecessary semicolon.
index.js: line 23, col 5, Expected an assignment or function call and instead saw an
expression.
index.js: line 23, col 11, Missing semicolon.
index.js: line 23, col 58, Expected an assignment or function call and instead saw
an expression.
5 errors
Figure 18.1 shows the process running in a terminal window.
As you can see, JSHint doesn’t care about how I’ve formatted my code, only the technical accuracy of the code. It will be much easier for me to locate and fix the bugs in the file because there are simply fewer of them—only because of the tool I selected to validate my code.
Now, there are many times when developers will do something in their code that is technically accurate but JSHint won’t have any way of knowing. One of the best examples I can think of is the Cordova APIs. When I’m coding a Cordova application, I can use the Cordova APIs in my code without having the API’s JavaScript code handy. When the application is running in a Cordova container, the cordova.js file loads the APIs for me, and the associated JavaScript files will be in the container, placed there automatically by the Cordova CLI.
If you take a look at the JSHint documentation at www.jshint.com/docs/, you’ll see that there are many configuration options you can use to tweak JSHint (and JSLint as well). The tweaks are generally applied by simply adding options to the JavaScript file. For example, to instruct JSHint that I want undefined and unused variables to be flagged, I can add the following to the beginning of my source code file:
/* jshint undef: true, unused: true */
Then, when JSHint runs, I will see the following output:
index.js: line 8, col 3, 'alert' is not defined.
index.js: line 11, col 3, 'document' is not defined.
index.js: line 15, col 3, 'console' is not defined.
index.js: line 16, col 29, 'device' is not defined.
index.js: line 18, col 3, 'navigator' is not defined.
In this example, alert
, console
, document
, and navigator
are built-in capabilities available in the browser and the Cordova WebView, so even though I don’t have JavaScript files that reference them, they’re still valid. To override JSHint and let it know that these variables are OK, I can add the following to my source code file:
/*global alert*/
/*global console*/
/*global device*/
/*global document*/
/*global navigator*/
This defines the objects so that JSHint will ignore them. The comments are ignored by JavaScript but processed by JSHint.
There’s a whole lot more you can do with these tools; I’ve only touched the surface here. I simply wanted to let you know about some of the tools that can help you write better code. In the next section, I’ll show you how those tools are exposed through code-editing tools so that you can validate your code as you write it.
As I mentioned before, when working on the code for my previous PhoneGap/Cordova books, I used Aptana Studio to edit the HTML and JavaScript source code. For this book, I decided to use the then-still-in-beta Adobe Brackets. About halfway through the book, I discovered WebStorm and spent some of my time with that editor as well.
Both editors support JSLint and JSHint, plus both can work directly with Apache Cordova and Adobe PhoneGap projects. In this section, I’ll introduce you to each editor and show you how to use the Cordova-related special capabilities of each.
In 2012, Adobe announced a new open-source project, the Brackets web code editor (http://brackets.io/). The editor is lightweight, JavaScript based, and uses plugins to enhance its capabilities. With the editor you get basic editing of web content (HTML, CSS, and JavaScript), syntax highlighting, and more. Through extensions, you can have support for JSLint, JSHint, Apache Cordova, and much more.
The editor is built using the Chromium Embedded Framework (CEF), and anyone can download the code to see how all of this stuff works. Brackets supports Windows, OS X, and Linux, so it’s available on any platform a Cordova developer would use.
To use Brackets, download the installer from http://brackets.io and run it. Figure 18.2 shows the Brackets editor with a Cordova project open. On the left is the list of open files and below that the project folder structure. With Brackets, you can open individual files or you can open an entire folder and quickly switch between files. It even supports live preview, which is pretty useful when writing web applications.
For JavaScript code editing, I always turn on the Auto Close Braces option (under the Edit menu) which causes Brackets to automatically add closing braces when editing JavaScript files. Beyond that one setting, all of the other interesting capabilities for me come through extensions.
To access Brackets extensions, open the File menu and select Extension Manager. A window will appear similar to the one shown in Figure 18.3. In this example, I’m using the extension search capabilities to locate and install the Beautify extension (http://goo.gl/yoo0t0). Beautify uses the JS Beautifier module to properly format source code.
To install an extension, select it from the list and click the Install button shown on the right side of Figure 18.3. For the Beautify extension, you can beautify any file by opening the Brackets Edit menu and selecting Beautify, or you can have Beautify run every time you save any file by enabling the plugin’s Beautify on save option located in the same menu.
I have this extension enabled to beautify on every save; that way all of my source code files are always cleanly formatted. The extension works on HTML and JavaScript files and is so quick you won’t even notice it running.
For the manuscript, I like to indent the structure of the code by two spaces for each level. This provides my code with clear indentation but utilizes the minimum of real estate. Beautify defaults to indenting by tabs, but for the manuscript I had to use spaces. The extension offers a quick and easy way to change that setting. If you look in the bottom-right corner of Figure 18.2, you can see Spaces: 2. To switch from spaces to tabs, simply click the word Spaces. To switch from tabs to spaces, click Tabs (not shown). To adjust how many spaces are used for indentation, click on the 2 and type a new value. That’s all there is to configuring Beautify.
There is also a JSHint extension for Brackets, so I use that to have Brackets automatically check for errors every time a file is saved. You can see an example of this in Figure 18.4. I’ve opened up a JSHint Problems report at the bottom of the Brackets window.
Notice the triangle on the bottom right of the screen—that indicates that there are problems with the code. Click the symbol to open or close the Problems report shown in the figure. This feature is another reason why I split out my Cordova application’s web code into .html and .js files everywhere—it enables me to use JSHint more efficiently in Brackets.
Tip
Double-click on any of the lines in the JSHint Problems area to highlight the corresponding code line in the editor.
Brackets doesn’t have an awareness of Apache Cordova, but since it’s an Adobe product, I knew that it could. There are currently two Brackets Cordova plugins available as shown in Figure 18.5. The first one is published by Ray Camden, a developer evangelist at Adobe, so I decided to select that one. Both plugins support only OS X, which is disappointing, but there’s nothing I can do about it unless I want to make my own extension or submit fixes to Ray’s.
After you install the extension, whenever the extension detects that you are working with a Cordova project, it enables some Cordova-aware features in the editor. The first thing you must do is open a Cordova project. To do this, open the Brackets File menu and select the Open Folder option. Navigate to a Cordova project folder and click the Open button as shown in Figure 18.6.
With the project selected, notice the Cordova icon shown in the upper-right side of Figure 18.7. When the button is enabled, you can click on it to open the panel shown at the bottom of the figure. From the Platforms tab shown in the figure, you can add or remove target platforms from the project by clicking true or false in the Enabled column. To execute the application project in a simulator or physical device, click the Emulate or Run option in the Build Options column.
You can manage plugins directly from this panel as well. Select the Plugins tab at the top of the panel and you will be shown a list of the plugins that are currently installed in the project. Click the Remove link to the right of the plugin version to remove the plugin from the project. To add plugins to the project, use the search field to locate the plugin, then click the Add Plugin button to add it to your project (see Figure 18.8).
That’s it; that’s all there is to this plugin. It’s not earth-shattering, but it’s at least useful. I would like to see the ability to add new projects added to the extension.
There’s also a PhoneGap plugin for Brackets, but it’s pretty lame. All it does is allow you to log in to the PhoneGap Build service as shown in Figure 18.9 and interact with your existing PhoneGap Build projects.
After you have logged in, you can view your existing projects and initiate a rebuild or delete the project from the panel (Figure 18.10).
For all the features I’ve described, I really like Adobe Brackets and it will probably remain my primary editor for web application projects. I also love the extensibility of the editor and hope I can find some time to write my own plugins or help enhance some existing ones.
As I worked on this manuscript, I noticed an email on the Cordova dev list describing the Cordova capabilities of the WebStorm JavaScript IDE (http://goo.gl/ZPaELr). WebStorm is from JetBrains, the company behind IntelliJ IDEA, the IDE under the covers in Google’s Android Studio. Where Brackets is lightweight, quick, and nimble, WebStorm is not; it takes a really long time to start up and keeps grabbing focus as it completes its different startup scans.
WebStorm comes out of the box with support for Apache Cordova, Adobe PhoneGap, and Ionic. As long as WebStorm can detect your framework CLI installation, it will enable the features within the IDE.
When creating a new project, you can select PhoneGap/Cordova App as shown in Figure 18.11.
When you click the OK button, you will be prompted to select the CLI command you want to use for this new project. Select cordova.cmd (on Windows) as shown in Figure 18.12 to create a Cordova project. Select phonegap.cmd to create a PhoneGap project.
If you have an existing project open, WebStorm will ask whether you want the current window replaced as shown in Figure 18.13.
To create the project, WebStorm invokes the appropriate CLI to create a new project. Figure 18.14 shows the new project in the editor. Notice the folder structure on the left; this is the same folder structure you have seen many times throughout this book. It was created using the CLI, so you can work with it here within the WebStorm IDE or switch out to a terminal window and work with the project via the appropriate CLI. Pretty cool stuff.
WebStorm can also manage the installation of Cordova plugins into the project as shown in Figure 18.15. Open the File menu and select Settings to open the dialog shown in the figure. Settings shows the list of plugins currently added to the project. To manipulate that list, use the buttons highlighted on the right side of the figure.
To add a plugin to the current project, click the plus sign (+) shown in the figure. WebStorm will open the Available Packages window shown in Figure 18.16. You can browse through the list of plugins from the Cordova Plugin Registry, or you can type a keyword in the search box to filter the results. When you select a plugin, click the Install Package button to add the plugin to your project.
Click the minus button (-) to remove a selected plugin. Use the up arrow, when enabled, to upgrade the selected plugin.
WebStorm also has support for running a hybrid application project directly from within the IDE. To enable this capability, you must first create one or more Run Configurations for your project. To do this, open the Run menu and select Edit Configurations. WebStorm will open the window shown in Figure 18.17. Click the plus sign (+) in the upper-left corner of the window to create a new configuration. WebStorm will prompt you to select the type of Run Configuration to create; select PhoneGap/Cordova from the list.
I haven’t dug into too many of the options in this dialog. For my testing all I needed to do was select the command that would be executed (run
versus emulate
, for example) and what target platform to use. As this is a Windows system, iOS wasn’t an available option, but on OS X it would be. With the Run Configuration defined, click the OK button to save your changes.
Now in the WebStorm main editing window shown in Figure 18.18 you should see your Run Configuration listed in the Run Target drop-down highlighted in the figure. Click the Run button to launch the selected Run Configuration. WebStorm will open a terminal window at the bottom of the editing window and launch the appropriate Cordova, PhoneGap, or Ionic CLI commands to run your project as you have defined.
WebStorm would be incomplete if it didn’t check your code for you as you typed. Built into the IDE is support for both JSLint and JSHint and more. To enable one of them, open the Settings window, expand Languages and Frameworks, and select the one that suits your requirements; you will see a panel open similar to the one shown in Figure 18.19.
In this example, I’ve opened the options for JSHint as I find JSLint to be too restrictive. To use this option, you must check the Enable checkbox highlighted at the top of the screen. Next, ignore or configure each JSHint option shown in the figure. WebStorm gives you access to most, if not all, capabilities of JSHint; you only have to decide which ones are important for you.
There’s a lot more to this tool; I’ve only touched the surface of what it can do. Its awareness of hybrid development tools makes it a great choice for Cordova, PhoneGap, and Ionic developers.
As you have seen already in this chapter, individuals and companies have produced Cordova-aware tools. In the previous section, I showed you some code editors that have features designed to help hybrid developers; in this section, I’ll show you some developer productivity enhancement tools available today.
There are quite a few products in this space, and I won’t be able to cover all of them. I meant to take a look at the Intel XDK (http://goo.gl/DmfHXG) but didn’t have time, and it’s got so many features that it likely would have required its own chapter. Maybe in the next book. I will spend some time here covering AppGyver and a new Eclipse project called THyM.
AppGyver (www.appgyver.com) provides a set of tools designed to help developers build web applications that are indistinguishable from native apps. They are best known for Steroids, a set of tools for Apache Cordova development. They also offer Composer, a browser-based designer for web applications, and Prototyper, a tool for quickly converting image files into application prototypes.
Steroids consists of a command-line tool for creating, managing, and running hybrid web applications. The CLI is pretty sophisticated, doing a lot more hand-holding than the Cordova or PhoneGap CLI will do. It also tells you a lot more about what to do next. It offers a set of UI controls a developer can leverage to create web applications that look and feel like native applications. It includes support for a navigation bar, loading page, views, and more.
To simplify testing and debugging, Steroids offers a Scanner application that is a lot like the PhoneGap Developer App. When you create your hybrid application, you can serve it from your local development system and use the Scanner app to download updates to the application so you can run it in real time without needing a build environment.
The Scanner application is available in the public app stores; you can see an example of the Android version in the Google Play store in Figure 18.20.
When you install the application, you’re prompted to enable a wide range of options as shown in Figure 18.21. The Scanner application comes preconfigured with many, if not most, Cordova plugins, so that’s why you have to enable so many options.
To manage hybrid projects using AppGyver, you use a terminal window and the steroids
command. AppGyver provides a tutorial that walks you through how to work with projects, so I’m only going to cover a highlight here.
Once you have a hybrid project created, you can test it pretty quickly using the steroids connect
command. When you execute the command, it will build the project, then host the application using a local server as illustrated in Figure 18.22.
It will then launch the system’s default web browser and display the page shown in Figure 18.23.
With this in place, launch the AppGyver Scanner application on a supported mobile device. You will see a screen similar to the one shown in Figure 18.24. Tap the Scan button in the middle of the screen, use the smartphone’s camera to capture the QR code shown in Figure 18.23, and the hybrid application will download and launch automatically in the Scanner application.
As you test the application and make changes to the application’s code, you can simply return to the terminal window (Figure 18.22) and press the keyboard’s Enter key to refresh the content and reload it in the mobile application.
AppGyver is worth looking at from a UI and developer experience standpoint. The company seems to be well funded and has released some interesting products.
The JBoss (www.jboss.org) tools team at Red Hat (www.redhat.com) created a suite of tools for mobile development and donated them to the Eclipse project as THyM, which stands for The Hybrid Mobile. The project adds cross-platform mobile development capabilities to the Eclipse IDE. Originally designed for Cordova development, the team added support for other distributions and frameworks. You can read about the project at www.eclipse.org/thym/.
Going forward, I’m going to skip the fancy spelling and just refer to the project as Thym.
The main parts of Thym are
New hybrid project wizard
Project import and export
Config.xml editor
Run options for Android and iOS
Plugin Discovery wizard
Thym is installed as an Eclipse plugin; simply open an instance of Eclipse, open the Help menu, and select Install New Software. In the Available Software wizard that appears, add the Thym project download site http://download.eclipse.org/thym/snapshots to the Work with field as shown in Figure 18.25. Select the project from the list of options, then click the Next button to work through the remainder of the installation wizard.
With the plugin installed, Eclipse now has the new project type called Hybrid Mobile shown in the Eclipse New Project wizard in Figure 18.26. When you select this option, you’ll be enabling the creation of a new Cordova project. Thym doesn’t use the Cordova CLI to create projects; the new project capability is built into the plugin.
As you work through the New Project wizard, you’re prompted for Cordova-specific settings. Figure 18.27 shows the settings for the Cordova application name and application ID.
Next, you’ll be asked to select the hybrid framework version to use for this project as shown in Figure 18.28. You should be able to use PhoneGap and other distributions here as well. Simply click the Download button to install a new framework version.
Once the wizard finishes, Eclipse will open the new hybrid project as shown in Figure 18.29. In this figure, the project’s config.xml file is open in the configuration editor; this isolates you from having to edit the configuration file in XML format.
Notice the project structure in the navigator on the left side of the figure. This looks like the standard Cordova project folder structure, only the config.xml is in a different place. The platforms folder is missing as well, but that is taken care of by the plugin at runtime.
Thym adds some new run options to Eclipse as shown in Figure 18.30. Since this screen shot was taken on a Windows system, only Android options are shown. On OS X, you would see options for running on iOS devices and simulators as well.
Thym is brand-new and still has a long way to go, but it’s a good starting point for providing the Eclipse IDE with hybrid development capabilities.
For some web development projects, there are tasks that must be performed as part of the build step that happens before deployment. Those tasks may include optimizing image files, minimizing or merging source code files, and even compiling code. The tools used to help perform these types of tasks are called build tools.
If, for example, you coded a web application’s logic using something like CoffeeScript (http://coffeescript.org/) or Dart (www.dartlang.org), the code would need to be compiled into JavaScript before the application could be deployed. If you’d crafted a web application’s CSS using Less (http://lesscss.org/) or Sass (http://sass-lang.com/), you would need to compile the code into CSS for deployment.
There is a plethora of free build tools available; for example, the Android Developer Tools use either Ant or Gradle, depending on the IDE you use. As Cordova uses JavaScript and Node, there are several Node-based build tools available as well. One of the most popular is Grunt JS (http://gruntjs.com/), along with other options such as Gulp (http://gulpjs.com/) and Brunch (http://brunch.io/).
In this section, I’ll show how to use Gulp and Grunt to automate some of the build tasks associated with Cordova development projects.
Gulp (http://gulpjs.com/) was created by developers who thought Grunt was too complicated, and I agree with them. It’s a stream-based build system that gains performance enhancements by having the results of one operation streamed directly to the next step in the process instead of having to make an intermediate trip to disk.
Gulp projects are coded in JavaScript and Gulp, and its plugins can all be installed using Node. To use Gulp, you create a file called gulpfile.js in your project’s root folder, then add JavaScript code to the file to perform specific build tasks. Let me show you how this works.
First, install Gulp by opening a terminal window and issuing the following command:
npm install –g gulp
On OS X or Linux, you may have to run the command using this:
sudo npm install –g gulp
Now all you have to do is populate the gulpfile.js with the code to perform the appropriate tasks for your project. At a minimum, the gulp file, gulpfile.js, needs to include the following:
var gulp = require('gulp'),
gulp.task('default', function() {
// place code for your default task here
});
Anything Gulp does is coded using JavaScript inside of that gulp.task
method.
Now let me give you an example of how I use Gulp in a Cordova project. When I build a Cordova application, there are a few things I want to do to my code before I put it into production. First, I want to minimize all of the source code (HTML, JavaScript, and CSS) so it’s smaller and loads faster in the container. Additionally, if I have any image files, I want to optimize them for mobile, reducing either the size or the quality of the images so they load quickly and render correctly on a mobile device. I may even want to concatenate my application’s JavaScript files into a single, minified file. These are all tasks I can perform using Gulp.
Now, in order to do this, I can’t code my application in the Cordova project’s www folder as the Cordova CLI will expect to find all of its files there. What I want is to code in a different folder location, then use Gulp to process the files and copy them into the www folder before passing control over to the Cordova CLI to do its stuff.
So, what I did was added a folder called code to my Cordova application project folder structure, then placed my web application’s files there. Then I created the gulp file shown in Listing 18.1 to preprocess the files and copy the results into the project’s www folder.
// include gulp
var gulp = require('gulp'),
var shell = require('gulp-shell'),
// include plug-ins
var jshint = require('gulp-jshint'),
var changed = require('gulp-changed'),
var imagemin = require('gulp-imagemin'),
var minifyHTML = require('gulp-minify-html'),
var concat = require('gulp-concat'),
//Uncomment the following line before going to production
//var stripDebug = require('gulp-strip-debug'),
var uglify = require('gulp-uglify'),
var autoprefix = require('gulp-autoprefixer'),
var minifyCSS = require('gulp-minify-css'),
// JS hint task
gulp.task('jshint', function () {
gulp.src('./code/js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
// minify new images
gulp.task('imagemin', function () {
var imgSrc = './code/img/**/*',
imgDst = './www/img';
gulp.src(imgSrc)
.pipe(changed(imgDst))
.pipe(imagemin())
.pipe(gulp.dest(imgDst));
});
// minify new or changed HTML pages
gulp.task('htmlpage', function () {
var htmlSrc = './code/*.html',
htmlDst = './www';
gulp.src(htmlSrc)
.pipe(changed(htmlDst))
.pipe(minifyHTML())
.pipe(gulp.dest(htmlDst));
});
// JS concat, strip debugging and minify
gulp.task('scripts', function () {
gulp.src(['./code/js/index.js', './code/js/*.js'])
.pipe(concat('script.js'))
//Uncomment the following line before going to production
//.pipe(stripDebug())
.pipe(uglify())
.pipe(gulp.dest('./www/'));
});
// CSS concat, auto-prefix and minify
gulp.task('styles', function () {
gulp.src(['./code/css/*.css'])
.pipe(concat('styles.css'))
.pipe(autoprefix('last 2 versions'))
.pipe(minifyCSS())
.pipe(gulp.dest('./www/'));
});
gulp.task('prepare', shell.task(['ls', 'cordova prepare']));
// default gulp task
gulp.task('default', ['imagemin', 'htmlpage', 'scripts', 'styles',
'prepare'], function () {});
If you look at the code, you’ll notice that there are a bunch of modules that are required by the gulp file. These are Gulp plugins, and each one takes care of a specific step in the process. One option is to manually install each module using the following commands:
npm install gulp-autoprefixer
npm install gulp-changed
npm install gulp-concat
npm install gulp-imagemin
npm install gulp-jshint
npm install gulp-minify-css
npm install gulp-minify-html
npm install gulp-strip-debug
npm install gulp-uglify
The modules are installing locally; notice that I didn’t add the –g
flag to each command, as each project may have different requirements. To make this easier, I created a package.json file that contains all the required modules as shown in Listing 18.2.
{
"name": "gulpdemo",
"version": "1.0.0",
"description": "Cordova Gulp Demo",
"main": "gulpfile.js",
"dependencies": {
"gulp": "^3.8.10",
"gulp-autoprefixer": "^0.0.7",
"gulp-changed": "^0.3.0",
"gulp-concat": "^2.2.0",
"gulp-imagemin": "^0.5.0",
"gulp-jshint": "^1.6.0",
"gulp-minify-css": "^0.3.4",
"gulp-minify-html": "^0.1.3",
"gulp-shell": "^0.2.5",
"gulp-strip-debug": "^0.3.0",
"gulp-uglify": "^0.3.0"
},
"devDependencies": {},
"author": "John M. Wargo",
"license": "Apache"
}
Now, to use this in any project, I simply have to copy over my gulpfile.js and package.json files to the Cordova project folder, then create a folder called code, and I’m all set. Once the files are there, I can open a terminal window pointing to the folder and issue the following command:
npm install
This will automatically install all of the required Gulp plugin modules for me.
Now let’s dig into the code for Listing 18.1. If you look at the very bottom of the file, you’ll see the following code:
// default gulp task
gulp.task('default', ['imagemin', 'htmlpage', 'scripts', 'styles', 'prepare'],
function () {});
This defines the default task Gulp performs when you issue the gulp
command all by itself. In this example, the default process is performing the following steps:
1. Minimize image files.
2. Process HTML files.
3. Process JavaScript files.
4. Process CSS files.
5. Issue a cordova prepare
command.
If you take a look through the remainder of the file, you will see that a separate function is defined for each of these tasks. Let’s take a look at the code for processing JavaScript files:
// JS concat, strip debugging and minify
gulp.task('scripts', function () {
gulp.src(['./code/js/index.js', './code/js/*.js'])
.pipe(concat('script.js'))
//Uncomment the following line before going to production
//.pipe(stripDebug())
.pipe(uglify())
.pipe(gulp.dest('./www/'));
});
What this code does is process all of the .js files in the code/js folder, treating the index.js file as the primary file. Notice how all of the commands that follow begin with .pipe
; that’s because the results of one are piped into the next command in the list. So, for this example, the JavaScript files are first concatenated into a single file called script.js, then uglified (minified) and finally copied into the project’s www folder. All of that is done with one line of code.
Notice that I have the call to stripDebug
commented out; that particular function removes any code lines that call console.debug
, the thought being that those are there for debug purposes and should not be included in production code.
If you look through the remainder of the file, you’ll see that all of the functions are set up the same way, only processed a little differently depending on the type of file being processed.
You can have multiple tasks defined within a Gulp file; simply add additional commands the same way as the default option was added. To add a debug process that shrinks images but copies over the source files in their original format, unminified, I would add a debug option using
gulp.task('debug', ['imagemin', 'copyfiles', 'prepare'], function () {});
Then I would add a new function to the file called copyfiles that copied the files from code to www and I’d be all set. To invoke the command I would pass the command name to the gulp
command using
gulp debug
The gulp file issues a cordova prepare
when it’s done processing all of the files, so to use this as part of my development process, I simply had to have a terminal window open to the project folder and issue the following commands:
gulp
cordova run android
This will prepare all of the files, then run the application on either an Android device or Android emulator. You can replace the cordova run
command with whatever command is appropriate based on what it is you want to do. All I’m really showing is that I’ve replaced typing cordova prepare
with gulp
; otherwise the process remains the same.
Figure 18.31 shows Gulp in action, processing all of my application’s files.
There is, of course, much more you can do with Gulp; I’ve only touched the surface here, but I hope I’ve provided you with enough information to get started with the tool. There are a ton of plugins available, so you can likely find one that can perform most any task you want performed.
Grunt (http://gruntjs.com/) is a JavaScript-based build tool like Gulp. Grunt is more popular than Gulp, but mostly because it’s been around longer. Gulp is faster and easier to use, but Grunt has a wider following.
To install Grunt, open a terminal window and execute the following command:
npm install grunt-cli
On OS X or Linux, you may have to run the command using this:
sudo npm install –g grunt-cli
This installs the Grunt CLI; you’ll still need to install Grunt and any associated plugins in each project folder.
Using Grunt is just like using Gulp: you create a package.json file that includes all of your dependencies and use a gruntfile.js file to execute all of your project’s Grunt commands. For this example, I created the simple gruntfile.js shown in Listing 18.3. It performs three actions on a project’s source code files: minimizes the application’s HTML files, minimizes the application’s JavaScript files, and optimizes the application’s image files.
module.exports = function (grunt) {
grunt.initConfig({
//Process JavaScript files
uglify: {
jsFiles: {
files: [{
expand: true,
cwd: 'code',
src: '**/*.js',
dest: 'www'
}]
}
},
//Process HTML files
htmlmin: {
htmlFiles: {
options: {
removeComments: true,
collapseWhitespace: true
},
files: [{
expand: true,
cwd: 'code',
src: '**/*.html',
dest: 'www'
}]
}
},
//Process Image files
imagemin: {
imgFiles: {
files: [{
expand: true,
cwd: 'code/img',
src: ['**/*.{png,jpg,gif}'],
dest: 'www/img'
}]
}
}
});
//Load the needed grunt modules
//Minifies JavaScript files
grunt.loadNpmTasks('grunt-contrib-uglify'),
//Minifies HTML files
grunt.loadNpmTasks('grunt-contrib-htmlmin'),
//optimizes image files
grunt.loadNpmTasks('grunt-contrib-imagemin'),
// Default task(s).
grunt.registerTask('default', ['uglify', 'htmlmin', 'imagemin']);
grunt.registerTask('js', ['uglify']);
grunt.registerTask('html', ['htmlmin']);
};
As with the Gulp example, the gruntfile.js defines the default task:
grunt.registerTask('default', ['uglify', 'htmlmin', 'imagemin']);
When grunt
is executed without any additional parameters, this is the task that will execute.
To use this for your projects, copy the gruntfile.js and package.json file (shown in Listing 18.4) to your Cordova project folder, create a folder called code, and populate the folder with your application’s code. To install the required modules, open a terminal window, navigate to the Cordova project folder, and issue the following command:
npm install
With the modules installed, to execute the default Grunt process, issue the following command:
grunt
{
"name": "gruntdemo",
"version": "1.0.0",
"description": "Cordova Grunt Demo",
"main": "gruntfile.js",
"author": "John M. Wargo",
"license": "Apache",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-htmlmin": "^0.3.0",
"grunt-contrib-imagemin": "^0.9.2",
"grunt-contrib-uglify": "^0.6.0"
}
}
That’s all there is to it. Grunt will minify the HTML and JavaScript files, then process any image files. Figure 18.32 shows the default grunt
command in action. In this example, a single JavaScript file was processed, the index.html was compressed from 522 bytes to 453 bytes, and no image files were processed (because my project doesn’t have any).
I’ve also defined some additional tasks in the gruntfile.js, such as
grunt.registerTask('js', ['uglify']);
This task only processes the application’s JavaScript files and can be executed using the following command:
grunt js
There is, of course, much more you can do with Grunt; I’ve only touched the surface here, but I hope I’ve provided you with enough information to get started with the tool. There are a ton of plugins available, so you can likely find one that can perform most any task you want performed.
In this chapter, I covered different third-party tools you can use to simplify your Cordova development efforts. In some cases, they are tools I use myself, so I find them to be particularly useful. For others, what you learned about here were tools that I’m interested in but never really got a chance to play with (until now).
That’s all there is for this book; I’m out of space (I exceeded the publisher’s length estimate by about 100 pages) and I’m out of time (the manuscript is due tomorrow). I hope you enjoyed this book!
35.170.81.33