tutory

Herunterladen
Keine Hooks, kein Hype – nur Ja­va­Script
wie wir eine kom­ple­xe Webapp mit mi­thril.js und funk­ti­o­na­len Pat­tern ge­baut haben
Wer sind wir?
  • tu­to­ry.de – Ma­te­ri­al­er­stel­lung für den Un­ter­richt

  • Ar­beits­blät­ter als PDF oder in­ter­ak­ti­ves Ar­beits­blatt

  • Ent­wick­lung 8 Jahre

Was kann tu­to­ry.de
  • Gra­fik­ori­en­tier­ter Edi­tor für (päd­ago­gi­sches) Ma­te­ri­al

  • Drag- & Drop-​Funktionalität

  • Ex­port als PDF

  • Di­gi­ta­les Ar­beits­blatt (mit Selbst­kon­troll­mög­lich­kei­ten)

  • Kom­pa­ti­bi­li­tät mit Desk­top und iPad

  • Keine In­stal­la­ti­on er­for­der­lich, je­doch als Electron-​App ver­füg­bar

Demo
Co­ding Phi­lo­so­phie
  • KISS - Keep it stu­pid simp­le

  • Funk­ti­o­nen > Me­tho­den

  • POJO > Klas­sen

  • wenig Ab­hän­gig­kei­ten

  • mög­lichst kein Frame­work/Lib-​spezifischer Code

  • Modul-​lokale Va­ri­a­blen ftw!

  • Tes­ten wo sinn­voll aber kein Muss

  • star­ke Ko­he­si­on (auch auf Da­tei­e­be­ne)

    • zu­sam­men­ge­hö­ren­de Da­tei­en lie­gen in glei­chen Ord­nern (page.js, page.test.js, page.styl)

  • Ver­mei­dung von Higher-​Order Funk­ti­o­nen

  • Fokus auf De­bug­ga­bi­li­ty

  • kein this – kein pro­to­ty­pe - kein class!

Ar­chi­tek­tur
Front­end
Front­end

REST-​API, SSR, As­sets

nginx
node.js
post­g­res
DB
redis (keydb)
pup­pe­teer
PDF
Stack
  • Ba­ckend: Ex­press/Koa

  • Front­end: mi­thril.js

  • Data-​Layer: mo­delz.js (Front­end und Ba­ckend)

  • ORM/DB: hedy.js/Knex

  • i18n: trans­la­te.js

  • PDF: pup­pe­teer

  • tests: mocha + chai (ak­tu­ell > 2700 Unit-​Tests)

  • css stylus.lang

Warum mi­thril.js?
  • GTD-​Framework

  • braucht kei­nen spe­zi­el­len Da­ten­lay­er (redux, streams, ob­ser­ver­va­bles)

  • kein XML 🎉

  • mi­ni­ma­le stab­lie API (keine stän­di­gen Re­wri­tes oder Re­fac­to­rings nötig)

  • man ver­steht es in 1 min, kann es in 1h und be­herrscht es in einem Tag



let c = 0
const app = {
view: () => [
m("h1", [
"Say ",
m("button", { onclick: () => c++ },'👋'),
" to Mithril!"
]),
m("div", c, '👋 sent.')
]
}
// Mount component into #app
m.mount(document.body, app);

Frame­work

Major-​API-​Änderungen 5 Jahre

Be­mer­kung

React

3 (Class → Hooks → Ser­ver Com­pon­ents)

Vue

2 (Op­ti­ons → Com­po­si­ti­on API)

Svel­te

2 (Syn­tax/Com­pi­ler)

Mi­thril

0 ✅

sta­bil seit 2016

Quel­le ChatGPT 🙈
mo­delz.js
  • Schema-​Definition

  • Da­ten­kon­sis­tenz ohne Type­script/Klas­sen

  • Pri­mi­ti­ve + Kom­ple­xe Da­ten­ty­pen (Nesting)

  • Com­pu­ted Pro­per­ties

  • Se­ri­a­li­sie­rung/Par­sing

  • Caching

  • Ser­ver/Client-​Side



