• Noser.com
facebook
linkedin
twitter
youtube
  • NOSERmobile
    • Android
    • HTML 5
    • Hybrid Apps
    • iOS
    • Windows Phone
  • NOSERembedded
    • Medizintechnik
  • NOSERprojektmanagement
  • NOSERtesting
  • NOSERlifecycle
    • .NET Allgemein
    • Application Lifecylce Management
    • Apps
    • Architektur
    • ASP.NET
    • Azure
    • Cleancode
    • Cloud
    • Silverlight
    • Visual Studio / Team Foundation Server
    • Windows 8
    • Windows Presentation Foundation
  • NOSERinnovation
    • Big Data
    • Cloud
    • IoT
    • Operations Research
    • Augmented Reality
    • RFID, NFC, Bluetooth LE

ManuScripts: Wenn jemand eine Reise tut… Funktionale Programmierung mit Elm – Teil 4 – Über Stock und Stein

30. Mai 2016
Manuel Baumann
3
Angular2, AngularJs, Elm, Functional Programming, Javascript, react, ReactJS, scrabble

Eine Blog-Serie zum Vergleich von Elm, ReactJS und AngularJS anhand eines praktischen Beispiels. Hier geht es direkt zu [Teil 1, 2, 3, 5, 6]

Endlich sind wir soweit, dass wir mit unserer Beispiel-Applikation anfangen können.

Zur Erinnerung: Ziel ist es, eine Browser-Applikation zu bauen, die von SCRABBLE-Spielern genutzt werden kann, um Anagramme zu generieren für die Buchstaben-Steine, die sie aus dem Säckchen gezogen haben und nun auf ihrer Bank liegen.

Der elm Anagramm-Generator ist für Scrabbler

Anagramme sind diejenigen Worte, die sich durch Umsortieren dieser Buchstaben ergeben, und die in unserem Falle auch gültige deutsche Worte sein müssen.

Also, nicht FUN GAME, sondern UMFANGE. Im Scrabble ist das sogar ein BINGO, also ein Wort, bei dem alle 7 Buchstaben-Steine des Spielers verwendet werden können.


Elm, React und Angular sitzen im Bus zwischen Schwanden und Elm und schauen zu den gewaltigen Gebirgsketten hoch. Von dort würde sie die Luftseilbahn dann direkt in das rauhe Gelände hieven. Alle drei hielten sich aber oft in klimatisierten Räumen mit Monitor-Beleuchtung auf, und keiner von ihnen war vertraut mit den Konditionen rund um Mount Anagramm. Elm ruft die Tourdaten auf seinem Smartphone ab und fasst aus ihrer Sicht zusammen, wie die steinige Bergrealität sich präsentieren wird:

Gelände-Bedingungen

Wort-Brocken

Damit dieses Programm überhaupt möglich wird, benötigt es eine Liste von möglichst vielen gültigen, deutschen SCRABBLE-Wörtern. Glücklicherweise bin ich im Besitz einer solchen Liste, wenn auch einer etwas älteren. Die Liste enthält praktisch alle im Duden erschienenen Wörter, mit ihren Beugungen, Deklinationen und sämtlichen temporalen Formen. Die längsten Wörter haben 15 Buchstaben (Das ist die Breite des Spielbretts).

Echo

Weil diese Wort-Liste selbst in optimierter und komprimierter Form recht gross ist, macht es mehr Sinn, einen Web-Service anzubieten, der die Anagramm-Suche durchführt, als diese Daten auf jeden Client zu serialisieren.

Das Deployment des elm Anagrammerators

Wegweiser

Mit Elm kommt eine vorgeschlagene Architekur, die Elm Architektur. Die Grundidee ist, dass jedes Programm in einem Model seinen Zustand hält, mit einer Update-Funktion (und nur damit) wird dieser Zustand verändert und mit einer View wird der Zustand angezeigt.

Dieses Muster zieht sich durch alle Module durch, die zusammen den gesamten Applikations-Zustand ausmachen. Dies führt dann dazu, dass jedes Modul nur die drei Funktionen init, update und view anbietet, und dazu eine Reihe von Nachrichten-Typen definiert, die von update verarbeitet werden können.

