Mobile Webapps

Matteo Antony Mistretta

Let's get serious

  • Client
  • Server
  • Both (isomorphic)
  • Native (universal apps)
  • Embedded (Johnny-Five) 

Node

Single-threaded, event-driven, scalable

var http = require('http');

var server = http.createServer(function (req, res) {
  res.end('<html><body><h1>Hello world!</h1></body></html>');
});

server.on('/about', function(req, res) {
  if (req.method === 'GET') {
    res.writeHead(200, {'Content-Type': 'text/plain'});

    res.write('We are young');
    res.write('We are strong');
    res.write('We’re not looking for where we belong');
    res.end();
  }
});

server.listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');

NPM

npm init

npm install --save lodash
npm install --save-dev uglifyjs

npm update --save
npm update --save-dev

npm install -g coffee-script
npm list -g --depth=0

npm install
npm test
npm start
npm run uglify
var _ = require('lodash');

function weightedAverage(marks, weights) {
  var squares = _.map(marks, function(mark, index) { return mark * weights[index] });
  var weightedAvg = _.reduce(squares, function(prev, curr) { return prev + curr });
  return weightedAvg / _.reduce(weights, function(prev, curr) { return prev + curr });
}

module.exports = { weightedAverage: weightedAverage };

Bower

bower init

bower install --save jquery
bower install --save git://github.com/user/package.git
bower install --save http://example.com/script.js

bower update --save

bower install
<!DOCTYPE html>
<html>
<head>
  <script src="/lib/jquery.min.js"></script>
  <script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
  <script src="/bower_components/jquery/dist/jquery.min.js"></script>
</head>

<body>
  <div id="app">
    <p>Awesome!</p>
  </div>
</body>
</html>

Express

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.post('/', function (req, res) {
  res.send('Got a POST request');
});

// middlewares
app.use(express.static(__dirname + '/bower_components'));
app.use(express.static(__dirname + '/public'));

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Preprocessors

Because JavaScript just isn't enough for us

Reasons to learn them

  • Sugar syntax
  • More power
  • Live the future
  • Keep up the pace

TypeScript

/// <reference path="phaser.d.ts" />

window.onload = function() {
  var game: Phaser.Game,
    platforms: Phaser.Group,
    player: Phaser.Sprite,
    cursors: Phaser.CursorKeys,
    score: number,
    scoreText: Phaser.Text;

  game = new Phaser.Game(
    800, 600, Phaser.AUTO, '',
    {
      preload: preload,
      create: create,
      update: update
    }
  );

  function preload() { }
  function create() { }
  function update() { }
};
/// <reference path="phaser.d.ts" />

window.onload = function() {
    var game, platforms, player,
        cursors, score, scoreText;

    game = new Phaser.Game(
      800, 600, Phaser.AUTO, '',
      {
        preload: preload,
        create: create,
        update: update
      }
    );

    function preload() { }
    function create() { }
    function update() { }
};

ES6

const {Object3D, Material} = Core;

class Mesh extends Object3D {
  constructor(
    geometry = new Geometry(),
    material = new Material({
      color: 0xffffff
    })
  ) {
    super();

    this.geometry = geometry;
    this.material = material;

    this.updateMorphTargets();
  }
}
... you don't want to know.

Module systems

Let's try to avoid global namespace pollution

Namespace pattern

AKA "One namespace to rule them all"

//------ lib.js ------
(function(root) {
  (function(app) {
    var myPrivateVar;

    function MyModule() {
      ...
    }

    root.app.MyModule = MyModule;
  })(root.MyApp || (root.MyApp || {}));
})(MyCompany || (MyCompany = {}));

//------ main.js ------
(function() {
  var lib = new MyCompany.MyApp.MyModule();
})();

CommonJS

//------ lib.js ------
var math = require('awesome-math-library');

var square = function(x) {
  return x * x;
};

module.exports = {
  diag: function(x, y) {
    return math.sqrt(square(x) + square(y));
  }
};

//------ main.js ------
var lib = require('./lib');

console.log(lib.diag(4, 3)); // 5

The Node/NPM way

AMD

//------ lib.js ------
define(['awesome-math-library'], function(math) {
  var square = function(x) { return x * x; };
  return {
    diag: function(x, y) {
      return math.sqrt(square(x) + square(y));
    }
  };
});

//------ main.js ------
requirejs.config({
  baseUrl: 'scripts',
  paths: {
    'awesome-math-library': '../vendor/math.min'
  },
  shims: { 'backbone': { deps: ['underscore'], exports: 'Backbone' } }
});

define(['./lib'], function(lib) {
  console.log(lib.diag(4, 3)); // 5
});

 Kindly brought to you by RequireJS

UMD

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['dep1', 'dep2'], factory);
  }

  else if (typeof module === 'object' && module.exports) {
    module.exports = factory(require('dep1'), require('dep2'));
  }

  else {
    root.MyGlobalModule = factory(root.GlobalDep1, root.globalDep2);
  }
}(this, function(Dep1, dep2) {
  return {
    combine: function() {
      return new Dep1().awesomeFunc(dep2);
    }
  };
}));