const scheme = modelz()
const createUser = schema({
firstName: 'string',
lastName: 'string',
fullName: {
get: u => `${u.firstName} ${m.lastName}`,
set: (u, value) => {
const [firstName, ...lastName] = value.split(' ')
u.firstName = firstName
u.lastName = lastName.join(' ')
},
cacheKey: ['firstName','lastName']
}
})
He­dyORM – Im­muta­ble Query Buil­der
  • ba­sie­rend auf knex.js Query-​Builder

  • ein­fa­che API

    • ein­fa­che Dinge (CRUD) sind tri­vi­al

    • kom­pli­zier­te Dinge (z. B. join-​filters), soll­ten je­doch mög­lich sein

  • kon­sis­ten­te Er­geb­nis­se (glei­che Spal­ten ohne SEL­ECT *)

  • de­fi­nier­te Mu­ta­ti­o­nen (schreib­ba­re Spal­ten de­fi­nier­bar)

  • Crea­te/Up­date/Delete-​Hooks (z. B. zur Cache in­va­li­die­rung)

  • Re­la­ti­o­nen via Sub-​Queries

  • kom­bi­nier­te PKs, JSONP-​Where, Backend-​agnostisch

const userQuery = store('user', {
afterDelete: invalidateUser,
afterPut: invalidateUser,
afterPost: invalidateUser,
})
.columns(['id', 'firstname', 'lastname']),
.hasMany(worksheetQuery)
.hasManyThrough(groupQuery, groupUserQuery)
.map(userModel)
const user = await userQuery.get(userId)
const users = await userQuery
.whereLike({ firstname: '%Ada%' })
.load()
await userQuery.put(userId, {
firstname: 'Konrad'
})
i18n via trans­la­te.js
  • min­mal (~100loc)

  • mäch­tig

    • ein­fa­che Strings

    • Strings mit Er­set­zun­gen

    • Plu­ral­for­men

    • subKey-​Verarbeitung

    • Ali­a­se

    • Dom-​Knoten als Er­set­zun­gen

  • schnell

  • über­setz­te URLs

t('tree') //=> 'Baum'
t('trees', 1) //=> '1 Baum'
t('trees', 2) //=> '2 Bäume'
t('places.with.trees', 2, { place: 'Leipzig' }) // => 'Leipzig hat 2 Eichen'
const button = m('button', 'Knopf')
t.arr('push.the.button', { button }) //=> ['Drücke den ', button, '!']
Ge­meis­ter­te Her­aus­for­de­run­gen in 7 Jah­ren
  • lang­sa­me JS-​Buildzeiten (brow­se­rify) → Um­stel­lung auf es­build

  • PDF Ge­ne­rie­rung ohne Mehr­auf­wand → SSR + Pup­pe­teer (vor­her wkhtml2pdf)

  • Kon­sis­ten­te PDF-​Generierung über Re­leases hin­weg → WS-​Compare

  • Kon­sis­ten­te Aus­ga­be über Brow­se­ren­gi­nes → Inden­ti­fi­ka­ti­on und Ver­mei­dung der Ur­sa­chen (z. B. line-​height-​Behandlung)

  • Text­for­ma­tie­rung + WY­SI­WYG → zu­nächs­te ei­ge­ne markup-​Sprache (edu­Mark), spä­ter In­te­gra­ti­on von Pro­s­eMir­ror (inkl. eduMark-​Konverter)

  • Infra: Vir­tu­el­ler Ser­ver (uber­space) → Bare Metal (hetz­ner) → Do­cker + Cloud (hetz­ner)

  • Daten-​Migration → Mi­gra­ti­on on-​the-​fly

Of­fe­ne Her­aus­for­de­run­gen
  • com­mon­js/esm Um­stel­lung

  • CSS-​Organisation (ak­tu­el­le stylus aber ohne klare struk­tur)

  • Kon­sis­ten­tes Formular-​Handling

  • Mul­ti­play­er

  • Off­line Sup­port (via Ser­vice Workers)

  • Über­gang zur Post-​A4-Welt

Pro­ble­me die wir nicht haben
  • Framework-​Updates/Re­fac­to­rings

  • kom­ple­xe Build-​Pipelines

  • Li­mi­tie­run­gen durch Frame­works/Libs (Kampf wir gegen Frame­work)

  • Ren­de­ring Performance-​Probleme

  • Mehr­auf­wand einer Front­end/Backend-​Trennung

    • se­pa­ra­te De­p­loy­ments

    • Dop­pel­struk­tu­ren im Code

    • Zeit-​Abhängigkeiten

  • De­bug­ging­pro­ble­me durch kom­pi­lier­ten Code

  • Over-​Engineering & Tooling-​Explosion

  • Ab­hän­gig­keit von Ökosystem-​Tempo

  • Pro­ble­me mit State-​Magie



Danke, gibt es Fra­gen oder An­re­gun­gen?

tutory

von Stephan Hoyer

Lizenzhinweis

Alle Bestandteile dieses Materials sind frei oder unlizenziert. Klicken Sie auf einen Baustein, um die Lizenz zu sehen.
x