The Dart side of disruption

@a14n @GirouGuillaume @MatBreton @NicoFrancois
 
 
 

Avant de commencer

Pourquoi ?

Nouveau langage pour le web

Répond aux problématiques d'aujourd'hui

Performance

Moderne

Disruptif ?

Définition

Une technologie de rupture, également connue comme « rupture technologique », est une innovation technologique qui porte sur un produit ou un service et qui finit par remplacer une technologie dominante sur un marché. (Wikipedia)

Objectif de l'atelier

Etre capable de développer une application web moderne
 
 
 

Introduction au langage

1er pas

Hello world

lang-dart void main(){
     var hello = "Hello Devoxx France";
     print(hello);
 }

Hello Devoxx France

Fonction top level

lang-dart void main(){
     var who = "Devoxx France";
     print(sayHello(who));
 }

 String sayHello(String name) =>  "Hello $name"

Hello Devoxx France

Paramètres

Paramètres optionnels nommés

lang-dart // Affecte les flags bold et hidden à leur valeurs.
 enableFlags({bool bold, bool hidden}) {
   // ...
 }
lang-dart enableFlags(bold: true, hidden: false);
lang-dart enableFlags(hidden: false, bold: true);
lang-dart enableFlags(hidden : true);
lang-dart enableFlags();

Paramètres optionnels positionnés

lang-dart String say(String from, String msg, [String device]) {
   var result = '$from says $msg';
   if (device != null) {
     result = '$result with a $device';
   }
   return result;
 }
 
lang-dart say('Bob', 'Howdy');
 // 'Bob says Howdy'
 say('Bob', 'Howdy', 'smoke signal');
 // 'Bob says Howdy with a smoke signal'

Classes

Ma 1ère classe

lang-dart class MaClasse {

 }

lang-dart var classe = new MaSuperClasse();
 MaSuperClasse unAutreClasse = new MaSuperClasse();

Classe avec getter/setter

lang-dart class Person {
   // Visibilité restreinte par le _
   String _name;
   String get name => _name;
   set name(val) => _name = val;
 }

lang-dart var p = new Person();
 p.name = "John"; // Set
 var name = p.name; // Get

Classe complète

lang-dart import 'dart:math';

 class Point {
   final int x, y;
   Point(this.x, this.y);
   num distanceTo(Point other) {
     var dx = x - other.x;
     var dy = y - other.y;
     return sqrt(dx * dx + dy * dy);
   }
   String toString() => "($x, $y)";
 }
lang-dart var p = new Point(2, 3);
 print(p);// Affiche '(2, 3)'
 var x = p.x;
 var distance = p.distanceTo(new Point(5, 5));

Héritage

lang-dart class Person {
   Person.fromJson(Map data) {
     print('in Person');
   }
 }
lang-dart class Employee extends Person {
   // Person n'a pas de constructeur par défaut
   // Il faut appeler super.fromJson(data).
   Employee.fromJson(Map data) : super.fromJson(data) {
     print('in Employee');
   }
 }

Implémentation

lang-dart // Person est une interface implicite contient greet().
 class Person {
   // Dans l'interface mais visible dans la bibliothèque
   final _name;
   // Pas dans l'interface car c'est une constructeur
   Person(this._name);
   // Méthode de l'interface
   String greet(who) => 'Hello, $who. I am $_name.';
 }
lang-dart // Une implémentation de Person.
 class Imposter implements Person {
   // On le définit mais on ne l'utilise pas
   final _name = "";
   String greet(who) => 'Hi $who. Do you know who I am?';
 }

Mixin

lang-dart // Un mixin doit
 // étendre Object, ne pas avoir de constructeur, pas d'appel à super
 abstract class Musical {
   bool canPlayPiano = false;
   bool canCompose = false;
   bool canConduct = false;

   void entertainMe() {
     //
   }
 }
lang-dart class Musician extends Performer with Musical {
   Musician(String musicianName) {
     name = musicianName;
     canConduct = true;
   }
 }