Be friends with everyone :)

ES6 imports

// lib.js

import {obj1, obj2} from 'dep1';
import dep2 from 'dep2';

export const PI = 3.14;

export function square(x) {
  return x * x;
}

export default MyLib = {
  hello: 'world'
}

// main.js

import {PI, square}, MyLib from 'lib';

Peace, at last.

War is not over yet

Automation Tools

Repetitive tasks belong to machines

Build: Gulp

Build: Grunt

Scaffolding: Yeoman

Tests

Frameworks

Backbone

MVC? MVVM!

AngularJS

A quick recap

angular.module('todosApp', ['ngRoute', 'todosCtrl','todosFlt', 'todosSvc']);

var todosCtl = angular.module('todosCtl', []);
todosCtl.controller('TodoListCtl', ['$scope', 'Todo', function($scope, Todo) {
  $scope.todos = Todos.query();
  $scope.orderProp = 'age';
}]);

var todosSvc = angular.module('todosSvc', ['ngResource']);
todosSvc.factory('Todo', ['$resource', function($resource){
  return $resource('todos/:id.json', {}, {
    query: {method:'GET', params: {id: 'todos'}, isArray:true}
  });
}]);
<ul ng-controller="TodoListCtl">
  <li ng-repeat="todo in todos | orderBy:orderProp">
    <input type="checkbox" ng-model="todo.completed">
    <label ng-class="{completed: todo.completed}">{{todo.title}}</label>
    <button class="destroy" ng-click="removeTodo(todo)"></button>
  </li>
</ul>

Angular2 (1/2)

The future is now. Welcome to Java 5

export class Todo {
  completed: Boolean;
  private _title: String;

  get title() { return this._title; }
  set title(value: String) { this._title = value.trim(); }

  constructor(title: String) { this.completed = false; this.title = title; }
}

import {Component} from 'angular2/core';
import {TodoStore, Todo} from './services/store';

@Component({
  selector: 'todo-app',
  templateUrl: 'app/app.html'
})
export default class TodoApp {
  todoStore: TodoStore;

  constructor(todoStore: TodoStore) { this.todoStore = todoStore; }

  remove(todo: Todo) { this.todoStore.remove(todo); }
}

Angular2 (2/2)

"Wow, it's so readable!" - Perl developer

<ul class="todo-list">
  <li *ngFor="#todo of todoStore.todos"
      [class.completed]="todo.completed">

    <input type="checkbox"
        (click)="toggleCompletion(todo)"
        [checked]="todo.completed">

    <label>{{todo.title}}</label>

    <button (click)="remove(todo)"></button>
  </li>
</ul>
<input [(ngModel)]="todo.title">
import {bootstrap} from 'angular2/platform/browser';
import TodoApp from './app'
import {TodoStore} from './services/store';

bootstrap(TodoApp, [TodoStore]);

React

Declarative, reactive, functional, performant

var KnockKnock = React.createClass({
  // mixins: [StopUsingMe],
  getInitialState: function() { return { sound: this.props.sound } },
  render: function() { return <div>{this.props.sound} {this.state.sound}</div> }
});

class Hello extends React.Component { // v0.14
  constructor(props) {
    super(props);
    this.state = { who: props.who };
  }
  render() { return <div>{this.props.greeting} {this.state.who}</div> }
}

const Goodbye = ({words}) => {
  return <ul>{words.map(word => <li key={word}>{word}</li>)}</ul>
}

ReactDOM.render(
  <div>
    <KnockKnock sound={'knock'} />
    <Hello greeting={'hello'} who={'world'} />
    <Goodbye words={['goodbye', 'cruel', 'world']} />
  </div>,
  document.getElementById('container'))

Flux Architecture: Redux

It's 'state machines', not 'transition machines'

react-redux

Your personal time machine

  • Presentational/Container components
  • Decorator vs. Mixins
  • connect, Provider

Performance tips

KISS

Rules of optimization

Coding Tricks

  • Write JavaScript-y code
  • Use local variables, avoid globals
  • Attach methods to prototype
  • Use immutability
  • Minimize DOM touches
  • Minimize APIs server-side
  • Don't reinvent the wheel
  • DRY
  • Prefer readability over performance

Google PageSpeed Rules

Travel Light

  • Is SPA necessary?
  • Are all browsers necessary?
  • Is all JS necessary?
  • Is all CSS necessary?
  • Are all those HTTP requests necessary?
  • Is client-only necessary?

Thank you!

Matteo Antony Mistretta

Github: IceOnFire, IngloriousCoderz

LinkedIn: antonymistretta

Twitter: antonymistretta

Email: antony.mistretta@gmail.com

Mobile webapps

By Matteo Antony Mistretta

Mobile webapps

  • 576