Přejít k navigační liště

Zdroják » Webdesign » Merkur aneb jak vzniká mikrofrontend framework

Merkur aneb jak vzniká mikrofrontend framework

Články Webdesign

Mikrofrontendy jsou zajímavá adaptace konceptu microservices pro potřeby frontendového vývoje. Podívejte se, co to v praxi obnáší a proč jsme se v Seznam.cz rozhodli vyvinout náš vlastní microfrontend framework, Merkur.

Nálepky:

Mikro-co?

Mikrofrontendy, jinak taky frontendové mikroslužby, jsme my frontendisté tak trochu odkoukali od backendu. Představa je asi taková:

  1. Frontend se rozdělí na samostatné uzavřené celky (komponenty, widgety),
  2. určí se způsob, jak budou komunikovat mezi sebou a s backendem,
  3. vytvoří se kompoziční vrstva, která složí všechny dílky dohromady tak, aby to všechno společně fungovalo.

Jestli se teď drbete na hlavě a ptáte se, k čemu je to všechno dobré, odpovědi jsou podobné jako u backendových mikroslužeb: třeba jednodušší odlaďování menšího balíku kódu, opakované použití prvků napříč projekty, nebo menší vývojové týmy. Na druhou stranu, mikroslužby nejsou samospásné a složitost, kterou s sebou nesou, nemusí vždy vyvážit jejich výhody.

O mikrofrontendech jsme u nás začali vážně uvažovat v momentě, kdy jsme začali pracovat na jednotné ovládací liště pro Seznamácké služby. Naše weby běží na různých platformách – React, IMA.js (izomorfní JavaScript framework postavený na Reactu, který můžete znát ze seriálu tady na Zdrojáku), nebo přímo čistý JavaScript. A to mluvíme jen o frontendu – backend je kapitola sama pro sebe. Samostatný modul, nezávislý na technologiích hostující aplikace, by nám značně zjednodušil život. 

Když jsme se začali rozhlížet po existujících možnostech, rychle jsme zjistili jednu věc: protože mikrofrontendy jsou spíš koncept než vývojový vzor, zdá se, že existuje sto a jedno řešení, jak je vytvářet. Dobrý přehled různých přístupů nabízí například Florian Rappl ve článku 6 Patterns for Microfrontends.

Při bližším pohledu se ale ukázalo, že většina frameworků nesplňuje naše potřeby. Nemůžeme použít nginx k embedování našich mikrofrontendů (jak to navrhuje Micro Frontends project), nemůžeme přejít na GCloud nebo Amazon S3 (OpenComponents), nemůžeme zcela rozdělit naše weby na mikrofrontendy (Piral). A u většiny ostatních pak chyběl server-side rendering, bez kterého se kvůli SEO a výkonnosti neobejdeme.

Nakonec jsme se rozhodli, že nejjednodušší bude postavit si řešení vlastní: Merkur.

Po vlastní ose

Merkur widget v akci můžete vidět na této ukázce. Chcete-li se podívat, jak to vypadá takříkajíc pod kapotou, použijte @merkur/create-widget, který generuje vše potřebné pro provoz Merkur widgetu. Nejjednodušší je spustit ho pomocí npx: npx @merkur/create-widget my-first-widget.

Co pro vás @merkur/create-widget nachystá? Merkur jako takový (@merkur/core), generování HTML na serveru i klientu (na výběr je několik knihoven jako Preact nebo Hyper) a nakonec obsluhu serverové části widgetu (v současnosti Express). Jak HTML renderer, tak server je možné vyměnit za jinou knihovnu – jestli chcete, můžete mít Merkur widget postavený na Vue a obsluhovaný třeba Fastify. 

Fungování Merkuru nejvíc připomíná to, co popisuje Zack Jackson ve svém článku Micro-frontend Architecture: Replacing a Monolith from the Inside Out. Vypadá to nějak takhle:

  1. Hostující aplikace zavolá Merkur widget API v průběhu vykreslování na serveru. Jako props předá všechny informace potřebné pro první vykreslení widgetu.
  2. Widget se inicializuje a provede své vlastní serverové vykreslení.
  3. Widget API vrátí widget jako JSON serializovaný objekt se všemi daty – názvem widgetu, číslem verze, props, state widgetu, a především vyrenderovaného HTML a odkazy na skripty a styly.
  4. Hostující aplikace zahrne skripty, styly a vyrenderované HTML do vygenerovaného kódu stránky.
  5. V prohlížeči se widget oživí. Protože jsou widgety pojmenované a verzované, je možné jich provozovat na jedné stránce víc zároveň.
  6. Widget teď běží v hostující aplikaci. Komunikace je možná prostřednictvím props widgetu (host => widget) a buď nativními DOM eventy, nebo Merkur eventy na widgetu (widget => host). 