Klingt simpel, ist es auch. Darum folgen wir diesem Stil wie Lemmings. Im verlinkten Artikel wird der update-loop grafisch dargestellt und beschrieben, wie das ganze mit Subscriptions zusammengehängt wird. Wir werden in einem weiteren Teil auf elm-Subscriptions eingehen.

Etappen-Ziel

SCRABBLE-Buchstaben

elm Anagrammerator: Scrabble Spieler-Bank
Auf dieser Bank sind zwei mir bekannte Bingos versteckt. Das Finden des Anagramms ist die eine Sache, das Wort muss auch auf dem Brett platziert werden können, indem bereits gelegte Steine verwendet werden. (Ausser natürlich beim ersten Zug des Spiels)

Zu Beginn seines Zuges hat ein Spieler im Regelfall 7 Buchstaben-Steine vor sich auf der Bank liegen. Auf jedem Stein ist ein Buchstabe abgebildet – in anderen Sprachen sogar mehrere pro Stein – und ein Buchstaben-Wert.

elm Anagrammerator: Buchstaben

Die Ausnahme bilder der BLANKO-Stein, ohne Buchstaben und mit Wert 0.
Der Spieler darf frei wählen, für welchen Buchstaben der Stein als Platzhalter dienen soll.

elm Anagrammerator: Scrabble Blanko-Stein

In der deutschen Variante des Spiels, und um die soll es hier gehen, gibt es total 102 Steine im Sack, 2 davon sind Blankos.

elm Anagrammerator: Scrabble-Steine für die DE-Version

(K)einen Stein machen

Anstatt beliebige Zeichenketten als Eingabe zu erlauben, sollen Benutzer nur Eingaben machen können, die auch während eines echten Spiels so hätten stattfinden können.

Wenn wir also für jede Abfrage diese Regeln einführen:

  • Nicht mehr als zwei Blankos zulässig
  • Nicht mehr als 12 andere, beliebige Buchstaben.
  • Nur Buchstaben, die auch so aus dem Sack gezogen hätten werden können. z.B. nicht mehr als 5 mal A

dann hat das diese Vorteile:

  • Die App wird spannender und kommt näher an ein “echtes” Problem.
  • Der durchschnittliche Anwender wird nicht in Versuchung geführt, exzessive Such-Anfragen zu gestalten (15 Blankos).
  • Die Antwortzeiten sind sehr kurz in diesem Rahmen.
  • Die Buchstaben-Werte können z.B. für Sortierung nach Wortwert verwendet werden.

Die Regeln müssen natürlich und vor allem auch serverseitig durchgesetzt werden, aber dazu kommen wir später.

Agil zum Ziel

An dieser Stelle wäre der Plan gewesen, im Projekt elm-anagrams weiterzufahren (siehe Teil 1), aber Elm hat seit Beginn der Blog-Serie die Version gewechselt. Mit dem Update von 0.16 auf 0.17 hat es einige Veränderungen gegeben (allesamt Vereinfachungen für den Programmierer). Das Package Graphics.Element, welches wir im Hello.elm verwenden, ist jetzt aber kein Paket der Kern-Bibliothek mehr. Wir könnten es wieder einbinden, aber ich bin lieber cutting-edge, darum schmeiss ich das völlig sinnlose Hello.elm weg und aktualisiere meine elm-Plattform kurzerhand:

rm Hello.elm
rm elm-package.json
rm -rf elm/stuff
rm elm.js

npm i -g elm

elm-package install -y

Hier findet man die Implementation von Hello World für die aktuelle Version: examples/hello-html

Modul Tile.elm

Anmerkung: Sublime Text bietet mit dem Package Elm Language Support exzellente Elm-Unterstützung. (Der Support, der von Atom und LightTable angeboten wird, ist sogar noch besser, wie ich zwischenzeitlich herausgefunden habe)

