Jordane Grenat | @JoGrenat
Fat Arrow functions
Generators
Promises
(Classes)
...
...
...
...
export function name1() {
};
export const name2 = 'value';
export let name3 = 1;
export class MyClass {};
let name4 = () => {};
let name5 = 5;
export { name4, name5 };
export { name4 as arrowFunc, name5 as five };export default 'value';import theDefaultExport from 'lib';
import { name1, name2 } from 'lib';
import theDefaultExport, { name1 } from 'lib';
import { name1 as otherName } from 'lib';
import * as myLib from 'lib';
import 'lib';System.import('lib')
    .then(myLib => {
        // Code
     })
    .catch(error => {
        // Error
    });SystemJS.config({
  packageConfigPaths: [
    "npm:@*/*.json",
    "npm:*.json",
    "github:*/*.json"
  ],
  transpiler: "plugin-babel",
  map: {
    "backbone": "npm:backbone@1.2.3",
    "css": "github:systemjs/plugin-css@0.1.20",
    "handlebars": "github:components/handlebars.js@4.0.5",
    "hbs": "github:davis/plugin-hbs@1.2.1",
    "jquery": "npm:jquery@2.2.1",
    "json": "github:systemjs/plugin-json@0.1.0",
    "plugin-babel": "npm:systemjs-plugin-babel@0.0.6",
    "process": "github:jspm/nodelibs-process@0.2.0-alpha"
  },
  packages: {
    "app": {
      "main": "app.js"
    },
    "github:davis/plugin-hbs@1.2.1": {
      "map": {
        "handlebars": "github:components/handlebars.js@4.0.5"
      }
    },
    "npm:backbone@1.2.3": {
      "map": {
        "underscore": "npm:underscore@1.8.3"
      }
    }
  }
});
Polyfill for the
ES Module Loader
<script src="system.js"></script>
<script>
  // loads relative to the current page URL
  System.import('./local-module.js'); 
  // load from an absolute URL directly
  System.import('https://code.jquery.com/jquery.js');
</script>SystemJS is an
universal module manager
It can load:
define(['jquery'], function($) {
    return function() {};
});AMD Modules
var $ = require('jquery');
exports.myModule = function () {};CommonJS Modules
import $ from 'jquery';
export default () => {};ES2015 Modules
window.myModule = function() {};Global Modules
You don't even CARE what kind of module you're loading!
With plugins, you can also load:
Package manager
built on top of SystemJS
It can load packages 
from any registry:
jspm install npm:aurelia
jspm install github:twbs/bootstrap
jspm install backboneGenerates SystemJS config automatically
Front MVP framework with
4 kinds of elements
Template management is left to the developper
We're gonna use
# One global install for the CLI
npm install -g jspm@beta# One local install for the project
npm install --save-dev jspm@betajspm install backbone jquery{
    "quotes": [
        {
            "text": "I think the worst time to have a heart attack is during a game of charades.",
            "author": "Demitri Martin"
        }, {
            "text": "When people ask me how many people work here, I say, about a third of them.",
            "author": "Lisa Kennedy Montgomery"
        }, {
            "text": "Always and never are two words you should always remember never to use.",
            "author": "Wendell Johnson"
        }, {
            "text": "Those who believe in telekinetics, raise my hand!",
            "author": "Kurt Vonnegut"
        }, {
            "text": "Always go to other people's funerals, otherwise they won't come to yours.",
            "author": "Yogi Berra"
        }, {
            "text": "Knowledge is knowing a tomato is a fruit; wisdom is not putting it in a fruit salad.",
            "author": "Miles Kington"
        }
    ]
}
src/config.json
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Random Quotes</title>
</head>
<body>
    <div class="view-main"></div>
	
    <script src="/jspm_packages/system.js"></script>
    <script src="/jspm.browser.js"></script>
    <script src="/jspm.config.js"></script>
    <script>
        System['import']('app/app.js');
    </script>
</body>
</html>
index.html
1- Load SystemJS
2- Load our configs
3- Import our entry point
(use ['import'] for IE8 compatibility)
import Backbone from 'backbone';
export default Backbone.Model.extend({
    defaults: {
        text: '',
        author: ''
    }
});
src/quote/QuoteModel.js
import Backbone from 'backbone';
import config from 'app/config.json!';
import Quote from './QuoteModel.js';
export default Backbone.Collection.extend({
    model: Quote,
    initialize() {
        this.set(config.quotes);
    }
});
src/quote/QuoteCollection.js
jspm install jsonLoad JSON config file
<blockquote class="quote">
	{{ quote.text }}
	<cite class="quote-author">{{ quote.author}}</cite>