Constructeurs

Constructeur nommé

lang-dart import 'dart:math';

 class Point {
   num x, y;
   Point(this.x, this.y);
   Point.zero() : x = 0, y = 0;
   Point.polar(num theta, num radius) {
     x = cos(theta) * radius;
     y = sin(theta) * radius;
   }
 }
lang-dart Point p1 = new Point.zero();
 Point p2 = new Point.polar(0, 1);

Factory

lang-dart class Logger {
   final String name;
     bool mute = false;

     static final Map<String, Logger> _cache = <String, Logger>{};

     factory Logger(String name) => _cache.putIfAbsent(name, () =>
          new Logger._internal(name));

     Logger._internal(this.name);
   }

lang-dart Logger logger = new Logger("foo");

Collections

List

lang-dart // Creation de listes
 var vegetables = [] // == new List();
 var fruits = ['apples', 'oranges'];
lang-dart // Ajout d'éléments
 fruits.add('kiwis');
 fruits.addAll(['grapes', 'bananas']);
 assert(fruits.length == 5);
lang-dart // Tri
 fruits.sort();
 assert(fruits[0] == 'apples');

Map

lang-dart var gifts = {
   // Keys       Values
   'first'  : 'partridge',
   'second' : 'turtledoves',
   'fifth'  : 'golden rings'
 };
lang-dart gifts['fourth'] = 'calling birds';    // Add a key-value pair
lang-dart assert(gifts['first'] == 'partridge')
 assert(gifts.length == 4);
lang-dart var keys = gifts.keys;
 var values = gifts.values;

Set

lang-dart // Création
 var ingredients = new Set();
 ingredients.addAll(['gold', 'titanium', 'xenon']);
lang-dart // Intersection
 var nobleGases = new Set.from(['xenon', 'argon']);
 var intersection = ingredients.intersection(nobleGases);
 assert(intersection.length == 1);
 assert(intersection.contains('xenon'));

Lamdba

lang-dart var teas = ['green', 'black', 'chamomile', 'earl grey'];
lang-dart // Affichage en majuscule
 var loudTeas = teas.map((tea) => tea.toUpperCase());
 loudTeas.forEach(print);
lang-dart // La camomille n'est pas caéfinée.
 bool isDecaffeinated(String teaName) => teaName == 'chamomile';
lang-dart // Filtrage
 var decaffeinatedTeas = teas.where(isDecaffeinated);
lang-dart // Construction map
 var decaffeinatedTeasMap =
    new Map.fromIterable(teas, value: isDecaffeinated);

Asynchronisme

Future

lang-dart Future result = costlyQuery();

 // Enchainer méthodes
 return result.then((value) => expensiveWork())
              .then((value) => lengthyComputation())
              .then((value) => print('done!'))
              // Gestion erreur
              .catchError((exception) => print('DOH!'))

Stream

lang-dart // Trouver un bouton et ajouter un listener
 querySelector('#submitInfo').onClick.listen((e) {
   // Quand le bouton est cliqué, ce code est exécuté
   submitData();
 });

Divers

Metadata

lang-dart class Television {
   /// _Deprecated: Utiliser [turnOn]._
   @deprecated
   void activate() {
     turnOn();
   }

   void turnOn() {
     _illuminateDisplay();
     _activateIrSensor();
   }
 }
lang-dart class SmartTelevision extends Television {
   @override
   void turnOn() {
     super.turnOn();
     _bootNetworkInterface();
   }
 }

Cascade

lang-dart var button = querySelector('#button');
 button.text = 'Click to Confirm';
 button.classes.add('important');
 button.onClick.listen((e) => window.alert('Confirmed!'));

lang-dart querySelector('#button')
             ..text = 'Click to Confirm'
             ..classes.add('important')
             ..onClick.listen((e) => window.alert('Confirmed!'));

Outils

Bibliothèques