Erstellen wir also unser erstes 0.17-elm Modul, in einem File namens Tile.elm und definieren darin die für die Spielsteine benötigten Strukturen:

module Tile exposing (..)

type alias TileDef =
  { letter : String
  , value : Int
  , count : Int
  }

type alias Id = Int

type alias Model =
  { id : Id
  , def : TileDef
  , blankoLetter: Maybe String
  }

Zuoberst ist die Modul-Deklaration. Im exposing (..) könnten anstelle der Punkte auch komma-separierte Namen der exportierten Funktionen aufgelistet werden. Momentan ist diese einfache Schreibweise willkommen. So wird alles exportiert und kann nun auch von anderen Modulen verwendet werden.

TileDef ist eine Typ-Definition für einen Spielstein: Welcher Buchstabe, welcher Wert, wie oft er im Sack vorkommt. Diese Art von Typ nennt sich in Elm ein Record, und ist eine leichtgewichtige Datenstruktur mit Feldern beliebigen Typs.

Id stellt ein Alias für den Basis-Typ Int dar. Damit soll bloss der Zweck dieses Int auch beim Lesen deutlich gemacht werden. Nun kann Id gleichbedeutend mit Int (einer Ganzzahl) verwendet werden.

Das Model in diesem Modul ist ebenfalls ein Record, der die Daten, den Zustand, eines einzelnen Spielsteins beschreibt.

  • Jeder Stein braucht eine Id, damit er von anderen mit der gleichen TileDef unterschieden werden kann.
  • Spannender ist das Attribut blankoLetter. Es ist vom Typ Maybe String. Dies bedeutet, dass der Wert einen String annehmen kann, er kann aber auch Nothing sein.

Maybe sollte man nicht mit null vergleichen, das es in vielen anderen Sprachen gibt. Wir werden noch sehen, dass die Konzepte sich sehr unterscheiden. null ist nicht Typ-sicher, es hat keinen Typ.

Dafür hat sich der Erfinder der Null-Referenz, Tony Hoare, sogar öffentlich entschuldigt; er nennt es seinen ‘Billion-Dollar mistake‘

init

Die Elm-Architektur schlägt drei Funktionen vor: init, update und view.

Die erste Funktion soll das Modell initialisieren. Daher ist ihr Rückgabe-Typ vom Typ Model. Als Input kriegt sie, was sie von der Programmlogik her braucht. In unserem Fall sind das eine Id und eine TileDef. Mit Signatur:

init: Id -> TileDef -> Model
init id tileDef =
    { id = id
    , def = tileDef
    , blankoLetter = Nothing  -- wird erst später gesetzt
    }

Zur Repetition: Die Signatur einer Funktion in elm liest sich folgendermassen:

Name : Input1 -> Input2 -> … -> Output

Die Implementation fängt mit dem Namen der Funktion an. Daruf folgt eine Liste von Parameter-Namen, so viele und in der Reihenfolge, wie sie deklariert wurden, mit Leerschlag voneinander getrennt.

init id tileDef =

Nach dem = folgt dann der “Body”, der einen Wert zurückgeben muss gemäss Signatur.

  { id = id
  , def = tileDef
  , blankoLetter = Nothing
  }

Es wird also ein neues Model initialisiert, indem die übergebenen Parameter in einem neuen Record gesetzt werden. Der blankoLetter wird zu Beginn auf Nothing gesetzt.

Keine neuen Erkenntnisse, nur eine neue Schreibweise, mit wesentlich weniger “Geräusch”. Auch der Formatierungs-Stil ist ‘elm-ish’, und eignet sich sehr gut für späteres Refactoring.

Eine alternative Schreibweise für die Initialisierung eines Records, die zwar schneller zu schreiben, aber nicht so verständlich zu lesen ist, wäre der Aufruf des Typ-Alias als Funktion mit den Parametern in der Reihenfolge, wie sie im Record angeordnet sind:

init id typeDef = Model id def Nothing

update

Als nächstes kommt die update Funktion. Unser Tile unterstützt genau eine Art von Update, nämlich das Setzen der Bedeutung eines Blanko-Steines.