</blockquote>
<button class="js-newQuote quoteButton">Another quote!</button>src/quote/quoteTemplate.hbs
jspm install handlebars
html, body {
  height: 100%;
}
body {
  background-color: #daf0f8;
}
.view-main {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100%;
}
.quote {
  width: 60%;
  margin: 0;
  text-align: center;
  font-family: Georgia, serif;
  font-size: 3rem;
  font-style: italic;
  line-height: 1.45;
  color: #383838;
}
@media (max-width: 1200px) {
  .quote {
    width: 90%;
  }
}
.quote-author {
  color: #999999;
  font-size: 1.5rem;
  display: block;
  margin: 1rem 0;
  text-align: center;
}src/quote/quote.css
.quote-author:before, .quote-author:after {
  content: "\2009 \2014 \2009";
}
.quoteButton {
  position: relative;
  margin-top: 2rem;
  min-height: 3rem;
  padding: 0.4rem 2rem;
  border: 4px solid lightblue;
  background: none;
  border-radius: 20px;
  font-size: 1.5rem;
  font-family: Arial, serif;
  font-style: italic;
}
.quoteButton:hover, .quoteButton:focus {
  background-color: lightblue;
}
.quoteButton:active, .quoteButton:focus {
  outline: none;
  border: 4px solid lightblue;
}
.quoteButton:active:before, .quoteButton:focus:before {
  content: ' ';
  border-radius: 20px;
  position: absolute;
  border: 2px dashed white;
  display: block;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
import Backbone from 'backbone';
import './quote.css!';
import renderTemplate from './quoteTemplate.hbs!';
import QuoteCollection from './QuoteCollection.js';
export default Backbone.View.extend({
    el: '.view-main',
    events: {
        'click .js-newQuote': 'render'
    },
    initialize() {
        this.quotes = new QuoteCollection();
    },
    render() {
        let quote;
        while((quote = this.quotes.sample()) && quote === this.quote);
        this.quote = quote;
        this.$el.html(renderTemplate({ quote: quote.toJSON() }));
    }
});
src/quote/QuoteView.js
jspm install css
jspm install hbs=github:davis/plugin-hbs1- Load CSS file
2- Load template
3- Select random quote
4- Render template
'quote/quote.css!css'
import Backbone from 'backbone';
import QuoteView from 'app/quote/QuoteView.js';
let AppRouter = Backbone.Router.extend({
    routes: {
        '': 'quote'
    },
    initialize() {
        this.quoteView = new QuoteView();
    },
    quote() {
        this.quoteView.render();
    }
});
export default new AppRouter();src/appRouters.js
import Backbone from 'backbone';
import './appRouter.js';
Backbone.history.start();src/app.js
Very easy, we only need to install npm and JSPM modules
{
  "scripts": {
    "postinstall": "jspm install"
  }
}npm installpackage.json
live-servernpm install --save-dev live-server{
  "scripts": {
    "start": "live-server"
  }
}npm startpackage.json
jspm bundle entryPoint destinationFilebuild
or
Group several modules into a bundle
Can be injected into browser configuration
Don't need SystemJS
Can use tree shaking
No lazy-loading
--minifycommand +
--separateCSScommand +
--skip-source-mapscommand +
{
  "bundles": {
    "dist/app.js": [
      "npm:underscore@1.8.3/underscore",
      "github:components/jquery@2.1.4/jquery",
      "npm:process@0.10.1/browser",
      "quote/quote.css!github:systemjs/plugin-css@0.1.13",
      "github:components/handlebars.js@3.0.3/handlebars",
      "config.json!github:systemjs/plugin-json@0.1.0",
      "quote/QuoteModel",
      "npm:underscore@1.8.3",
      "github:components/jquery@2.1.4",
      "npm:process@0.10.1",
      "github:components/handlebars.js@3.0.3",
      "quote/QuoteCollection",
      "github:jspm/nodelibs-process@0.1.1/index",
      "quote/quoteTemplate.hbs!github:davis/plugin-hbs@1.0.0",
      "github:jspm/nodelibs-process@0.1.1",
      "quote/QuoteView",
      "npm:backbone@1.2.1/backbone",
      "appRouter",
      "npm:backbone@1.2.1",
      "startup"
    ]
  }
}ollup
= Dead Code Elimination
=> Use System.import() and create several bundles !
jspm bundle app/app.js dist/app.js
jspm bundle app/quote/QuoteView.js - app/app.js dist/quotes.jsquote() {
    let promise;
    if(this.quoteView) {
        promise = Promise.resolve(this.quoteView);
    } else {
        promise = System.import('quote/QuoteView').then(QuoteView => {
            this.quoteView = new QuoteView['default']();
            return this.quoteView;
        });
    }
    return promise.then(quoteView => quoteView.render());
}src/appRouter.js
1.
2.
3.
4.
5.
All!
That's
And
Replace scripts in index.html
JSPM build
npm install --save-dev gulp gulp-html-replace  var gulp = require('gulp');
var htmlReplace = require('gulp-html-replace');
gulp.task('html', function () {
    return gulp.src(['index.html'])
        .pipe(htmlReplace({
            js: 'app.js'     
        }))
	.pipe(gulp.dest('dist'));
});
Gulpfile.js
<!-- build:js -->
<script src="/jspm_packages/system.js"></script>
<script src="/jspm.browser.js"></script>
<script src="/jspm.config.js"></script>
<script>
    System['import']('app/app.js');
</script>
<!-- endbuild -->index.html
{
  "scripts": {
    "build": "jspm build app/app.js dist/app.js --minify && gulp html"
  }
}npm run buildpackage.json
npm install --save-dev mocha babel-core
npm install --save-dev babel-preset-es2015{
  "presets": ["es2015"]
}.babelrc
npm install --save-dev karma karma-mocha \
        karma-jspm karma-chrome-launchermodule.exports = function(config) {
  config.set({
	
    proxies: {
        '/base': '/base/src',
    },
    frameworks: ['jspm', 'mocha'],
    jspm: {
        config: "src/jspm-config.js",
        packages: '/src/jspm_packages',
        serveFiles: [
            'src/**/*.js',
            'src/**/*.json',
            'src/**/*.hbs',
        ],
        loadFiles: [
            'src/**/tests/**/*.test.js'
        ]
    },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    concurrency: Infinity
  })
}
karma.conf.js
import QuoteCollection from 'quote/QuoteCollection';
describe('Test', function() {
    const quoteCollection = new QuoteCollection();
	describe('#get()', function() {
		it('should return 6 quotes', function() {
            expect(quoteCollection.get().length).toEqual(6);
		});
	});
});
src/quote/tests/QuoteCollection.test.js
karma start karma.conf.js{
  "scripts": {
    "test:unit": "karma start karma.conf.js"
  }
}npm run test:unitpackage.json
npm install --save-dev codeceptjs
npm install -g codeceptjscodeceptjs initScenario('I have a button to change the quote', (I) => {
  I.amOnPage('/');
  I.waitForText('Another quote!');
});Feature('Random quotes');Scenario('I can change the quote', function*(I) {
  I.amOnPage('/');
  I.waitForText('Another quote!');
  const quote1 = yield I.grabTextFrom('.quote');
  I.click('Another quote!');
  const quote2 = yield I.grabTextFrom('.quote');
  assert.notEqual(quote1, quote2);
});
Scenario('I never have the same quote when changing the quote', function*(I) {	
  I.amOnPage('/');
  
  for(let i = 0; i < 30; i++) {
    I.waitForText('Another quote!');
    const quote1 = yield I.grabTextFrom('.quote');
    I.click('Another quote!');
    const quote2 = yield I.grabTextFrom('.quote');
    assert.notEqual(quote1, quote2);  
  }
});{
  "scripts": {
    "test:e2e": "codeceptjs run",
    "test": "npm run test:unit && npm run test:e2e"
  }
}npm run testpackage.json
{
  "scripts": {
    "postinstall": "jspm install",
    "start": "live-server",
    "build": "jspm build src/app.js dist/app.js --minify && gulp html",
    "test:unit": "karma run karma.conf.js",
    "test:e2e": "codeceptjs run",
    "test": "npm run test:unit && npm run test:e2e"
  }
}package.json
Jordane Grenat | @JoGrenat