Parallel Universe

Java Developer’s Guide to Front-End Development

Kito Mann (@kito99), Virtua, Inc.

Kito D. Mann (@kito99)

  • Principal Consultant at Virtua (http://virtua.tech)

  • Training, consulting, architecture, mentoring

    • JSF, Java EE, Polymer/Web Components, Angular

  • Official US PrimeFaces and PrimeNG partner

  • Author, JavaServer Faces in Action

  • Founder, JSF Central (http://www.jsfcentral.com)

Kito D. Mann (@kito99)

  • Co-host, Enterprise Java Newscast (http://enterprisejavanews.com)

  • Java Champion

  • Google Developer Expert in Web Technologies

  • Internationally recognized speaker

    • JavaOne, JavaZone, Devoxx, Devnexus, NFJS, etc.

  • JCP Member

    • JSF, MVC, JSF Portlet Bridge, Portlets

Topics

  • Vocabulary

  • JavaScript

  • Tooling

  • Web Frameworks

  • Web Platform

Become a Full Stack Developer!

full stack developer

Vocabulary

monkeypatch

A monkey patch is a way for a program to extend or modify supporting system software locally (affecting only the running instance of the program). In Ruby, Python, and many other dynamic programming languages, the term monkey patch only refers to dynamic modifications of a class or module at runtime, motivated by the intent to patch existing third-party code as a workaround to a bug or feature which does not act as desired.

 — Wikipedia

shim

In computer programming, a shim is a small library that transparently intercepts API calls and changes the arguments passed, handles the operation itself, or redirects the operation elsewhere. Shims can be used to support an old API in a newer environment, or a new API in an older environment. Shims can also be used for running programs on different software platforms than they were developed for.

 — Wikipedia

polyfill

In web development, a polyfill (or polyfiller) is downloadable code which provides facilities that are not built into a web browser. It implements technology that a developer expects the browser to provide natively, providing a more uniform API landscape. For example, many features of HTML5 are not supported by versions of Internet Explorer older than version 8 or 9, but can be used by web pages if those pages install a polyfill. Web shims and HTML5 Shivs are related concepts.

 — Wikipedia

middleware

Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware. [Similar to Servlet Filters.]

 — Express site

transpiler

A source-to-source compiler, transcompiler or transpiler is a type of compiler that takes the source code of a program written in one programming language as its input and produces the equivalent source code in another programming language. A source-to-source compiler translates between programming languages that operate at approximately the same level of abstraction, while a traditional compiler translates from a higher level programming language to a lower level programming language.

 — Wikipedia

JavaScript

History

  • JavaScript really was written in 10 days in 1995 by Brendan Eich

  • ECMAScript 2 released in 1998

  • ECMAScript 3 released in 1999

  • ECMAScript 5 released in 2009

  • Current: ES2015 (ES6), ES2016 (ES7), ES2017 (ES8)

    • ECMA Technical Committe 39 (TC39) is working on ES2018 (ES9)

JavaScript Engines

  • JavaScript Engine ≈ Java Execution Environment

  • Java implementations

    • Rhino (Mozilla)

      • Ships with JDK 6

    • Nashorn (Oracle)

      • Ships with JDK 7+

JavaScript Engines

JavaScript Engines

  • Node.js = ECMAScript Engine + Standard Libraries + Package Manager (NPM)

Support for ES6+

ES6 / ES2015

  • Class syntax

class Shape {
	constructor(id, x, y) {
		this.id = id;
		this.x = x;
		this.y = y;
	}
}
class Rectangle extends Shape {
    constructor (id, x, y, width, height) {
        super(id, x, y)
        this.width  = width
        this.height = height
    }
}
class Circle extends Shape {
    constructor (id, x, y, radius) {
        super(id, x, y)
        this.radius = radius
    }
}

ES6 / ES2015

  • let and const

let a = [5,4,"foo",45];
for (let i = 0; i < a.length; i++) {
    let x = a[i];
}
console.log(a); // [5,4,"foo",45]
console.log(i); // undefined
console.log(x); // undefined
const immutable = 45;
immutable = 46; // error

ES6 / ES2015

  • Arrow function

this.nums.forEach((v) => {
    if (v % 5 === 0)
        this.fives.push(v)
})

ES6 / ES2015

  • Promises

function msgAfterTimeout (msg, who, timeout) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${msg} Hello ${who}!`), timeout)
    })
}
msgAfterTimeout("", "Foo", 100).then((msg) =>
    msgAfterTimeout(msg, "Bar", 200)
).then((msg) => {
    console.log(`done after 300ms:${msg}`)
})

ES6 / ES2015

  • Symbols

let f = Symbol("foo");
let f2 = Symbol("foo");
f === f2; // false

let f3 = f;
f === f3; // true

ES6 / ES2015

  • Template literals

let customer = { name: "Foo" }
let card = { amount: 7, product: "Bar", unitprice: 42 }
let message = `Hello ${customer.name}, want to buy ${card.amount} ${card.product} for a total of ${card.amount * card.unitprice} bucks?`
console.log(message)
// Displays "Hello Foo, want to buy 7 Bar for a total of 294 bucks?"

ES6 / ES2015

  • Destructuring

let { op, lhs, rhs } = getASTNode()
let tmp = getASTNode();
let op  = tmp.op;
let lhs = tmp.lhs;
let rhs = tmp.rhs;

ES6 / ES2015

  • Modules

  • Generators and Iterators

  • Maps and Sets

  • Proxying and Reflection

  • Internationalization / Localization

Transpilers

Transpilers: New JavaScript Features

  • Traceur

  • Babel

  • TypeScript

Transpilers: Type Saftey

  • Flow

  • TypeScript

Transpilers: TypeScript

interface CanGreet<T> {
    greeting: T;
    greet();
}

class Greeter<T> implements CanGreet<T> {
    greeting: T;
    constructor(message: T) {
        this.greeting = message;
    }
    greet() {
        return this.greeting;
    }
}

class HappyGreeter<T> extends Greeter<T> {
    constructor(message: T) {
        super(message);
    }
    happyGreet() {
        return "Hello! Happy " + super.greet();
    }
}

type NumberOrString = string | number;

let greeter = new Greeter<string>("Hello, world");
let happyGreeter = new HappyGreeter<NumberOrString>(55);

console.log(greeter.greet());
console.log(happyGreeter.greet());
console.log(happyGreeter.happyGreet());
}

Transpilers: TypeScript

Hello, world
55
Hello! Happy 55

Transpilers: Other Languages

Tools

Package Managers

  • Package Manager ≈ Dependency Manager

  • Popular Package Managers

    • Bower

    • Node Package Manager (NPM)

    • Yarn

npm

npm package.json

{
  "name": "ExampleApp",
  "version": "1.0.0",
  "license": "COMMERCIAL",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --host localhost --port 4201",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "doc": "compodoc -p tsconfig.json"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^4.4.6",
    "@angular/common": "^4.4.6",
    "@angular/compiler": "^4.4.6",
    "@angular/core": "^4.4.6",
    "@angular/forms": "^4.4.6",
    "@angular/http": "^4.4.6",
    "@angular/platform-browser": "^4.4.6",
    "@angular/platform-browser-dynamic": "^4.4.6",
    "@angular/router": "^4.4.6",
    "@types/html2canvas": "^0.5.35",
    "@types/jspdf": "^1.1.31",
    "chart.js": "2.6.0",
    "core-js": "^2.5.3",
    "crypto-js": "^3.1.9-1",
    "fullcalendar": "^3.8.0",
    "html2canvas": "^1.0.0-alpha.9",
    "jquery": "^3.2.1",
    "jspdf": "^1.3.5",
    "moment": "^2.20.1",
    "nanoscroller": "0.8.7",
    "primeng": "^4.3.0",
    "quill": "^1.3.4",
    "rxjs": "^5.5.6",
    "zone.js": "^0.8.20"
  },
  "devDependencies": {
    "@angular/cli": "1.2.4",
    "@angular/compiler-cli": "^4.4.6",
    "@compodoc/compodoc": "^1.0.5",
    "@types/googlemaps": "3.26.17",
    "@types/jasmine": "2.5.53",
    "@types/node": "^8.5.9",
    "codelyzer": "~3.1.2",
    "jasmine-core": "~2.6.4",
    "jasmine-spec-reporter": "~4.1.1",
    "karma": "^1.7.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.3.3",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "protractor-screenshoter-plugin": "^0.3.2",
    "ts-node": "~3.3.0",
    "tslint": "~5.5.0",
    "typescript": "~2.4.2"
  }
}

CSS Preprocessors

  • "Transpilers" for CSS

  • Add language features

    • Variables, imports, mixins, inheritance, operators, new functions, etc.

  • SASS

  • Less

  • Stylus

Saas Example

@import '../sass/variables-app-global';

$primaryColor: $appPrimaryBlue;
$primaryTextColor: $appBrightTextColor;
$toggleButtonBgColor: $appDefaultBackgroundColor;

@import '../sass/theme/_theme-app';

body, .app-body, .ui-widget {
  font-family: $appBodyFontFamily;
  font-size: $appBodyFontSize;
  line-height: $appLineHeight;
  color: $appPrimaryTextColor;
}

.app-base-padding {
  padding: .5 * $appBaseUnit;
}

.app-button {
  @extend .app-base-padding
}

.ui-dialog {
  @include overlay-shadow();
  border: $overlayBorder;
  font-size: 1.25 * $appBaseUnit;

  .ui-dialog-titlebar {
    padding: $headerPadding;
    padding-top: 1em;
    padding-bottom: 1em;

    .ui-dialog-title {
      margin: 0;
      float: none;
      vertical-align: middle;
      @extend .app-display;
    }

    .ui-dialog-titlebar-icon {
      color: $headerIconColor;
      border: 0 none;
      @include transition(color $transitionDuration);
      padding: 0;
      margin-left: .35em;
      font-size: $fontSize + 2;

      &:hover {
        color: darken($headerIconHoverColor, 10%);
      }
    }
  }
}

Build Tools

  • What is there to build?

Build Tools

build process

Build Tools

  • Grunt

  • Gulp

  • Webpack

  • Browserify

  • Brunch

Gruntfile.js

'use strict';

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('tiny-pubsub.jquery.json'),
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
      ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
    // Task configuration.
    clean: {
      src: ['dist']
    },
    concat: {
      options: {
        banner: '<%= banner %>',
        stripBanners: true
      },
      dist: {
        src: ['src/<%= pkg.name %>.js'],
        dest: 'dist/ba-<%= pkg.name %>.js'
      },
    },
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        src: '<%= concat.dist.dest %>',
        dest: 'dist/ba-<%= pkg.name %>.min.js'
      },
    },
    qunit: {
      files: ['test/**/*.html']
    },
    jshint: {
      gruntfile: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: 'Gruntfile.js'
      },
      src: {
        options: {
          jshintrc: 'src/.jshintrc'
        },
        src: ['src/**/*.js']
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/**/*.js']
      },
    },
    watch: {
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      src: {
        files: '<%= jshint.src.src %>',
        tasks: ['jshint:src', 'qunit']
      },
      test: {
        files: '<%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      },
    },
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Default task.
  grunt.registerTask('default', ['jshint', 'qunit', 'clean', 'concat', 'uglify']);

};

Gulpfile.js

'use strict';

var gulp = require('gulp');
var del = require('del');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var merge = require('merge-stream');
var path = require('path');
var glob = require('glob-all');
var gulpIf = require('gulp-if');
var gulpIgnore = require('gulp-ignore');
var runSequence = require('run-sequence');
var sourcemaps = require('gulp-sourcemaps');
var ts = require('gulp-typescript');
var tsProject = ts.createProject('tsconfig.json');

var src = '.';
var DIST = '.';
var dist = function(subpath) {
	return !subpath ? DIST : path.join(DIST, subpath);
};

gulp.task('typescript', function() {
	var tsResult = gulp.src()
		.pipe(sourcemaps.init())
		.pipe(ts(tsProject, undefined, ts.reporter.longReporter()));
	return merge([
		tsResult.dts.pipe(gulpIgnore.exclude(src + '/test/**/*')).pipe(gulp.dest(dist())),
		tsResult.js.pipe(sourcemaps.write('.')).pipe(gulp.dest(src))
	]);
});

gulp.task('clean', function() {
	var filesToDelete = ['.tmp', src + '/{test,demo}/**/*.{js,map,d.ts}',
		src + '/*.{js,map,d.ts}', '!' + src + '/{gulpfile,wct.conf}.js'];
	if (dist() != '.') {
		filesToDelete.push(dist());
	}
	return del(filesToDelete);
});

// Watch files for changes & reload
gulp.task('serve', ['typescript'], function() {
	browserSync({
		port: 5000,
		notify: false,
		logConnections: true,
		server: {
			baseDir: ['.tmp', '.'],
			routes: {
				'/': 'bower_components/'
			},
			index: 'index.html',
			directory: true
		}
	});
	gulp.watch([
			'{' + src + ',demo,test}/**/*.{ts,html}',
			'!{' + src + ',demo,test}/**/*.d.ts'
		],
		['typescript', reload]);
	gulp.watch([src + '/styles/**/*.css'], reload);
});

// Build production files, the default task
gulp.task('default', ['clean'], function(callback) {
	runSequence(['typescript'], callback);
});

Webpack

  • Module bundler, but anything can be a module

  • More of a Maven approach

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');

const config = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

Other Tools

yeoman logo

JavaScript Web Frameworks

What about jQuery?

jquery logo

What is a JavaScript Web Framework?

  • Apps can be entirely separated from the back-end

    • Communicate with server via REST

  • Support single-page apps

    • Support routing

  • Custom programming model

    • Component models, support for "model" objects, other feaures like services and pipes

    • Provides a way to structure the app

What is a JavaScript Web Framework?

  • Facilities for common tasks

    • Views

    • Communicaion with back-end (Ajax, parsing JSON)

    • State management

  • Run-time or compile-time optimizations

    • Angular’s compiler

    • React’s Virtual DOM

  • Command Line Interface (CLI)

What is a JavaScript Web Framework?

  • Two-way data binding

  • One-way data binding

    • Properties flow down to children; changes sent via events

Data Binding

Angular

<li>{{hero.name}}</li>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>

Polymer

<li>[[hero.name]]</li>
<app-hero-detail hero="{{selectedHero}}"></app-hero-detail>

JavaScript Web Frameworks

  • Backbone / Marionnete

  • Ember

  • AngularJS

JavaScript Web Frameworks

  • Angular

  • React

  • Vue

  • Aurelia

  • Polymer

JavaScript Web Framework

Component-oriented architecture is now standard.

Angular

angular architecture

React

  • Specifies only view layer

  • Components are functions

  • JSX ≈ JSP

  • Usually uses Flux or Redux handle global state and actions

Polymer

  • Library that provides features on top of web components specs

    • Data binding, syntactic sugar, mixins, helpers

  • Sets of components

    • UI (Material Design)

    • Application building blocks

    • Google Services

Managing State

  • Command Query Responsibility Segregation (CQRS) pattern

  • Implemented by Flux, Redux, Ngrx, etc.

  • Used to handle state in larger apps

Redux

redux

The Web Platform Has Matured

Do we still need web frameworks?

Remember the Browser Wars?

HTML(5)

HTML5.x

  • Web Sockets

  • WebRTC

  • Web Storage

HTML5.x

  • IndexedDB

  • Canvas

  • WebGL

  • And more (Bluetooth, USB, etc.)

Web Components

  • Custom Elements

  • Shadow DOM

  • HTML Template

CSS3

  • Technnically, there is no such thing as CSS3

  • Collection of "Modules" released after CSS2.1

  • Different snapshots published periodically by W3C

CSS3

  • Rounded corners, shadows, gradients, animations

  • Variables

  • Better layout

    • Flexible Box Layout (Flexbox)

    • Columns Layout

    • Grid Layout

Progressive Web Apps (PWAs)

Baseline PWA Technologies

  • Responsive Design

  • HTTPS

  • Web Manifest

  • Service Worker

Additional PWA Technologies

  • History API

  • Payment Request API

  • Credential Management API

Additional PWA Technologies

  • Notifications API

  • Network Information API

  • HTTP/2

  • WebAssembly

Do We Still Need Web Frameworks?

  • It depends.

  • At the very least, you will probably have dependencies and some tools.

  • So you’ll need a build tool…​

  • and a package manager…​

  • and…​

Questions?