Die Signatur von Update sieht folgendermassen aus:

update: Msg -> Model -> Model

Es soll eine Msg, also eine Nachricht, und ein Model kriegen und wieder ein Model zurückliefern. Auf diese Art wird jedes Model, jeder Zustand, in den nächsten Zustand überführt.

Das sollte nicht so schwierig zu erreichen sein, wenn wir einfach einen Typ namens Msg definieren (also:

type Msg =
    SetBlankoLetter String

Dies ist ein Typ, der nur zusammen mit einem String komplett ist.

Die Funktion update wird damit erst mal so implementiert:

update: Msg -> Model -> Model
update msg model =
    case msg of
        SetBlankoLetter letter ->
            if model.def.letter == " " then
               { model | blankoLetter = Just letter }
            else 
               model

In dem switch-ähnlichen Konstrukt case … of findet ein Pattern-Matching statt. In unserem Fall gibt es nur einen case zu behandeln, wo wir eine msg vom Typ SetBlankoLetter erhalten, mit dem nun instanziierten letter-String-Wert. Dann wird mit einem if…then…else geprüft, ob es sich wirklich um einen Blanko handelt. Falls ja, dann müssen wir den letter  mit Just in von String  in seinen richtigen Typ Maybe String verwandeln. Sieht lustig aus, man gewöhnt sich schnell daran.

Zurückgegeben wird ein NEUES Model, eine Kopie des Parameters, AUSSER des Attributs blankoLetter, das wird nämlich auf Just letter, also den Wert der übergebenen Msg, gesetzt.

Im else -Fall, wenn es kein Blanko ist, wird der Zustand, das model, unverändert zurückgegeben.

view

Um etwas zu sehen, braucht es noch die Funktion view. Mit Signatur sieht das im einfachsten Falle so aus:

view: Model -> Html Msg
view model =
    div [] [ text (toString model) ]

Also: Model rein, Html raus. Das muss keine Html-Antwort sein, aber für unser Beispiel wollen wir Html-Output.

Anmerkung: Am Return-Typ hängt noch ein Msg dran. Das soll erst nicht weiter verwirren, wir schauen das im Zusammenhang mit Benutzer-Interaktionen nochmals genauer an.

div hat zwei Parameter: eine Liste der Attribute und eine Liste seiner Elemente. Das einzige Element darin wird von Html.text erzeugt, welches nach einem String-Parameter verlangt.

toString ist aus dem core-Package und verwandelt Objekte jeden Typs in ihre textuelle Darstellung.

Elm-Package einbinden

Html ist jedoch nicht Teil des core-Packages. Damit wir die Funktionen div und text benutzen können, müssen wir das html-package einbinden:

elm-package install elm-lang/html -y

und oben im File Tile.elm wird die Abhängigkeit deklariert und das Package importiert. Und zwar gleich wieder alles davon mit (..):

module Tile where (..)

import Html exposing (..)

Wenn wir explizit hätten sein wollen, dann hätten wir bloss die drei benötigten Funktionen importiert:

import Html exposing (Html,div,text)

main

Das komplette File Tile.elm sieht nun so aus:

module Tile exposing (..)

import Html exposing (Html,div,text)

type alias TileDef =
  { letter : String
  , value : Int
  , count : Int
  }

type alias Id = Int

type alias Model =
  { id : Id
  , def : TileDef
  , blankoLetter: Maybe String
  }

type Msg =
  SetBlankoLetter String

init: Id -> TileDef -> Model
init id tileDef =
  { id = id
  , def = tileDef
  , blankoLetter = Nothing  -- wird erst später gesetzt
  }

update: Msg -> Model -> Model
update msg model =
  case msg of
    SetBlankoLetter letter ->
      { model | blankoLetter = Just letter }

view: Model -> Html msg
view model =
  div [] [text (toString model)]

Es fehlt bloss noch ein Test, bzw. ein Hauptprogramm. Auch in elm heisst dieses main, und kann verschiedene Typen zurückgeben. In unserem Fall ist es ein Html-Typ einer beliebigen Art. (Mehr dazu bei den Benutzer-Aktionen)

Zuunterst im File wird das Modul mit diesen Zeilen getestet:

letterA : TileDef
letterA =
  TileDef "A" 1 5 -- erste Methode, um einen Record zu initialisieren, Reihenfolge wie in Record-Def.

blanko : TileDef
blanko =
  { count = 2, letter = " ", value = 0 } -- zweite Methode, Reihenfolge egal

main: Html msg
main =
    let
      a1 = init 0 letterA
      a2 = init 1 letterA
      b1 = init 2 blanko
      b2 = update (SetBlankoLetter "Q") b1

    in
      div [] [ view a1
             , view a2
             , view b1
             , view b2
             ]

(Mit let wird ein Block mit Zuweisungen geöffnet, der mit in wieder geschlossen wird. let und in müssen genau untereinander stehen; es darf auch nichts dazwischen sein)

Ich war für den Blog-Post hier im ersten Modul sehr gründlich, aber man muss die Signaturen nicht immer angeben, ganz im Gegenteil, da Elm eine Sprache ist mit Typ-Inferenz, also Typen in den meisten Fällen anhand vorhandener Angaben herleiten kann, wird es dadurch noch “geräusch”-freier.

Am besten probiert man es selber aus, lässt hie und da mal eine Signatur weg, oder baut absichtlich einen Fehler ein, denn der Compiler, und darauf kommen wir gleich, gibt sich wirklich Mühe, dem Programmierer mit seinen Meldungen behilflich zu sein.

Build & Run

Natürlich ist der elm-reactor, der nun gestartet wird, oder immer noch läuft, die naheliegendste Option, um seine Fortschritte zu überprüfen.

Auf der Kommando-Zeile elm-reactor eingeben und auf http://localhost:8000 erscheint das für 0.17 überarbeitete GUI:

elm Anagrammerator: elm-reactor UI

Ein Klick auf Tile.elm startet die Kompilierung und zeigt entweder die noch zu wenig gelobten, sinnreichen Fehlermeldungen, oder unser für diesen Teil abschliessendes Ergebnis:

Während der Entwicklung mit Sublime Text, benutze ich lieber den eingebauten Build-Support des ‘Elm Language Support’-Package mit Ctrl+B. Der gibt mir Fehler-Highlighting und schlägt fehlende Signaturen vor.

In beiden Fällen wird selbstverständlich der Compiler elm-make gestartet, und sollte mal etwas nicht rund laufen, dann empfiehlt es sich, das elm-stuff/-Verzeichnis zu löschen und elm-package install -y && elm-make Tile.elm auszuführen (oder welche Datei es dann zu kompilieren gibt).

Wann sind wir endlich da?

Es ist mir bewusst, dass diese Blog-Serie stellenweise etwas ausführlich ist. Es geht mir aber wirklich darum, Elm auch weniger erfahrenen Entwicklern näher zu bringen. Und die sind vielleicht hie und da dankbar um das zusätzliche Detail.

Leider werden die Posts dadurch auch sehr lange, wodurch sich die Modellierung des Spielsteins in AngularJS und ReactJS auf den nächsten Teil verschiebt.

Dieser wird jedoch bedeutend weniger ausführlich ausfallen. Aber auch mit der unverkennbaren Absicht, bei jedem sich bietenden Hinweis die Dominanz von Elm zu verkünden.

Mit den Steinen würde sie fertig werden, da ist sich Elm sicher. Trotzdem wird ihr leicht mulmig zumute beim Gedanken an die Martinsloch-Sage, die sie kurz vor Abreise gelesen hatte. Sollte es das sein, was die drei da oben erwartet?

ManuScripts: Wenn jemand eine Reise tut… Funktionale Programmierung mit Elm – Teil 3 – ReactJS mit TypeScript

20. Mai 2016
Manuel Baumann
3
AngularJs, Elm, Javascript, Reactive Programming, ReactJS

Sardona Welterbe

Eine Blog-Serie zum Vergleich von Elm, ReactJS und AngularJS anhand eines praktischen Beispiels.Hier geht es direkt zu [Teil 1, 2, 4, 5, 6]

Der dritte Reise-Teilnehmer: ReactJS mit TypeScript

React kann es kaum erwarten, den anderen von seinem neuen Release 15 zu erzählen. Endlich eine richtige Nummer! Elm lugt etwas neidisch von seinem Smartphone hoch.

Von den Dreien war React sicher der Kurligste. Klar, keiner von ihnen war ohne Ecken, aber React drückte sich stets in einem lustigen Dialekt aus, der sich zwar teilweise wie HTML anhörte, aber so richtig verstehen konnte ihn trotzdem niemand (JSX Syntax).

Ausser dieser einen, von der React so schwärmte: Babel. Die hatte ihn schon früh gut verstanden und mittlerweile ist aus der anfänglichen Romanze eine richtig Beziehung geworden.

ReactJS wurde entwickelt von Facebook und Instagram und stellt momentan die deutlichste Konkurrenz zu Google’s Angular dar. React ist zwar eine Bibliothek und Angular ein Framework, aber wir interessieren uns nur dafür, wie leicht damit Web-Anwendungen entwickelt werden können.

Architektonisch gesehen stellt wohl die Verwendung des virtuellen DOM (Document Object Model), und den damit verbundenen Konsequenzen den grössten Unterschied dar.

Ein Virtual DOM, also eine In-Memory-Darstellung des echten HTML-DOMs, bringt bei gleichzeitiger Vereinfachung der Programmierung einen enormen Geschwindigkeitsvorteil. Bei jeder Änderung wird das Framework angewiesen, alles neu zu zeichnen. Das klingt zwar ineffizient – und wäre es auch, würde man den DOM direkt bearbeiten – jedoch durch die Strukturierung der Applikation in möglichst viele Komponenten mit unveränderbarem Zustand (also Komponenenten, die von aussen mit Eigenschaften versehen werden, die sich nicht mehr ändern), kann das Framework effizient berechnen, welche tatsächlichen Änderungen sich durch eine Aktion im DOM ergeben würden und nur diese anwenden.

Diese Unveränderbarkeit (eben: immutability) führt dazu, dass das Framework dem Programmierer einen funktionalen Stil geradezu aufdrängt, weil es sich halt eben dafür eignet.

Gegenüber Angular fühlt sich ReactJS modularer an, sicher nicht zuletzt durch die HTML-ähnliche Tag-Syntax namens JSX, die innerhalb von Komponenten verwendet werden kann, um die View zu beschreiben und zu binden.

Ein Argument gegen ReactJS war in den Anfängen, dass dadurch ein zusätzlicher Kompiler (oder Transpiler) benötigt würde, um JSX nach javascript zu übersetzen.

Das Argument gilt aber nicht nur für JSX, sondern auch für jede andere Geschmacksrichtung von Javascript, sei es CoffeeScript, TypeScript oder ES6-nach-ES5-Übersetzung.

BabelJS ist ein derartiger Javascript Compiler, der möglichst viele verschiedene Formate und Sprachen nach Javascript übersetzen will (auch z.B. Stylesheets und Fonts), was Modularisierung erheblich vereinfacht.

Dieser “One-Compiler-To-Bind-Them-All” hat im Verlaufe seines Feldzuges zur Markt-Dominanz nebenbei einen JSX-Loader entwickelt und angeboten, welcher es geschafft hat, den Transpiler von Facebook zu verdrängen. Dieser hiess übrigens JSTransform und wird nicht mehr unterstützt. JSX-Fragmente werden heutzutage mit Babel übersetzt. (eine Abhängigkeit und ein Segen).

Es sei denn, und das ist in diesem Beispiel so, man verwendet TypeScript, dann sieht alles anders aus. Eine Alternative zu TypeScript wäre Flow von Facebook (welches dann auch wieder mit Babel zusammenarbeitet), aber da Angular2 schon TypeScript einsetzt, beschränken wir uns darauf.

Gut gepackt ist halb gewandert

Im nächsten Abschnitt wird ohne viel Erläuterung eine ReactJS/TypeScript Entwicklungs-Umgebung zusammengestellt. Das Vorgehen kann natürlich auch für Angular-Entwicklung angewandt werden und grössere Projekte sollten auf jeden Fall Gebrauch machen von den vorgestellten oder ähnlichen Werkzeugen.

Zwischen der ersten Fassung und der Überarbeitung dieses Blogposts haben sich diverse Anpassungen durch neue Versionen ergeben (sowohl für React, als auch für TypeScript).

mkdir react-anagram && cd react-anagram && npm init -f && git init

Core-Bibliotheken installieren:

npm install --save react react-dom

Wie erwähnt wollen wir TypeScript auch für die Applikation mit React verwenden, um Elm in möglichst Nichts nachzustehen:

npm install -g --save typescript 
npm link typescript
npm install typings --global
typings install debug --save

typings search react
typings install dt~react --global --save
typings install dt~react-dom --global --save
cat typings/index.d.ts

TypeScript-Compiler-Konfiguration (tsconfig.json):

{ 
  "compilerOptions": {
    "jsx": "react",
    "module": "commonjs",
    "noImplicitAny": true,
    "outDir": "./build/",
    "preserveConstEnums": true,
    "removeComments": true,
    "target": "ES5"
  },
  "exclude": [
    "node_modules",
    "typings/browser.d.ts",
    "typings/browser"
  ]
}

Der Inhalt der Datei wurde bereits im letzten Teil erklärt, Schlüsselzeile hier ist der Eintrag “jsx”: “react” , der den Kompiler anweist, den jsx -Syntax zu erlauben innerhalb von .tsx -Dateien.

Die folgende Html-Datei (index.html ) soll als Einstiegspunkt dienen:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello, React!</title>
  </head>
  <body>
    <div id='main'></div>      
    <script type="text/javascript" src="build/bundle.js" charset="utf-8"></script>
  </body>
</html>

Dafür brauchen wir aber einen Webserver und ein Tool, dass uns alle Source-Files in ein Bundle packt, also zum Beispiel das hervorragende webpack zusammen mit dem webpack-dev-Server

npm install --save-dev webpack webpack-dev-server ts-loader

Welcher konfiguriert wird mit (webpack.config.js ):

var path = require("path");

var config = {
  entry: ["./src/Hello.tsx"],
  output: {
    path: path.resolve(__dirname, "build"),
    filename: "bundle.js"
  },
  resolve: {
    extensions: ["", ".ts", ".tsx", ".js"]
  },
  module: {
    loaders: [
    {
      test: /\.tsx?$/,
      loader: "ts-loader",
      exclude: /node_modules/
    }
    ]
  }
};

module.exports = config;

Webpack wird angewiesen, von der Datei ./src/app.ts  ausgehend, allen abhängigen Code in die Datei bundle.js  im Verzeichnis build  zu packen. Dabei sollen Dateien mit den unter resolve  registrierten Endungen erkannt werden. Dateien die in .ts  oder .tsx  enden, sollen mit dem ts-loader geladen, bzw. übersetzt werden.

Da es aber noch keine Datei ./src/app.ts gibt, müssen wir die noch bereitstellen:

import * as React from "react";
import * as ReactDOM from "react-dom";

import Hello from "./Hello";

ReactDOM.render(<Hello name="React" />, document.getElementById("main"));

Und natürlich unsere erste und einzige Komponente (Hello.tsx):

import * as React from "react";

interface HelloProps {
  name: string;
}

class Hello extends React.Component<HelloProps, {}> {
  render() {
    return <div>Hello, {this.props.name}</div>;
  }
}

export default Hello;

Schuhe schnüren, los geht’s

`webpack-dev-server`

(Dies startet einen Entwicklungs-Webserver, der bei Änderungen die Dateien neu übersetzt und bundelt. Im build-Verzeichnis liegt nun ein File namens bundle.js , welches (unkomprimiert) etwa 675 KB gross ist. Für den produktiven Einsatz würde webpack mit Plugins versehen für minification und uglyfication, mehr dazu jedoch ein anderes Mal)

Der Index wird unter http://localhost:8080 ausgeliefert.

Für bessere Fehlermeldungen im Browser, und die Anzeige der Komponenten in ihrer Baumstruktur, steht das Plugin “React Developer Tools” bereit.

Die endgültige package.json -Datei sieht so aus (etwas aufgeräumt):

{
  "name": "react-anagram",
  "version": "1.0.0",
  "scripts": {
  },
  "author": "Manuel Baumann <manuel.baumann@noser.com>",
  "dependencies": {
    "react": "^15.0.2",
    "react-dom": "^15.0.2"
  },
  "devDependencies": {
    "ts-loader": "^0.8.2",
    "typescript": "^1.8.10"
  }
}

Elm ist etwas gelangweilt, während die anderen zwei sich intensiv über Build und Bundling, TypeScript und Babel, ES2015 und ES2016 unterhalten. Alles Dinge, über die sich Elm eigentlich nicht mehr viele Gedanken machen will.

Aber da sie sich sehr für den virtuellen DOM interessiert, den sie React damals abgeschaut hatte, hört sie trotzdem aufmerksam zu. Denn wenn die beiden über den virtuellen DOM zu debattieren anfangen, könnte es lustig werden.

Für den Fall der Fälle navigiert sie mit dem Browser auf ihrem Smart-Phone mal zu dieser Adresse: https://auth0.com/blog/2016/01/07/more-benchmarks-virtual-dom-vs-angular-12-vs-mithril-js-vs-the-rest/

Damit wären alle Wandervögel vorgestellt und die Grundlagen für dieses Experiment geschaffen. Im nächsten Teil fangen wir damit an, die Datenstrukturen für den Anagrammerator aufzubauen.

 

1234

Tag Cloud

.NET android Angular AngularJs Arduino ASP.Net automated testing Azure Big Data C# C++ Cloud continuous integration Elm Embedded Führung gRPC Internet of Things IoT Java Javascript M2M OWASP Projektmanagement protobuf Python Raspberry Pi Reactive Programming REST Scrum Security Softwarequalität SPA Testen testing Testmanagement Teststrategie UX Visual Studio WebAPI windows WPF Xamarin Xamarin.Android Xamarin.Forms

Archive

Current Posts

  • Akzente setzen mit der Android Splash Screen API unter .NET MAUI
  • Do You have Your Personal Space?
  • Automated provisioning with ARM Templates
  • Asynchrone Beobachtungen und Versprechungen in Angular
  • Simplify Your Automated Tests With Fluent Syntax

Last Comments

  • Hans Reinsch bei Der Safety-Plan: Die wichtigsten Antworten mit Checkliste
  • George H. Barbehenn bei Modeling Optocouplers with Spice
  • Noser Blog Touch-Actions in Xamarin.Forms - Noser Blog bei Mach mehr aus Animationen in Xamarin.Forms mit SkiaSharp
  • Noser Blog Focus on the Secure Storage service of Trusted Firmware (TFM) - Noser Blog bei First run of the Trusted Firmware (TFM) application
  • Noser Blog First run of the Trusted Firmware (TFM) application - Noser Blog bei Focus on the Secure Storage service of Trusted Firmware (TFM)

Popular Posts

Xamarin.Android Code Obfuscation

6 Comments

ManuScripts: Wenn jemand eine Reise tut... Funktionale Programmierung mit Elm - Teil 1 - Aufbruch

5 Comments

ManuScripts: Wenn jemand eine Reise tut... Funktionale Programmierung mit Elm - Teil 2 - Kein Picknick

4 Comments

Contact us

  1. Name *
    * Please enter your name
  2. Email *
    * Please enter a valid email address
  3. Message *
    * Please enter message
© 2013 NOSER ENGINEERING AG. All rights reserved. Datenschutz | Cookie-Richtlinie