hybrid-mobile-app-meetup



hybrid-mobile-app-meetup

0 0


hybrid-mobile-app-meetup

Slides for my talk at the hybrid mobile app meetup, Berlin

On Github tmaximini / hybrid-mobile-app-meetup

Effective Ionic workflow with gulp.js

Me

Thomas Maximini @tmaximini
Web Developer
App Developer

Trivia

Started App development after last meetup
First Techy Talk
Before: Angular.js
- little life goals 'present at a meetup'
- easy to learn, difficult to master

Rapid Prototyping

Iterative Development
Show something to client / team asap
Rapid - eliminate as much overhead as possible

Automation

Linting
Pre-compiling
Live Reloading
Emulating
Deploying
Any recurring task, really
- 2012 - revolution in front end development - who used / uses it? - who feels comfortable writing tasks in it? (or just copy pasting recipes?)

Grunt example

    
module.exports = function(grunt) {

  grunt.initConfig({
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['scripts/*.js'],
        dest: '<%= distFolder %>/main.js'
      },
      deploy: {
        src:['deploy/*.js'],
        dest:'deploy.js'
      }
  }});


  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('build', ['concat']);
};

    
- 2014 - adopted quickly - who used / uses it? - who feels comfortable writing tasks in it? (nearly everyone who uses it)

Gulp 101

  • npm package, install globally (and locally)
  • streams w/ virtual file format (vinyl-fs)
  • tasks: .src(), .pipe(), .dest()
// general pattern
gulp.task('scripts', function() {
    gulp.src('app/scripts/**/*.js')
        .pipe(anyGulpPlugin())
        .pipe(gulp.dest('dist/scripts'))
        .on('error', errorHandlerFunc);
});

Globs

  • 'scripts/**/*.js'
  • 'images/**/*.{jpg,png,gif}'
  • ['app.js', '**/*.js', 'some/other/path/*.js']

Gulp 101

    
        // gulpfile.js
        var gulp = require('gulp');

        // lots of plugins
        var concat = require('gulp-concat');
        var uglify = require('gulp-uglify');
        //...

        // or load all 'gulp-*' packages into plugins object
        var plugins = require('gulp-load-plugins')();

        // any npm package
        var path = require('path');

        // define tasks
        // example: copy images
        gulp.task('images', function() {
          return gulp.src('app/images/**/*.*')
            .pipe(gulp.dest(path.join('dist', 'images')))
        });

        // ... call this task via 'gulp images'
    
basic gulpfile.js example

Gulp Example: Scripts

    
        gulp.task('scripts', function() {
          gulp.src(['app.js', '**/*.js'], { cwd: 'app/scripts' })
            .pipe(plugins.if(!build, plugins.changed(dest)))
            .pipe(plugins.if(build, plugins.ngAnnotate()))
            .pipe(plugins.if(stripDebug, plugins.stripDebug()))
            .pipe(plugins.if(build, plugins.concat('app.js')))
            .pipe(plugins.if(build, plugins.uglify()))
            .pipe(plugins.if(build && !emulate, plugins.rev()))

            .pipe(gulp.dest(dest))

            .on('error', errorHandler);
        });
    
advanced example, gulp-if

Gulp Example: Styles

// precompile .scss and concat with ionic.css
gulp.task('styles', function() {

  var options = build ? { style: 'compressed' } : { style: 'expanded' };

  var sassStream = plugins.rubySass('app/styles/main.scss', options)
      .pipe(plugins.autoprefixer('last 2 version'));

  var cssStream = gulp
    .src('bower_components/ionic/css/ionic.min.css');

  return streamqueue({ objectMode: true }, cssStream, sassStream)
    .pipe(plugins.concat('main.css'))
    .pipe(plugins.if(build, plugins.stripCssComments()))
    .pipe(plugins.if(build && !emulate, plugins.rev()))
    .pipe(gulp.dest(path.join(targetDir, 'styles')))
    .on('error', errorHandler);
});
advanced example, streams can be merged

Gulp Example: Inject

    
// inject the files in index.html
gulp.task('index', ['jsHint', 'scripts'], function() {

  // build has a '-versionnumber' suffix
  var cssNaming = 'styles/main*';

  // injects 'src' into index.html at position 'tag'
  var _inject = function(src, tag) {
    return plugins.inject(src, {
      starttag: '',
      read: false,
      addRootSlash: false
    });
  };

  // get all our javascript sources
  // in development mode, it's better to add each file seperately.
  // it makes debugging easier.
  var _getAllScriptSources = function() {
    var scriptStream = gulp.src(['scripts/app.js', 'scripts/**/*.js'], { cwd: targetDir });
    return streamqueue({ objectMode: true }, scriptStream);
  };

  return gulp.src('app/index.html')
    // inject css
    .pipe(_inject(gulp.src(cssNaming, { cwd: targetDir }), 'app-styles'))
    // inject vendor.js
    .pipe(_inject(gulp.src('vendor*.js', { cwd: targetDir }), 'vendor'))
    // inject app.js (build) or all js files indivually (dev)
    .pipe(plugins.if(build,
      _inject(gulp.src('scripts/app*.js', { cwd: targetDir }), 'app'),
      _inject(_getAllScriptSources(), 'app')
    ))

    .pipe(gulp.dest(targetDir))
    .on('error', errorHandler);
});

    

workflow summary

gulp
start local dev server in ./.tmp, start watchers, compile and inject
gulp -b (--build)
compile, concat, annotate, uglify, versionize into ./www
gulp -e (--emulate) <platform>
run build, then emulate in platform. livereload in ios.
gulp -r (--run) <platform>
run build, then deploy app to connected device.
gulp select
select which device / platform to emulate on. ios only.
gulp icon / splash / resources
generate icons / splash images / both
gulp ripple
start ripple emulator

App Structure

- why create own generator? - came into project with old generator and lots of problems, force builds, ... - created from previous angular best practices - curious to hear from experienced generator-ionic users what features they use

thanks

Questions?

Slides: thomasmaximini.com/hybrid-mobile-app-meetup/

Seed Project: github.com/tmaximini/ionic-gulp-seed

Yeoman Generator: github.com/tmaximini/generator-ionic-gulp

Blog Post: thomasmaximini.com/2015/02/10/speeding-up-ionic-app-development-with-gulp.html

Twitter: @tmaximini