Hopp til innhold

Infrastrukturen til Jøkul

William Killerud

2022.03.09

Fredag 4. mars holdt jeg en kort presentasjon om infrastrukturen til Jøkul for ansatte i Fremtind. Det var en lyninnføring i monorepo og verktøyene vi bruker for å gå fra kode på localhost til endringen er i produksjon.

Dette er en oppsummering for de som ikke fikk med seg presentasjonen live. Fremtind-ansatte kan også finne et opptak av presentasjonen under Fagtimen.

Her er FigJamen jeg brukte underveis i presentasjonen om du vil bla litt i den selv:

Lyninnføring i monorepo

Koden til Jøkul er organisert som et monorepo i repositoriet fremtind/jokul på GitHub.

Kort fortalt går idéen om et monorepo ut på at man samler flere selvstendige men relaterte prosjekter i det samme Git-repositoriet. Det gjør det enklere å gjøre endringer på tvers av disse prosjektene, men gir noen unike utfordringer.

Monorepo.tools har en fin oversikt om du vil lære litt mer.

For Jøkul sin del betyr det at vi har en samling med selvstendige pakker i mappen packages, i tillegg til portalen. Pakkene (og portalen) er organisert med Yarn workspaces slik at pakker som avhenger av hverandre i monorepoet alltid bruker den lokale versjonen, ikke versjonen som er publisert på NPM. Det gjør det mye enklere å teste endringer.

I tillegg finner du en package.json på rotnivå i repositoriet. Her samler vi avhengigheter, konfigurasjon og scripts som gjelder for alle pakkene.

La oss gjøre en endring

La oss følge en tenkt endring hvor vi legger til en ID-prop i LoaderProps-interfacet:

export interface LoaderProps {
    id?: string; // Denne!
    className?: string;
}

Kjør bygg og tester

Når endringen er gjort må vi sjekke at vi ikke har innført noen feil. Det gjør vi ved å kjøre yarn build og yarn ci:test fra rotnivå. Hva skjer da?

Hver pakke har sitt eget build-script som beskriver hvordan den pakken bygges. På rotnivå ber vi Turborepo ta seg av kjøringen av disse scriptene.

Turborepo bygger pakker i riktig rekkefølge, og cacher resultatet mellom bygg. Hvis en pakke ikke har noen endringer så kjøres heller ikke bygget. Det sparer oss for potensielt mye tid, siden et bygg av alle pakker tar et par minutter.

Byggscriptene ute i pakkene ser for det meste ganske like ut.

  • Reactpakkene bruker Rollup og Babel for å kompilere TypeScript til JavaScript.
  • Stilpakkene bruker Gulp for å kompilere Sass til CSS

Enhetstesting gjøres med Jest, og linting med ESLint og Stylelint. Til slutt gjør testscriptet en typesjekk med TypeScript.

Lag en commit

I Jøkul bruker vi Commitizen for å få strukturerte commitmeldinger i et spesielt format, Conventional Commits. Formatet bruker vi senere for å automatisk beregne riktig versjonsnummer når endringen skal publiseres, og for å legge til commitmeldingene i pakkens changelog.

Vi har en egen kommando, yarn commit, som tar deg gjennom en veiviser, sånn at du slipper å tenke på formatering.

Før commiten lages kjøres det et par kommandoer i en precommit-hook, satt opp med Husky og lint-staged. Hooken kjører Commitlint og Prettier, i tillegg til ESLint og Stylelint med "auto-fix" skrudd på. Dette er en ekstra liten sikkerhetssjekk, og sørger for at all koden i Jøkul følger det samme formatet uten at utviklere trenger å tenke noe på det.

Hva skjer under en pull request?

Pull requests sjekkes av en workflow på GitHub Actions. Den gjør en hel del ting i bakgrunnen for å sikre at det ikke har skjedd noe uventet.

Workflowen gjør en rask sjekk for å se om det er endret noen filer som gjør at vi trenger en grundig sjekk. Hvis det for eksempel bare er endret litt på en tekst i en Readme-fil så trenger vi ikke kjøre alle mulige slags tester.

I eksempelet vårt gjør vi endring i TypeScript, så da blir det full pakke 🍕

Actions bygger

Actions bygger pakkene med Turborepo på samme måte som på localhost. Så bygger den portalen.

Portalen er laget med Gatsby for å kunne bruke React-komponentene fra Jøkul for å bygge statiske nettsider. Innholdet kommer for det meste fra .mdx-filer rundtomkring, som er Markdown med React-støtte.

Actions tester

Actions kjører de samme testene som vi gjorde lokalt, men i tillegg kjøres visuelle regresjonstester med Cypress. Cypress-testene fordeles i en matrise med fem runners. Hver runner kjører en versjon av portalen som nettop ble bygget.

For hver test tar Cypress et skjermbilde og sammenligner med et skjermbilde som ligger i Git. På den måten fanger vi opp uforventede endringer.

Actions forhåndsviser

Til slutt bygger Actions også en versjon av portalen med en annen URL, og denne publiseres på GitHub Pages som et slags "staging-miljø" så vi kan forhåndsvise endringer.

Hvis alle automatiske tester går OK og du får en godkjent review av en kollega er det klart for å merge.

Automatisert publisering

Når en pull request merges er det release-workflowen som tar over. Det er her Lerna kommer inn og sjekker Git-historikken sammenlignet med forrige publisering. Hele denne workflowen går uten at et menneske er involvert 🤖

Versjonering

Lerna leser commitmeldinger for å se om det skal publiseres en ny SemVer patch, minor, eller major. For eksempel:

  • BREAKING CHANGE: blir til en major
  • feat: blir til en minor
  • fix: blir til en patch

Det kan være mange commits som samles inn i samme release, og Lerna er smart nok til å velge rett versjon fra samlingen. For eksempel vil en fix pluss en BREAKING CHANGE totalt sett bli én major-versjon, ikke først en patch og så en major.

Når Lerna har beregnet ferdig oppdaterer den alle package.json i repoet med de nye versjonsnummerene. Lerna samler også alle commitmeldinger og putter dem i pakkenes changelogs.

Publisering

Ved publisering bygger Actions pakkene på samme måte som før, med Turborepo. Deretter publiserer Lerna de nye pakkene til NPM og GitHub Packages.

Til slutt bygger Actions en ny versjon av portalen som publiseres til GitHub Pages.

Nå er alt klart til å brukes! 🎉

Spørsmål som ble stilt

Hvorfor er det delt i to pakker, en for CSS og en for React?

Det gir en større fleksibilitet. Ikke alle kan bruke React, og om f. eks. React-koden gjør import "./styles.scss" for å få stiler ville det lagt ganske kraftige føringer for hvilke byggverktøy som brukes ute i teamene.

Veien videre

Vi undersøker for tiden alternativer til Lerna, siden det dessverre ikke vedlikeholdes og holder oss på Yarn Classic. Du kan følge diskusjonen på GitHub om du vil se mer om alternativene og veien videre.