Mimochodem, server-side rendering je volitelný. Stejně jako velká část Merkuru, když už jsme u toho; základ Merkuru je minimální, většinu funkcionality obstarávají pluginy.

Jako ukázka, definice jednoduchého Counter widgetu vypadá následovně

import { componentPlugin } from '@merkur/plugin-component';
import { eventEmitterPlugin } from '@merkur/plugin-event-emitter';
import { errorPlugin } from '@merkur/plugin-error';
import pkg from '../package.json';
import View from './component/View';

export const widgetProperties = {
  name: pkg.name,
  version: pkg.version,
  $plugins: [componentPlugin, eventEmitterPlugin, errorPlugin],
  View,
  assets: [
    {
      name: 'polyfill.js',
      type: 'script',
    },
    {
      name: 'widget.js',
      type: 'script',
    },
    {
      name: 'widget.css',
      type: 'stylesheet',
    },
  ],
  onClick(widget) {
    widget.setState({ counter: widget.state.counter + 1 });
  },
  onReset(widget) {
    widget.setState({ counter: 0 });
  },
  load(widget) {
    // We don't want to set environment into app state
    // eslint-disable-next-line no-unused-vars
    const { environment, ...restProps } = widget.props;

    return {
      counter: 0,
      ...restProps,
    };
  },
};

Zprávy z první linie

Do nynějška jsme vytvořili 5 widgetů o různé složitosti. Bude potřeba ještě nějaký čas na plné vyhodnocení všech pozitiv a negativ, ale minimálně z hlediska vývoje se s Merkurem pracuje příjemně. 

Zaprvé, widgety jsou malinké. V porovnání s kódem našich webů je příjemná změna hledat chybu v něčem, co má sotva 15 tisíc řádků – a to včetně samotné knihovny!

To také dává prostor k určitému experimentování. Samozřejmě s mírou; nedokážu si představit větší noční můru, než spravovat armádu widgetů, který každý běží na jiné technologii. Ale i tak jsme našli pár věcí k vyzkoušení. Ne všechno se promítne zpět do našich běžných služeb (i když se nám líbily React hooky, do současné codebase postavené na třídách to úplně nepasuje), ale některé určitě ano (přejít na Webpack je rozhodně v plánu).

Ne všechno bylo samozřejmě “sluníčkové”.

Postavit vlastní nástroj doopravdy znamená ho postavit – žádná dokumentace, žádné “best practices”, na všechno si musíte přijít sami. Nenarazili jsme naštěstí na žádný kritický problém, ale pár nepříjemných momentů jsme zažili.

Kromě věcí týkajících se přímo Merkuru jsme se potýkali i s problémy vycházejícími přímo z mikrofrontendů jako takových. Nevýhoda uzavřených jednotek je zvýšená komplexnost systému jako celku. Nebo jinak: jednotlivé díly jsou jednoduché, ale jejich propojení už tak úplně ne. Nejvíc se to projevuje při odlaďování chyb. Tam, kde byla doteď jen jedna aplikace, jejíž kód a chybové hlášky bylo potřeba sledovat, teď jsou dvě. Připočtěte k tomu několik vrstev integračních modulů (kterým se při použití na více webech nevyhnete) a o pár dlouhých večerů je postaráno.

Všeobecně vzato to ale vidíme optimisticky. Nějakým problémům se v začátcích projektu vyhnout nedá a těch pár, se kterými jsme se setkali, nás od mikrofrontendů neodradilo. Takže Merkur v Seznamu určitě plánujeme používat dál. 

Pokud vás Merkur zaujal, tak do budoucna plánujeme napsat něco o našem posledním projektu, vizualizačních widgetech pro senátní a krajské volby z října 2020. Mezitím podívejte na dokumentaci a GitHub – Merkur je OpenSource a spolupráci určitě vítáme. 

Komentáře

Subscribe
Upozornit na
guest
16 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Mlocik97

