The Official Ionic Blog

Build amazing native and progressive web apps with HTML5

Jonathan Grupp is a software engineer at M-Way Solutions, the owner and maintainer of Generator-M-Ionic, and a frequent contributor to Ionic. He has written a three-part series on advanced workflows for building rock-solid Ionic apps. This is Part 2.

blog-02

In the second part of our series on developing enterprise-level Ionic apps, you’ll be learning about wonderful ingredients like testing, sub-generators, plugins, and ecosystem integration into the Ionic Platform. We are building on top of the project we created in Part 1 of this series. Time to climb the development mountain!

Quality assurance

You’ve set up your project, created your first commit, and are now ready to start coding. Whether you are coding alone or in a team, as a developer worried about professional development, you’ll want to take some measures to ensure the quality of your code. We’ve got you covered on this one!

Linting

Your Generator-M-Ionic project comes with established coding guidelines and workflows already baked in using ESLint. On every iteration of gulp watch, Gulp will check all your application JavaScript files for guideline violations.

eslint

To additionally get linting notifications as you develop in your editor or to learn how to configure the default set of rules, check out our ESLint Guide. If you are working with JSON files in your app/ folder -for instance to handle translations- the generator’s linting will validate those too! This keeps your development trouble free.

Testing

Another area where you just don’t have to deal with the hassle of setting up and configuring everything yourself is unit testing with karma and end-to-end testing with protractor. Your sample app even comes with a ready-to-use test-suite that you can try out right now by running:

gulp karma
# and
gulp protractor

The relevant files for the test setup are these:

test/
  └── karma/
  └── protractor/
karma.conf.js
protractor.conf.js

Our Testing Guide can help you get started with writing your own unit and end-to-end tests for your app. Once you have that mastered, the Husky Hooks Guide explains how you can run linting and tests automatically before you git commit or git push.

Coding

Ok, ok, enough already! You want to finally start coding and develop your very own app? Say no more. You’ll probably want to:
– add your own Angular components using our subgenerators
– controllers, templates, directives, services, filters, constants, … or even whole modules
– add some Sass to spice up your app’s styling
– add Cordova Plugins to use with ngCordova for that real app-feeling
– and maybe add some additional bower packages for special tasks

We will go through each of these tasks briefly to give you a general idea of how things work. For more detailed explanations, visit our Documentation.

Adding Angular components

Our array of subgenerators allows you to create the most important Angular components very easily. If applicable, they also generate sample test files so you can start testing right away.

For instance, we use the pair-subgenerator a lot. It creates a controller, with a test file and a template with the same name.

yo m-ionic:pair phone

sub_generator

Now, we only need to add a state to the main.js:

.state('main.phone', {
  url: '/phone',
  views: {
    'tab-phone': {
      templateUrl: 'main/templates/phone.html',
      controller: 'PhoneCtrl as ctrl'
    }
  }
})

Then add a navigation item in our tabs.html file, which you’ll find in app/main/templates/, to bring it all together:

<!-- List Tab -->
<ion-tab title="Phone" icon-off="ion-ios-telephone-outline"
  icon-on="ion-ios-telephone"
  ui-sref="main.phone">
  <ion-nav-view name="tab-phone"></ion-nav-view>
</ion-tab>

That’s it. A new navigation item, a new route, controller, test file, and template in about two minutes. Here’s the result:

nav_phone

Adding Sass

This is an even easier task. Every module you generate comes with a default Sass file. For your main module, this would be main.scss, and it’s located in app/main/styles/. Open it and add some Sass:

ion-list {
  ion-item {
    color:red;
  }
}

Upon saving, your gulp watch task will automatically compile and inject the resulting CSS, even reload your browser. Not sassy enough? As your project grows larger, you may want to split your Sass into multiple files. Find out how in our Sass integration Guide.

Adding plugins

We’ve got to add some nice Cordova Plugins to our app, to make it a real hybrid app. Let’s do it!

Your project comes with a local installation of the latest version of the Cordova CLI, which you can invoke through Gulp. We install it locally, so you don’t have to worry about which project you set up with which version. It’s always the one it got set up with. The syntax is almost exactly the same as using a global CLI installation. To install the Cordova camera plugin, run:

gulp --cordova "plugin add cordova-plugin-camera --save"

You want to develop for Windows, as well? Install the appropriate Cordova Platform requirements and type:

gulp --cordova "platform add windows --save"

Don’t forget to call --save, in order to persist new plugins and platforms in the config.xml! Our Development Introduction has a dedicated part on using the Cordova CLI wrapper.

Now that we’ve installed a new plugin, we want to use it! ngCordova is declared as a dependency for every module you create using the generator, so you can just start using the plugins right away. Refer to the main module declaration in your main.js to see how it’s done. So in my PhoneCtrl, I’ll only have to inject the $cordovaCamera service in order to access the plugin:

angular.module('main')
.controller('PhoneCtrl', function ($cordovaCamera) {

  var options = {
    destinationType: Camera.DestinationType.FILE_URI,
    sourceType: Camera.PictureSourceType.CAMERA,
  };

  $cordovaCamera.getPicture(options)
  .then(function(imageURI) {
    console.log(imageURI);
  });
});

Adding new plugins has never been so simple!

In some cases, you need to extend your ESLint configuration because some plugins expose JavaScript globals that you might want to use (like Camera in the example above). Or you might prefer to access your plugins through the cordova global, because ngCordova is not always up to date with the latest plugin versions or may not support the plugin you want to use. In order to use those globals without ESLint complaining, augment the globals section of your app/.eslintrc:

