Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintaining a PhoneGap Hybrid/Web App Codebase

I'm investigating the complexity involved in maintaining a cross-platform (web, ios, android) phonegap codebase that allows for platform specific code (and assets/tests) as simply as possible.

The current best approach I'm taking is to use grunt to build the code of a typical web app, and then use the grunt-phonegap module to generate the respective phonegap projects.

I'm confident this will work, however for my phonegap projects, I know I'm going to need to make use of some specially written plugins to make use of some device capabilities (these aren't typical cordova plugins)

I'm wondering if anyone has figured out an approach for maintaining a codebase that can adapt to different platforms and requirements. Javascript has no #IF_DEF functionality, but would it be possible to implement something like that using grunt?

like image 308
Kraig Walker Avatar asked May 12 '14 09:05

Kraig Walker


2 Answers

I recently had the same question myself. I couldn't really find much online regarding this so I decided to deep dive into Grunt, Node, and Git.

Grunt and Node

In the root folder of my Cordova projects (alongside the www, platforms, merges, and plugins folders) I have a grunt project. I store modular JavaScript files and CSS files that may or may not be platform dependent inside a src folder inside the root of the Cordova project. This grunt project builds the JavaScript and CSS stored in the src folder and places the resulting files into the www or merges folder as appropriate.

I even wrote a grunt task that will make a production build of the app by optimizing and minifying css, javascript, and html templates, then rebuilds the Cordova platform projects to include these production files.

Because there is no #IF_DEF in JavaScript, I have to use Grunt (mentioned above) to build out the JavaScript for each platform. I modularize almost all of the JavaScript functions by platform. If there are no platform differences for that function (no native hooks), I only need one file. If there are differences, I need to create a separate file for each platform for that function. For example, my Cordova onDeviceReady and onResume function usually differ from platform to platform. I create files called

CordovaEvents-ios.js and CordovaEvents-android.js

Inside the package.json file, I describe the "features" I want in my app. CordovaEvents is an example of a feature.

I also support "arguments". I use the same approach above in the file names of the modular files. An argument could look like this

CordovaEvents-ios--production.js and CordovaEvents-android--production.js

In this case the code needed in a production app will differ from non production code. I can simply pass this argument (or list of arguments) during the build process, and the correct files will be picked up and built. I think this most closely addresses your question if there is an approach to maintaining a codebase that can adapt to different platforms and requirements. The requirements are the feature names and arguments. The argument can be anything you want, maybe using one plugin or another plugin.

I also describe the platforms I want to support ("iOS", "Android", and "Desktop"). Grunt processes each platform in a MultiTask, and then looks at the features I want to support. It will try to find a file called feature-platform.js. If it cannot find this file, it will just try to look for feature.js. After I concatenate all the functions together needed for the platform, it will copy the file over to the merges folder for iOS or Android. Typically all the files kept in the WWW folder in the root project will work on a desktop because there are no native Cordova hooks... this allows me to debug in Chrome. All the files that contain native hooks are stored in the merges folder. Once the Cordova project is built for the respective platform, the code can be tested in a device simulator.

If you are new to Grunt I would strongly suggest taking a look a their getting started guide.

http://gruntjs.com/getting-started

Git

I also employed Git to version my code. I used SourceTree to create the Git repository in the root folder of my Cordova project, and have a remote repository on my Mac Mini server that I can push my commits too. This allows us to have a backup copy of the code, and makes it so my team can also work on the code out-of-band.

I Git ignore the following folders:

  • node_modules
  • plugins
  • platforms
  • plugins

All the other files and folders contained in the root directory of my Cordova project are versioned. I used the following link as a reference to help define my Git strategy for Cordova:

https://leanpub.com/developingwithcordovacli/read#version-control

It didn't take me overnight to figure all this stuff out, in fact it took a little bit more than two months. I hope my answer can server as a guide to you and others to address your concerns you mentioned in your opening post.

like image 156
njtman Avatar answered Oct 26 '22 22:10

njtman


I am using gruntjs, javascript, jade, bower, and phonegap to build hybrid web applications and phonegap mobile applications. After some investigation, I settled on to use jade template language for creating my html and javascript files. This is my setup.

//begin grunt module
module.exports = function(grunt) {
var $jadeConfigObject = {
          compileDevelopment: {
            options: {
              pretty: true,
              data: {
                debug: true,
                **phonegap : '<%= isPhonegapBuild %>'**
              }
            },

            files: [{
              expand: true,
              cwd : "src",
              src: "**/*.jade",
              ext: ".html",
              dest:"dist/development/www/"

            }]
          }
    };

grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    clean: [$dist_folder,"www"],
    jade: $jadeConfigObject
     // other gruntjs tasks
  })


grunt.registerTask('setPhonegap', 'Set Phonegap related values.', function(n) {
  **grunt.config.set('isPhonegapBuild', true);**
});
 grunt.registerTask('buildPhonegap', ['setPhonegap','buildDevelopment'
,'copy:phonegap_www']);

}

Now explanation

Use gruntjs setPhonegap task to distinguish between phonegap build and normal web application build. Task setPhonegap set isPhonegapBuild config property, this property, in turn, is used by jade config object. Then I can use "if phonegap" statements in jade files.

I have following line in my jade layout file

include ../includes/mainJavascript.jade

mainJavascript.jade

if phonegap
  script(type='text/javascript',src='#{mainFolder}/cordova.js')
  script(type='text/javascript',src='#{mainFolder}/cordova_plugins.js')
  script(type='text/javascript',src='#{mainFolder}/plugins/org.apache.cordova.device/www/device.js')
  script(type='text/javascript',src='#{javascriptServicesFolder}/pushTokenService.js')
  script(type='text/javascript',src='#{javascriptFolder}/plugins/com.phonegap.plugins.PushPlugin/www/PushNotification.js')
  script(type='text/javascript',src='#{javascriptFolder}/phonegap/pushNotificationHelper.js')

This way I have following features

  • My web application does not contain any phonegap related scripts or html
  • I can use jade layouts (Master Page) to simplify my files very easily.
  • Adding new javascript to every page or changing every html for every page in application very easy.

Note that phonegap wants www folder for its build scripts, therefore I create following directory structure.

src -- every code file here, jade, javascript
www -- only created for phonegap build
dist/development/www -- normal development www build
dist/production/www -- production www build

I ignore www/* and dist/* in my source control. I only work with src jade and javascript files. Add this setup to bower, I believe it is a good option.

like image 29
Atilla Ozgur Avatar answered Oct 26 '22 22:10

Atilla Ozgur