Tá definice o mikrofrontende mi znie nie len prapodivná, ale není to vlastne definícia pre komponentový prístup, aký je bežný vo front-ende už snáď 10 rokov? A že „Při bližším pohledu se ale ukázalo, že většina frameworků nesplňuje naše potřeby.“ tak to ani Svelte? Lebo ten by som povedal že to splňuje viac než dobre.

Peter

Ja robim mikfronden apky nejako takto https://gitlab.com/peryl/happ

Slavek

Ano, to je pravda. Urcite je to jeden z dalsich pristupu pro SPA. Dival, jsem se na poslany link, ale SSR demo jsem tam nenasel. Asi se jenom spatne divam.

L.

Pokud by ty jednotlivé widgety byly ve stejné technologii, vytvářené pokud možno stejným týmem pak ano, dal by se na to použít běžný komponentový přístup.

Microfrontend pattern se používá hlavně v situacích, kde je potřeba poskládat web z částí tvořených v různých technologiích (třeba kvůli přechodu na novou technologii, nebo protože ty části tvoří různé týmy používající různé technologie). A dále je častý požadavek, aby ty komponenty byly server-side-rendered kvůli SEO.

Ten „framework“ se pak nestará o samotné vykreslení komponent, ale o posbírání server-side vykreslených widgetů z jejich API a poskládání do funkční stránky, tedy o úplně jinou úlohu, než kterou řeší Svelte / React / Angular / Vue / ..

ja

Ano, je to znát, Seznam se stává pomalejším, uživatelsky méně přívětivým, náročným na prostředky. To je daň za použití takových fíčur.

Mlocik97

@L. tak u Svelte to nesúhlasím, Svelte práveže má všetko čo ste popísali, vie to SSR, môžeš v tom použiť z ľubovolných technológií/frameworkov vytvorené komponenty, môžeš to spojiť a vykresliť.

L.

Takže Svelte umí out-of-the-box při SSR přes nějaké API (jaké?) načíst kus stránky vyrenderované jiným frameworkem a umístit ho do renderované stránky včetně korektního napojení skriptů a CSS?

Martin

Zajímavý projekt.

Nechápu použití čistého js. Kdyby to byl nějaký hobby projekt, tak proč ne, ale u projektu, který bude mít pravděpodobně značný scope nepoužít typescript – to mi hlava nebere.

Máte k tomu nějaký důvod?

Mlocik97

@L. áno, vie to.

Slavek

Ono to skoro vypadá jako boj mezi Svelte a Merkur, ale to bych řekl, je špatné porovnání. Spíše je to tak, že je možné použít Svelte s Merkurem stejně jako ostatní předpřipravené knihovny. Integrující aplikaci (napsané v PHP, Node, Python, atd.) je jedno jestli je widget psaný v Preactu, Svelte, v čistém JS nebo dokonce na klientu bez JS.

Slavek

Na HP Seznamu Merkur použitý není. Na jakém zařízení a prohlížeči zaznamenáváte problém?

Tonda Panděras

Jdete pozde chlapci a devcata. Renderovani pres API je dead, ted frci websockets! 8-) https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets

Slavek

@tonda  Myslim, si ze zalezi pripad od pripadu, ale treba React predstavil Server Components, kde pouziva API. Urcite neni problem Merkur upravit na WebSocket pokud by bylo potreba. Podle clanku mate v Merkuru taky vsechno na jednom miste. Je mozne se pripojit primo do DB nebo konzumovat nejake API. Zalezi na potrebach widgetu ;-)

Slavek

Planujem do budoucna zlepsit podporu pro TypeScript, ale zasadne by to tedka nemelo branit pokud by nekdo chtel psat widget v TypeScriptu. Nemeli jsme zasadni duvod ho pouzit. Proc si myslite, ze je to tak dulezite?

Martin

Jak velky tym se na tomto projektu podili ve fazi vyvoje i potom v ramci nasledne udrzby?

Slavek

Ve fazi vyvoje se podileli tri vyvojove tymy na vyvoj ctyr widgetu v jednom monorepu, ktere jsou tedka v maintenance rezimu a nepotrebovali behem roku zadny zasah. Jeden widget v samostatnem repozitari byl pod aktivnim produktovym vyvojem a spravou jednoho vyvojare a nove jiz celeho tymu. Vsechny widgety jsou implementovane na projektech, ktere jsou pod aktivnim vyvojem a nasazovane minimalne co sprint.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.