//..
"globals": {
  "angular": true,
  "ionic": true,
  "localforage": true,
  // add those
  "cordova": true,
  "Camera": true
},
//..

Bower packages

And last but not least, you’ll probably want some more bower packages that go with your app. Maybe your app needs to support different languages. You can use angular-translate for that. Install it by running:

bower install angular-translate --save

The --save flag will persist that package in the bower.json. Sometimes, for all changes to take effect, it is necessary to restart gulp watch. Then, the only thing left to do is to mark the module as a dependency in your main.js module declaration:

'use strict';
angular.module('main', [
  'ionic',
  'ngCordova',
  'ui.router',
  // add this one
  'pascalprecht.translate'
])

Translations? You’ve got them now! Refer to the documentation to learn more.

Browser or device?

Up until now, we’ve only seen our app in the browser using gulp watch. But at least when you’re working with plugins, you may want to test your app on a device or emulator. If you have your system correctly set up according to the Cordova Platform Guides, this should be easy:

  1. connect your device to your machine
  2. make sure they’re both on the same network
  3. start the livereload command and keep it running:
# run on a connected device with livereload
gulp --livereload "run ios"
# run on an emulator with livereload
gulp --livereload "run --emulate android"

The best part about using livereload is that you can make changes to your code and see the changes immediately on the device. If you make changes to the Cordova files (config.xml, Platforms, Plugins) you’ll have to run the command again.

Your app is ready to be tested on your device!

device

If you don’t want to rely on your development machine to keep the livereload command running, you can run a full build of your app, which is then pushed onto your device.

gulp --cordova "run ios"
# or
gulp --cordova "run android"

Two things happen when you run this command:

  1. Gulp will build your app using gulp build
    • this takes care of all the JavaScript, HTML and CSS and puts it into the www/ folder
  2. Gulp will call Cordova with the supplied attributes and
    • takes the contents of the www/ folder and builds a Cordova app from it
    • the app is then pushed onto your device

The implicit run of gulp build, for which Cordova commands it will run as well as build options like minification, are explained in our Development Introduction in more detail.

gulp watch-build

Usually, gulp build will build your app without any problems, and everything should work just as if you run gulp watch. However, sometimes it will be necessary to debug the web app part of your build. Since this is a little cumbersome to do when the app’s already on your device, there’s a nice intermediate step:

gulp watch-build

This is just like gulp watch, but only for the www/ folder. It builds your app into that folder and then opens a browser window showing the built version of your app. This allows you do quickly find out why your app doesn’t build properly. Adding the --no-build flag enables you to watch the current version in the www/ folder. Of course, this command also works with --no-open and all the other flags that work with gulp watch, as well.

Ecosystems

There are some things you just don’t want to build yourself every time, like push services, user management, or other backend services. Luckily, the Ionic Platform can be integrated into your project using the Ionic CLI, as described in the Ionic Platform Integration Guide.

Congratulations!

You’ve learned how to season your app with spices like sub-generators, Sass, plugins, ecosystems, and bower packages. In Part 3 of this series, you’ll take your development skills to out-of-this-world levels by owning environments, proxies, and build tools; and handling app icons, splash screens, continuous integration and build variables.

Get in touch

Feedback, ideas, comments regarding this blog post or any of the features discussed here are very welcome in either the comments section below, at our Generator-M-Ionic’s Github repository or the Generator-M-Ionic Gitter Chat.

Credits

Author: Jonathan Grupp
Headline illustrations: Christian Kahl
Special thanks to Volker Hahn, Mathias Maier, and Tim Lancina

  • http://www.marcoturi.it Marco

    “yo m-ionic:pair phone” I stopped reading at this point, the file structure is vary bad. You should avoid using a single folder for all controllers, you should avoid putting all your routes in a single file, the same for tests, and so on. Specially in an enterprise app.

    I’m working for a big ecommerce company in my country and we used this file structure inspired by Jhon Papa, Todd Motto and Martin Micunda:

    https://github.com/marcoturi/ionic-es6-boilerplate

    • Jonathan Grupp

      Hi Marco, I agree the file-structure is not ideal! It originates back before John Papa’s and Todd Moto’s guides became popular. However a multi-module structure can have it’s percs and is not as bad as you say and we have a variety of complex apps with nice architectures based on it.
      We’ve been thinking to update the project structure for quite a while, but as many people already rely on it, we don’t want make any hasty changes or ruin upgrade paths. Additionally up until now we always saw our time better invested in many of the features that are part of this series. So maybe you can give it a try and keep on reading 🙂

      • http://matheo.co Mateo Tibaquirá Palacios

        Its weird to keep a faulty project structure. In the migration to Angular 2 / Ionic 2 people will have to stop thinking on update it and do it, because that’s not maintainable on non-small setups.
        Nice work there, but legacy stuff gotta go soon to get acceptation and success. Keep it up

  • Jeff

    I had to use:
    gulp –cordova “plugin add cordova-plugin-camera –save”

    cordova -v
    6.2.0

    Your notation is from cordova 4.x.

    • Jonathan Grupp

      Hi Jeff. You’re absolutely right. I think I copied this command from our docs, which apparently I forgot to update since the cordova registry was deprecated. Sorry for the slip up. I’ll try to get this corrected.