Interne
dart:io Entrée/Sortie système
dart:math Calcul, génération aléatoire, ...
dart:convert Codec de convertion (JSon, ... )
dart:html Manipulation DOM

Externe
unittest Tests unitaires
Polymer Web components

Déclaration librairies/Import

 library bestWebApp;

 part 'src/crazyImpl.dart';
 part 'src/wonderfullUI.dart';

 import 'dart:html';
 import 'package:polymer/polymer.dart';

 // crazyImpl.dart
 part of bestWebApp;

Pub

pubspec.yaml
lang-js
name: my_app
dependencies:
  polymer: ">=0.9.5 <0.10.0"
dev_dependencies:
  unittest: any
transformers:
- polymer:
    entry_points: web/index.html

lang-shpub get
lang-shpub build

Test

lang-dart import 'package:unittest/unittest.dart';

 main(){

   test('Un test simple', () => expect(2+2, 4));

   group('Test plus complexe', () {
     setUp(() {/*...*/});
     tearDown(() {/*...*/});
     test('Test complexe 1', () {/*...*/});
     test('Test complexe 2', () {/*...*/});
   });
 }
unittest-suite-wait-for-done
PASS: Un test simple
PASS: Test plus complexe Test complexe 1
PASS: Test plus complexe Test complexe 2

All 3 tests passed.
unittest-suite-success
 
 
 
 

Explication du codelab

Votre mission

goo.gl/GLZxvx

Architecture

Déroulement

  • Partie core
  • Partie UI
  • Partie Server

Démo

 
 
 

Polymer

Architecture

Organisation projet

Fondation

Custom Elements

lang-html<x-click-counter></x-click-counter>

lang-html<element name="x-click-counter">
  <template>
    <style>
        /* Css */
    </style>
    <-- Html -->
  </template>
  <-- Code Dart -->
  <script src="click_counter.dart"></script>
</element>

HTML Template

lang-html<template id="monSuperTemplate">
  <div class="super-style" >
  </div>
  <!-- Plein de html -->
</template>

lang-html<template if="{{maCondition}}">

lang-html<template repeat="{{maList}}">

Shadow DOM

lang-html<video controls src="/ma/super/video"></video>

lang-html<video controls="" height="300" src="/ma/super/video">
  #shadow-root
  <div>
    <div>
      <div>
        <input type="button">
        <input type="range" precision="float" max="596.48">
        <div style="display: none;">0:00</div><div>9:56</div>
          <input type="button">
          <input type="range" precision="float" max="1" style="">
          <input type="button" style="display: none;">
          <input type="button" style="">
        </div>
    </div>
  </div>
</video>

HTML Import

lang-html<head>
    <!-- Plein de déclaration -->
    <link rel="import" href="/components/click_counter.html">
</head>

Observer

lang-html<div>
  {{name}}
</div>

lang-dart @observable String name;

Communication serveur

HttpRequest

lang-dart HttpRequest.getString('myU')
            .then((String fileContents) {
               //..
             });
 
 
 

Dart coté serveur

Serveur Http

lang-dart import 'dart:io';

 main() {
   HttpServer.bind('127.0.0.1', 8080).then((server) {
     server.listen((HttpRequest request) {
       request.response..write('Hello, world')
                       ..close();
     });
   });
 }

Virtual Directory

lang-dart // Le répertoire des fichiers web
 final webDir = Platform.script.resolve('../web').toFilePath();
 // Les régles du serveur de fichiers
 final vDir = new VirtualDirectory(webDir)
           ..jailRoot = false
           ..followLinks = true
           ..allowDirectoryListing = true;
 // Association aux requêtes entrantes
 vDir.serveRequest(request);

WebSocket

lang-dart WebSocketTransformer.upgrade(request).then((WebSocket ws){
     // Envoi message
     ws.add("Hello");
     // Ecoute les événements qui arrive et les affiche
     ws.listen(print);
 });