(▀̿Ĺ̯▀̿ ̿)

Module resolution med node

Det tok tre dager å få til bygg og serve av backend igjen, og det har lært meg følgende facts:

  • Som utvikler setter man path aliases for å unnslippe path hell – relative paths som må endres manuelt overalt hvis du flytter på ting (i tillegg til at lange relative paths er stygge å se på.) Vi vil ha import { foo } from 'bar/foo', ikke import { foo } from '../../../../../bar/foo'.
  • Du legger til path aliases i tsconfig.json for å få intellisense på de pathene.
  • Hvis du setter path aliases i tsconfig.json må du samtidig sette baseUrl, ellers funker det ikke. Du skal også sette moduleResolution til node.
  • Byggescript, f. eks. next build resolver path aliases ut av boksen, men hvis du bruker bundler må path aliasene legges til bundler-configens resolve.alias for at bundleren skal klare å resolve dem.
  • Vi kjører appen i Node.js, som er et runtime environment for Javascript. Det første node gjør ved oppstart er å resolve alle imports og exports. Da er det slik at node ikke har begrep om path aliases. Den må ha relative paths. Så hvis du bygger og bundler med Webpack og så prøver å serve med node, så knekker det med vår venn, MODULE_NOT_FOUND.
  • Det fins ulike måter å løse det på, blant annet kan du kjøre noe som heter tsc-alias rett etter tsc som leser path aliases fra tsconfig.json, går gjennom alle modulene dine og erstatter path aliases med relative paths i Javascript-outputen.
  • Har ikke sett IDE bemerke det, men “trailing commas” er ikke støttet i JSON. Kan føre til at verktøy som tsc-alias feiler ved parsing av tsconfig.json.

ᓚᘏᗢ

Edit: Da blir det klonede instanser av én rigg med blandede tenants. Første milepæl er publisering av kampanje. Før det skal tre sites opp: OF Promo, Siv Nancy, og Firstbird Promo til portfolio.

Lurte på om jeg skal ha bare én rigg som jeg utvikler i ett og bare ett gitrepo. Så blir multitenant-0, multitenant-1 og multitenant-2 instanser av den med ulike bruksområder. Da har alle instanser alle collections, endpoints, plugins osv. men de bruker ulike partisjoner.

Kan jeg slippe unna med å deploye alt fra ett og samme repo? Si de ligger på egne branches som trigger deploys, så utvikler jeg på main og merger inn fortløpende. Da blir det mulig å holde alle up-to-date.

Men hvilken gevinst har det å partisjonere instansene da, kan jeg ikke bare bygge ut riggen og plusse på tenants etter hvert som de dukker opp? Mer fleksibilitet til å utvikle riggen etter behov?

Tanken var at poenget med multitenancy var å la tenants dele funksjonalitet og også unngå å tilpasse adminpanelet for dem. Men lignende tenants vil fortsatt ha ulike behov til adminpanelet, så den jobben må gjøres uansett. Da opprettes nye instanser etter hvert som de gamle begynner å fylle seg opp med data. Og det blir lett å utvide tenants med flere features.

Angående multitenant-0 så var den tenkt uten adminpanel eller noe funksjonalitet, kun enkle “visittkort på nett”. Men da trenger jeg bare en Next app og ingen backend.

Da gjenstår bare å se hvilke features skal på plass først.

Kan man gruppere features etter vanlige usecases? Typ:

Multitenant-0: Visittkort-på-nett

Adminpanel: Nei
Auth: Nei
Features: Kontaktskjema
Pris: 15

Disse er ikke tenants men Next-apper på kun Vercel.

Usecases er bedrifter som trenger et SEO-optimalisert webnærvær der det informeres om tjenestene de tilbyr, hvorfor du bør velge dem og hvordan man kommer i kontakt. For SEO skal de være SSG og optimalisert for SEO for øvrig, kanskje inkludert forvaltning av Google Bedrift-oppføring, hjelp med innsamling av reviews osv. Prototyper fra ekstern designer.

Multitenant-X: Auth uten adminpanel

Adminpanel: Nei
Auth: Ja (inkl. Payload)
Features: Edit-in-place, Auth
Pris: Ca. 20

Spesielt setup for edit-in-place uten adminpanel.

Usecase er websider med innhold som endrer seg eller oppdaterer seg ofte, men strukturen (sider, layout) aldri endrer seg, f. eks. bedrifter som legger til eller endrer tjenestene sine ofte.

Redigerbart innhold bør være variert for å fange maks nisje-usecases: Richtekst-editor til HTML (vanlig tekst med utvidet støtte), bilde og bildegalleri eller -karusell, accordion, kodeblokk, sitatblokk, osv. Det er kult fordi implisitt kommer alltid editerbare strukturer inkl. innhold i sidens design. (Selve editmodus kan være superenkelt.)

Typer redigerbart innhold kan være Payload Blocks som lages støtte for i frontend. Merk at admin må kunne legge til og fjerne blocks i frontend.

Det blir som en WordPress-side for basic behov, men med bedre brukbarhet og design.

Ved login blir admin redirectet til frontend. De er logget inn i Payload, uten adminpanel men kan nå åpne innhold for redigering i frontend. Endringene blir committet til collections i Payload.

Vil unngå en første-iterasjon der admin må logge inn i adminpanelet for å oppdatere innhold der, det er dårlig brukbarhet.

Krever ikke admin-branding siden adminpanelet ikke er i bruk, men edit-in-place krever at Auth er implementert, og det krever mye utvikling av frontend for å støtte oppretting, endring og fjerning av ulike typer blocks og committing av ulike typer endringer til Payload.

Multitenant-1

1 collection, kun standardfeatures.

