Upgrade to Pro — share decks privately, control downloads, hide ads and more …

No-Framework Microfrontends statt Frontend-Mono...

No-Framework Microfrontends statt Frontend-Monolithen

Unternehmen entwickeln ihren Webauftritt oft in Teams, die jeweils einen Teil der Funktionalität beisteuern. Ein Team baut das Anwenderprofil, ein anderes den Warenkorb, ein drittes Team die Bestellseite. Bald zeigen sich Überschneidungen bei nicht trivialen Use Cases. Die Adressänderung sollte im Anwenderprofil gleich funktionieren wie im Bestellformular. Klassisch hätten wir Komponenten für ein bevorzugtes Framework gebaut, eine Angular-Adressdirektive zum Beispiel. Mittlerweile entpuppt sich dieser Weg als Sackgasse. Um unseren Adressflow um QR-TAN zu erweitern, müssen wir alle Anwendungen neu ausrollen, und wir können ihn nicht mit neueren Frameworks einsetzen. Auch die Koexistenz von Anwendungen im selben Framework auf einer Seite wird zum Problem, sobald ein Team das Framework updaten muss, das andere aber nicht upgraden kann. Die Session zeigt, wie Micro Frontends mit No-Framework JavaScript dieses Problem lösen. Mit Tools wie sveltejs oder Stencil.js entstehen schlanke Micro-Frontend-Komponenten, die im Browser kein Framework benötigen, sondern auf das reine DOM API oder den Web-Component-Support des Browsers setzen, und deshalb mit anderen Anwendungen auf derselben Seite koexistieren oder als Teil einer frameworkbasierten Anwendung laufen können. Entwickler schreiben das Micro Frontend als MVC-Anwendung, und ein Compiler erzeugt daraus JavaScript-Komponenten, die im Browser kein Framework brauchen, und die wir getrennt voneinander updaten können.

Avatar for Dietrich Schulten

Dietrich Schulten

April 25, 2018
Tweet

Other Decks in Programming

Transcript

  1. INTEGRIERE SPAS AUF DATEN INTEGRIERE SPAS AUF DATEN SPA Framework,

    jQuery viele unterschiedliche ReST Ressourcen nicht-triviale Flows und Visualisierungen mehrfach benötigte Funktionalität wir Fragen auf
  2. — Gustaf Nilsson Kotte How can we develop websites where

    the different parts of the page are developed by different teams?
  3. NO-FRAMEWORK NO-FRAMEWORK MICROFRONTENDS MICROFRONTENDS Integriere auf UI, nicht auf Daten

    Verwende kein Framework im Browser Unabhängig updatebare Microfrontends Trade-off, nicht Silver Bullet Bewusster Einsatz von Constraints
  4. ARCHITECTURAL CONSTRAINTS ARCHITECTURAL CONSTRAINTS Kein Browser Framework Standard APIs +

    Transpiler + Po(n/l)yfill Benutze zweckgebundene Bibliotheken, treeshake Nur temporäres Eigentum an der Seite Striktes CSS Scoping Baue wegwerfbar
  5. KONSEQUENZ KONSEQUENZ Keine Versionskonflikte zwischen Microfrontends App verbessert sich mit

    Browser Updates Kleine App-Bundles Keine Konflikte mit Frameworks in der Seite Keine CSS Störungen Team Autonomie
  6. SVELTE COMPILER SVELTE COMPILER Erzeugt MVC Javascript beim Bundling Plain

    Component zum Einbinden in die Seite Web Component Server-Side Component mit Hydration (SSR) Debugging unproblematisch: Sourcemaps Radikal einfaches Komponenten-Konzept
  7. SVELTE COMPONENT SVELTE COMPONENT einzelne HTML Datei aus: 1. Markup:

    HTML + Svelte Tags 2. <script>: Data & Behaviour 3. <style>: Component style
  8. COMPONENT MARKUP COMPONENT MARKUP Svelte Tags in geschwei en Klammern

    binden Daten HelloWorld.html index.html <h1>Hello {name}</h1> <script src="bundle.js"> <main> <script> const helloWorld = new HelloWorld({ target: document.querySelector("main"), data: { name: 'World' } }); </script>
  9. COMPONENT DATA COMPONENT DATA bilden Zustand der Komponente Default data()

    und computed <h1>Hey {name}, you have {count} friend{count!==1 ? 's': ''}</ <!-- two-way binding with 'bind:' --> <input bind:value="name" placeholder="enter your name"> <script> export default { data() { return { name: 'Sheldon', friends: [] } }, computed: { count: ({ friends }) => friends.length } </script> 1 2
  10. KONTROLLSTRUKTUREN IM KONTROLLSTRUKTUREN IM MARKUP MARKUP Markup repräsentiert den Zustand

    {#if count === 0}<div>no friends</div> {:elseif count == 1} <div>one friend</div> {:else} <div>lots of friends</div> {/if} {#each friends as friend} … {/each} {#each friends as friend, index} … {/each} {#await promise} wait for it... {:then answer} the answer is {answer} {:catch error} my apologies, no answer today {/await}
  11. KOMPONENTEN SCHACHTELN KOMPONENTEN SCHACHTELN Gadget.html <div> <Widget/> </div> <!-- import

    and declare nested components --> <script> import Widget from './Widget.html'; export default { components: { Widget } }; </script> 1 2 3
  12. COMPONENT BEHAVIOUR COMPONENT BEHAVIOUR Eigene Methoden und Component API on:click

    directive <script> ... methods: { fetchFriends() { fetch('http://api.example.com/friends') .then(response => response.json()) .then(friendsJson => { const { friends } = this.get(); friends.push(...friendsJson); this.set({ friends }); } ... </script> 1 2 3 <button on:click="fetchFriends()" />
  13. COMPONENT STYLE COMPONENT STYLE Compiler erzeugt strikt gescopede Selektoren Widget.html

    Browser runtime <style> p { color: teal } </style> <p class="svelte-kjrgyl">scoped style</p> ... p.svelte-kjrgyl { color: teal; }
  14. STYLES IN SVELTE STYLES IN SVELTE Compiler entfernt ungenutztes CSS

    Hängt style an <head> oder generiert CSS Datei Unterstützt preprocessors (sass… )
  15. ELTERN AN KIND: INITIAL ELTERN AN KIND: INITIAL HTML Attribute

    werden Daten der Kind-Komponente Widget.html <div> <Widget foo bar='static' baz='{dynamic}'/> <button on:click='set({ dynamic: 'new baz' })'>New baz</butt </div> <script> import Widget from './Widget.html'; export default { data () { return { dynamic: 'this can change' } }, components: { Widget } }; </script> <p>foo: {foo}</p> <!-- true --> <p>bar: {bar}</p> <!-- static --> <p>baz: {baz}</p> <!-- this can change -->
  16. ELTERN AN KIND: REFS ELTERN AN KIND: REFS Eltern kommunizieren

    über Kind-Ref <Widget ref:myWidget/> <button on:click="letsPlay()">Widget, turn somersaults!</butto <script> import Widget from './Widget.html' export default { methods: { letsPlay() { this.refs.myWidget.somersault(3); } }, components: { Widget } } </script> 1 2
  17. ELTERN AN KIND: SLOTS ELTERN AN KIND: SLOTS Eltern füllen

    Slots, benannte Slots möglich App.html Widget.html <div> <Widget> This will appear <strong>inside</strong> widget. <sub slot="copyright">(c) Acme 2018</sub> </Widget> </div> <h1>Widget</h1> <slot>Nothing to see here</slot> <div> <slot name="copyright">no copyright</slot> </div>
  18. KIND AN ELTERN: EVENTS KIND AN ELTERN: EVENTS Kinder benachrichtigen

    Eltern Widget.html App.html <button on:click="fire( 'myEvent', { foo: true } )" <Widget on:myEvent="wiggle(event.foo)"/> <script> export default { methods: { wiggle(foo) { … executed when Widget fires myEvent …
  19. WHAT’S NEXT WHAT’S NEXT Manifest: Elisabeth Engel’s reading list http://svelte.technology

    http://github.com/escalon/microfrontends https://microservice-websites.netlify.com/ @_lizzelo_
  20. STENCIL COMPONENT STENCIL COMPONENT import { Component, Prop } from

    '@stencil/core'; @Component({ tag: 'my-first-component', styleUrl: 'my-first-component.scss' }) export class MyComponent { @Prop() name: string; render() { return ( <p>My name is {this.name}</p> ); } }
  21. COMPILE OPTIONEN COMPILE OPTIONEN Bundling je nach Einsatzzweck pkg.browser: iife,

    umd pkg.module: es6 Modul pkg.main: node pkg.svelte: für component import pkg.ce: custom-element
  22. HELPERS FÜR DATEN HELPERS FÜR DATEN <p>The time is {leftPad(minutes,

    2, '0')</p> <script> <-- e.g. node module from package.json dependencies --> import leftPad from 'left-pad'; export default { helpers: { leftPad }, data() { return { minutes: 2 } </script> 1 2 3
  23. NACHTEILE NACHTEILE ES2015+ Javascript und DOM API Know-How nötig Erhöhter

    Aufwand für Paketierung Mehr kleine Bundles Optimierung von Backend Calls erschwert