Du kan logge inn og oppdatere én toppcollection (f. eks. Events). Du får en frontend med et tilpasset view av dataene (f. eks. en liste over foredrag, konsertplan, turneplan).

Login: Ja, med adminpanel
Collections: 1 (inkl. view)
Features: Ingen tilpassede features
Pris: Ca. 25

Multitenant-2

Collections med booking (inkl. betaling) og aktivitetsrapporter.

Du kan logge inn og oppdatere flere collections (f. eks. Courses og Events). Du får visning av dataene i frontend, inkl. funksjonalitet for påmelding og betaling. Du får aktivitetsrapporter i adminpanelet.

Login: Ja, med adminpanel
Features: Påmelding/betaling, aktivitetsrapporter
Pris: Ca. 35

Tilpassede features

  • Booking: “Å kjøpe plass på et arrangement. Når arrangementet er over blir plassen borte. For å kjøpe ny plass må nytt arrangement opprettes
  • Reservation: “Å reservere en ressurs i et tidsrom. Etter tidsrommet blir ressursen tilgjengelig for reservering igjen.
  • Contract: Arbeidsflyt for utarbeidelse av avtaletekst med maltekster og -variabler, signatur med “magic link” el, PDF på epost…
  • Payment: Integrering med API for betaling med Vipps, Paypal, Stripe, krypto mm, registrering av påmelding…
  • Activity Report: Tabellvisning av historikk/aktivitet i forbindelse med booking, reservation mm, inkl. mulighet for eksport til fil eller Google Drive…

Standardfeatures

Ikke-tilpassede features som bør tilbys på alle produkter:

  • Kontaktskjema
  • Nyhetsbrev
  • Blogg
  • Admin: Branding
  • Admin: Pluss-add

Collections

Collections er samlinger av dokumenter. De har en viss shape gitt ved et konfigurert skjema i Payload. Features kan interface trygt med dem via typer.

Toppcollection er collections der andre, ikke-trivielle collections er nøstet inn. F. eks. et dokument av Courses gir typisk ikke mening hvis den mangler en liste med dokumenter av Events (mens en collection Addresses for å angi lokasjon er heller triviell.)

(✿◡‿◡)

Git

Jeg har jo et monorepo med ett backend-prosjekt som server n frontend-prosjekter. Så en vanlig workflow for meg er å kjøre backendprosjektet på localhost samtidig som jeg kjører ett av frontendprosjektene på localhost.

Samtidig er backenden deployet på Payload Cloud med bygg-trigger på innsjekk til en egen branch payload-cms, og frontendene deployet på Vercel med bygg-trigger på deres respektive branches. Men,

  • Det er klønete å jobbe mot to deploy-branches i ett repo fordi alle endringer må sjekkes inn til riktig branch hele tiden, hvis jeg sjekker inn endringer på prosjekt A til prosjekt B sin branch går As deploy glipp av dem og man må merge branchene manuelt.
  • Fordi branchene typisk ikke er i sync med hverandre kan jeg ikke ha branch A sjekket ut lokalt og kjøre branch B sin app i siste versjon. Jeg gidder ikke å merge branchene med hverandre (og med main) kontinuerlig.
  • Jeg kan ikke åpne repoet to ganger i VS Code; git endrer jo selve filsystemet etter utsjekket branch, så hvis jeg bytter branch i den ene instansen av VS Code så reflekteres det bare i den andre instansen.
  • Jeg kan ikke droppe branches og jobbe mot kun main, for da trigger jeg bygg på alle prosjektene hver gang jeg sjekker inn.
  • Jeg kan klone repoet to ganger og sjekke ut en branch i hver, men det fins bedre måter.

Arbeidsflyt med working trees

Man kan sjekke ut egne working trees fra repoet, ett for branch A og ett for branch B: https://andrewlock.net/working-on-two-git-branches-at-once-with-git-worktree/

Working trees er bare kopier av hele repoet, så det er som å ha klonet det to ganger, men i stedet for egne git-mapper har du en git-fil som peker på et rot-repo, så working-trærne jobber mot ett og samme filsystem; egne kloner er egne filsystemer.

Man kan da ta opp hver branch i egen instans av VS Code og kjøre appene i nyeste versjon der. Hvert innsjekk vil trigge bygg.

Kommando for å ta ut nytt working tree project-a fra branch-a:

git worktree add ../project-a branch-a

Trunk-based arbeidsflyt

Et annet alternativ er å jobbe rett på main. Ingen av prosjektene trigger der, så jeg kan sjekke inn kode fortløpende og merge til de respektive branchene når de er klare. Jeg trenger ikke tenke på at endringer i A må sjekkes inn ett sted og B et annet sted.

Ved større endringer kan jeg ta ut en arbeidsbranch, gjøre endringene der, merge til main og merge til trigger-branchen når alt er klart. Hvis flere utviklere skal jobbe mot samme repo kan main (og trigger-branchene) beskyttes med PR.

main er alltid nyest, så prosjektene kan kjøre parallelt på localhost i siste versjon. Pluss branchene blir alltid merget med siste nytt fra alle andre branches – som ikke har noen praktisk betydning, tror jeg, men jeg foretrekker det.

Jeg kan derfor jobbe mot alle prosjektene i samme instans av VS Code. Ved store endringer der jeg foretrekker å ha A og B i egne instanser av VS Code kan jeg lage en ny klon av repoet. Eventuelt holde meg i samme klon med egen arbeidsbranch i eget working tree. Det går ikke å ta ut samme branch to ganger i parallelle working trees, derav behovet for egen arbeidsbranch i så fall.

Kommando for å merge nyeste lokale commit (HEAD) med branch-a (husk å stå i main):

git push origin HEAD:branch-a