diff --git a/.htmlvalidate-public.js b/.htmlvalidate-public.js index 5afe2f5b71..3487f7188e 100644 --- a/.htmlvalidate-public.js +++ b/.htmlvalidate-public.js @@ -26,21 +26,30 @@ module.exports = { include: [ "^https://.*\\.vuejs.org/.*", + "^https://api-extractor.com/", "^https://commitlint.js.org/", "^https://developer.mozilla.org/", "^https://docs.cypress.io/", "^https://docs.npmjs.com", + "^https://en.wikipedia.org/wiki/", "^https://forsakringskassan.github.io/designsystem/", "^https://foundation.zurb.com/", "^https://getbem.com/", "^https://getbootstrap.com/", + "^https://github.com/conventional-changelog/", + "^https://github.com/ext/semantic-release-lerna/", "^https://github.com/[fF]orsakringskassan/", "^https://github.com/lerna/", "^https://github.com/semantic-release/", + "^https://gitlab.com/html-validate/", "^https://help.figma.com/", "^https://www.i18next.com/", + "^https://lerna.js.org/", + "^https://semantic-release.gitbook.io/", + "^https://semver.org/", "^https://support.atlassian.com/", "^https://typedoc.org/", + "^https://vitejs.dev/", "^https://www.conventionalcommits.org/en/v1.0.0/", "^https://www.digg.se/", "^https://www.figma.com/", diff --git a/docs/gettingstarted/contribute-to-fkds/release.md b/docs/gettingstarted/contribute-to-fkds/release.md index dffc596c0e..52db6c0b4f 100644 --- a/docs/gettingstarted/contribute-to-fkds/release.md +++ b/docs/gettingstarted/contribute-to-fkds/release.md @@ -31,7 +31,9 @@ För större ändringar utser vi en kontaktperson i FKDS-teamet som hjälper til Efter att du kommunicerat med teamet och fått en kontaktperson kan du börja implementera. Vi använder `main` som primär branch och du utgår vanligtvis från den branchen. -Gäller det en buggrättning som ska ut mot en äldre version utgår du från `release/N.x` (exempelvis `release/4.x` för v4). +Gäller det en buggrättning som ska ut mot en äldre version (maintenance release) utgår du från `release/N.x` (exempelvis `release/4.x` för v4). + +Läs mer om {@link monorepo#maintenance maintenance releases}. ### Branchnamn @@ -54,7 +56,8 @@ Om det finns ett JIRA- eller GitHub-ärende kan du använda det i branchens namn Commitmeddelanden skrivs i ett format baserat på [Conventional Commits][conventional-commits] och ligger som grund för release och changelog. -- Läs mer om {@link commits commitmeddelanden}. +- Läs mer om {@link monorepo#commits commitmeddelanden}. +- Läs mer om {@link monorepo#changelog Changelog}. [conventional-commits]: https://www.conventionalcommits.org/en/v1.0.0/ @@ -131,7 +134,7 @@ Exempel på åtgärder du kan göra för att behålla bakåtkompatibilitet: Går det inte lösa utan att bryta kompatibilitet så gäller följande: - Vi tillsammans samlar ihop flera brytande ändringar i samma release. -- Vi tillsammans går igenom kodbasen och tar nuvarande deprekerad funktionalitet. +- Vi tillsammans går igenom kodbasen och tar bort nuvarande deprekerad funktionalitet. - Vi tillsammans uppdaterar {@link release-plan Release planen}. - Vi tillsammans arbetar fram ett nyhetsmeddelande. - Din commit ska använda `!` efter type samt en trailer med `BREAKING CHANGE:` och kortfattade förklaring och instruktioner till migrering. @@ -175,11 +178,11 @@ En pull request ska generellt sett innehålla: - Hur löser denna pull requesten ovan beskrivet problem? - Om ändringen är visuell inkludera gärna en enkel före/efter bild i beskrivningen. 2. Välskriven kod som följer de kodstandarer vi satt upp. -3. Testfall: +3. Testfall, läs mer om {@link testverktyg testning}: - Enhetstester för logik. - Komponenttester för interaktion. - Screenshot-tester för visuellt utseende. -4. Dokumentation: +4. Dokumentation, läs mer om {@link dokumentation dokumentation}: - Behöverer live-exempel uppdateras? - Behövs nytt stycke som förklarar vad ändringen är? - Behövs en guide som lär ut hur man använder ändringen? @@ -240,6 +243,8 @@ Texten ska innehålla en kortfattad beskrivning av ändringen. Release byggs från CI-miljö för att säkerställa att vi har reproducerbara byggen och transparens i hur releasen är gjord. Bygg inte release från lokal utvecklingsmiljö. +Läs mer om hur {@link monorepo#release toolchain för releasejobb fungerar}. + Checklista innan release: - Prata med FKDS-teamet om releasen ska invänta andra pull requests som måste mergas först. diff --git a/docs/guide/toolchain/api-design.md b/docs/guide/toolchain/api-design.md new file mode 100644 index 0000000000..6cef0a1b25 --- /dev/null +++ b/docs/guide/toolchain/api-design.md @@ -0,0 +1,20 @@ +--- +title: API design +layout: content-with-menu +--- + +Så här rekommenderar vi att strukturera din kod + +## För FKUI + +### Vue-komponenter + +Som en tumregel bryter vi ut logiken i små enskilda funktioner som enbart agerar på input parametrar (pure functions) och testas separat med enhetstester. +Vue-komponenten nyttjar dessa funktioner och binder ihop logiken med DOM och interaktivitet. + +### Undefined behaviour + +undefined behaviour: där vi inte explicit har lovat att något fungerar så anser vi att det är odefinierat beteende och att det kan ändras i framtiden utan att det är en brytande ändring. +Hypotetiskt exempel, en funktion som tolkar datum garanterar bara ISO 8861 men om den råkar fungera med andra datumformat så är det odefinierat beteende och i en senare version av FKUI kan andra datumformat sluta fungera eller tolkas annorlunda. + +## För applikationer diff --git a/docs/guide/toolchain/byggscript.md b/docs/guide/toolchain/byggscript.md new file mode 100644 index 0000000000..c37372f5f0 --- /dev/null +++ b/docs/guide/toolchain/byggscript.md @@ -0,0 +1,264 @@ +--- +title: Byggscript +layout: content-with-menu +--- + +## Byggscript + +Våra paket byggs med hjälp av scriptet `build`. +Alla kommandon körs direkt från root i monorepot. + +- För att bygga hela FKUI anropar vi `npm run build`. +- För att bygga enskilda paket anropar vi `npm run -w @fkui/${PAKET} build`. + +Läs mer om {@link monorepo#npm-script att köra npm script}. + +Samtliga paket byggs som hybrid-paket (dvs vi levererar både CJS och ESM från samtliga paket). + +Beroende på vilken typ av paket bygger vi antingen med `rollup` eller `vite`. + +- `rollup` används för kod som är native (inte kräver något ramverk), exempelvis `@fkui/date` och `@fkui/logic`. +- `vite` används för kod som använder Vue, + +Utöver `rollup` och `vite` använder vi också: + +- [API Extractor][api-extractor] för att skapa en bundlad typescript dts fil samt generera en API deklaration i `etc` katalogen. +- [@html-validate/release-scripts][release-scripts] för att skapa en städad `package.json` före release. + +[api-extractor]: https://api-extractor.com/ +[release-scripts]: https://gitlab.com/html-validate/semantic-release-config/-/tree/master/packages/release-scripts + +## Filstruktur + +Filstrukturen i paketen ser ut som följande: + +``` + +lib +├── cjs +│   ├── package.json +│   ├── index.js +│   └── index.js.map +├── esm +│   ├── package.json +│   ├── index.js +│   └── index.js.map +├── types +│   └── index.d.ts +└── tsdoc-metadata.json + +``` + +TODO: nästlade package.json saknas i verkligheten, i vissa paket finns inte cjs/esm katalogen, i vissa finns inte types katalogen + +I `package.json` mappar vi med `exports` fältet för moderna toolchains (exempelvis Vite) samt med `main` och `types` för äldre toolchains: + +```json +{ + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "require": "./lib/cjs/index.js", + "import": "./lib/esm/index.js" + } + }, + "main": "lib/cjs/index.js", + "module": "lib/esm/index.js", + "types": "lib/types/index.d.ts" +} +``` + +Vi använder oss också av `sideEffects` fältet för de filer som har side effects (exempelvis polyfills som installeras globalt): + +```json +{ + "sideEffects": ["./lib/cjs/polyfills.js", "./lib/esm/polyfills.js"] +} +``` + +### Rollup + +TBD + +### Vite + +Vi använder en fördefinierad Vite konfiguration från NPM paketet [`@forsakringskassan/vite-lib-config`][vite-lib-config]. +Paketet exponerar en egen `defineConfig` som fungerar som Vite's egna men andra default-värden, precis som Vite's egna så mergas anpassningar med default-värden. +Konfigurationsobjektet tar också en ny egenskap `fk` med extra anpassningar. + +[vite-lib-config]: https://github.com/Forsakringskassan/vite-lib-config + +En typisk `vite.config.ts` ser ut så här: + +```ts +import { defineConfig } from "@forsakringskassan/vite-lib-config/vite"; + +export default defineConfig({ + /* FK-specifika anpassningar */ + fk: { + enableBanner: false, + }, + + /* Vite anpassningar, mergas med default inställningar */ + resolve: { + alias: { + "@fkui/vue": "src/index.ts", + }, + }, +}); +``` + +Läs mer om [FK-specifika anpassningar](https://github.com/Forsakringskassan/vite-lib-config/blob/main/README.md#viteconfigts). + +Läs mer om [Vite konfiguration](https://vitejs.dev/config/). + +`@forsakringskassan/vite-lib-config` levererar också ett CLI verktyg `fk-build-vue-lib` som används för att bygga paketet. +Verktyget tar hand om att bygga både CJS och ESM samt använder Babel för transpilering enligt SLA. +Under huven anropar verktygen Vite med API. + +Från `package.json` anropas verktyget likt: + +```json +{ + "scripts": { + "build": "run-s build:lib", + "build:lib": "fk-build-vue-lib" + } +} +``` + +### API Extractor + +API Extractor är ett verktyg som att hantera det API som exponeras från ett paket. +Vi använder det för att: + +- Bundla typescript deklarationer till en fil (dts rollup). +- Städa bort symboler som inte explicit deklarerats som publika (med `@public` parametern). +- Genererar en API deklaration i `etc` katalogen. + +API Extractor kräver att typescript deklarationer har genererats först. + +- För Vue använder vi `vue-tsc`. +- För övriga använder vi `tsc`. + +`tsconfig.json` är konfigurerat med: + +```json +{ + "compilerOptions": { + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "declarationDir": "temp/types" + } +} +``` + +Det innebär att typescript deklarationerna lagras i `temp/types`. + +`api-extractor.json` är sen konfigurerat med: + +```json +{ + "mainEntryPointFilePath": "/temp/types/index.d.ts", + "apiReport": { + "reportFolder": "/../../etc/" + }, + "dtsRollup": { + "publicTrimmedFilePath": "/lib/types/index.d.ts" + } +} +``` + +Även för API extractor finns ett verktyg `fk-api-extractor` i `@forsakringskassan/vite-lib-config`. +Skillnaden mot det officiella CLI verktyget är att verktyget kan hantera flera entrypoints samt har en flagga `--patch-augmentations` för hantering av globala module augmentations. + +Verktyget anropas likt: + +```json +{ + "scripts": { + "build": "run-s build:api", + "build:api": "fk-api-extractor --patch-augmentations api-extractor.*.json" + } +} +``` + +### Bundling + +Vissa beroenden kan med fördel bundlas in i NPM paketet. +Med bundling menar vi att koden för beroendet kompileras in i leverabeln. + +Fördelen med detta är att konsumenten inte behöver hantera beroendet alls eller ens känna till att det existerar. +Beroendet kommer inte finnas i deras `node_modules` katalog. + +Nackdelen är att konsumenten inte kan styra över vilken version som används eller kan direkt komma åt att nyttja beroendet eller konfigurera om det. + +Utgångsläget är att beroenden från FKUI ska bundlas men några tumregler att ta hänsyn till: + +- Beroendet bör vara förhållandevis litet. +- Beroendet ska ligga som `dependency` i `package.json` men vid release sanerar vi bort `dependencies` som inte markerats som `external`. Således kommer konsumenten inte hämta hem en extra oanvänd kopia av beroendet.Läs mer om [sanering](#release). +- Det API som beroendet kapslar in måste innehålla testfall som verifierar att beteendet fungerar även om det stegas upp till ny version, det behöver inte betyda 100% testtäckning av beroendet men 100% av det beteende man är ute efter i det API som exponeras. Se också [API design](#api-design). + +Är du tveksam prata med utvecklare i FKUI teamet. + +### `tsconfig.json` + +Varje paket har en egen `tsconfig.json` som ärver från `tsconfig.json` i root. + +Paketens `tsconfig.json` är ibland uppdelad i flera filer när olika typer av filer (speciellt Cypress) kräver olika konfiguration. +I de fallen ser paketets `tsconfig.json` ut ungefär så här: + +```json +{ + "files": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + /* ... */ + ] +} +``` + +där `tsconfig.lib.json` matchar en uppsättning filer med en viss konfiguration: + +```json +{ + "compilerOptions": { + "composite": true + /* ... */ + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.cy.ts"] +} +``` + +Läs också mer om [Cypress](cypress) för konfiguration för Cypress komponenttester. + +### Pageobjekt + +Pageobjekt återfinns i `src/pageobject` och kompileras för sig som en egen entrypoint. + +### Release scripts + +Vid release används [`@html-validate/release-scripts`](https://gitlab.com/html-validate/semantic-release-config/-/tree/master/packages/release-scripts) för att städa upp `package.json`. +Scriptet anropas både från `prepack` (anropas från `npm pack`) och `republishOnly` (anropas från `npm publish`). + +```json +{ + "scripts": { + "prepack": "release-prepack --bundle --retain-scripts", + "postpack": "release-postpack", + "prepublishOnly": "release-prepublish --bundle --retain-scripts" + } +} +``` + +> Notera: `--retain-scripts` används för att {@link monorepo#lerna Lerna} cachar vilka script som ska finnas och misslyckas därför senare att anropa script som städats bort. + +> Notera: `postpublish` är ej implementerad då {@link monorepo#lerna Lerna} anropar livscykel hooks i en annan ordning är `npm publish` och publicerar därför original `package.json` istället. +> Då releasebyggen alltid körs i CI-miljö har vi valt att ignorera att `package.json` inte återställs och working copy är dirty, eftersom den inte återanvänds. + +`dependencies` som inte bundlas vid kompilering ska markeras som externa antingen med `--external:${dependency}` eller med `externalDependencies` fältet. +Beroenden som inte markerats som externa kommer försvinna från `dependencies` fältet. diff --git a/docs/guide/toolchain/dokumentation.md b/docs/guide/toolchain/dokumentation.md new file mode 100644 index 0000000000..f67504f892 --- /dev/null +++ b/docs/guide/toolchain/dokumentation.md @@ -0,0 +1,57 @@ +--- +title: Dokumentation +layout: content-with-menu +--- + +Dokumentation genereras med `@forsakringskassan/docs-generator` och är konfigurerat i två filer: + +- `generate-docs.mjs` är den primära konfigurationen och den som anropar `@forsakringskassan/docs-generator`. +- `docs.config.js` är en förteckning över vilka filer som ska inkluderas vid bygge. + +Dokumentationen genereras upp från markdown-filer i `docs` katalogen. + +Exempel kan skapas upp i flera varianter: + +- Statiska exempel: visar enbart kod. +- Körbara exempel: ett block med html eller en Vue-komponent som monteras. +- Live exempel: ett körbart exempel med inställningar som läsaren kan justera. + +Exempel kan implementeras antingen inline i markdown-filer eller som fristående filer som importeras. + +Läs mer i dokumentationen för `@forsakringskassan/docs-generator`. + +## Exempel + +I FKUI använder vi ofta exempelfiler för att testa komponenter och för att visa upp i dokumentation. +Exempel som används i testning placeras i en underkatalog `examples` till komponenten exemplet tillhör och exempel som används för dokumentation kan placeras antingen i `docs` katalogen bredvid markdown-filen exemplet tillhör eller så kan samma exempel som används för testning användas. Konfigurationen för `@forsakringskassan/docs-generator` letar automatiskt i båda platserna. + +Flera verktyg för statisk kodanalys så som ESLint har andra regler för filer i `examples` kataloger. + +I exempel använder vi alltid paketets namn vid import, exempelvis: + +```ts +import { FTextField } from "@fkui/vue"; +``` + +Detta är för att när man läser exempel som konsument ska man alltid se koden precis som om man skrivit den i sin egna applikation. +Det möjliggör också att man enkelt kan kopiera koden direkt. + +För att möjliggöra import av biblioteket i exempel är `tsconfig.json` konfigurerat med: + +```json +{ + "compilerOptions": { + "paths": { + "@fkui/vue": ["./src/index.ts"] + } + } +} +``` + +Läs mer om tsconfig + +### Live exempel + +Live exempel implementeras som ett körbart exempel där exemplet använder `@forsakringskassan/docs-live-example`. + +Läs mer i dokumentationen för `@forsakringskassan/docs-live-example`. diff --git a/docs/guide/toolchain/index.md b/docs/guide/toolchain/index.md new file mode 100644 index 0000000000..daa3ca8e37 --- /dev/null +++ b/docs/guide/toolchain/index.md @@ -0,0 +1,13 @@ +--- +title: Toolchain +layout: content-with-menu +sortorder: 1 +--- + +## Definitioner + +- Konsument: den utvecklare som använder sig av ett eller flera FKUI-paket. +- Slutanvändare: den person som använder sig utav en applikation skriven med ett eller flera FKUI-paket. +- Paket: en leverabel som distribueras i form av NPM-paket, oftast publiceras till NPM för publik konsumption men kan vara internt. +- Root: översta nivån i katalogstrukturen. +- Symlänk: [Symbolisk länk](https://en.wikipedia.org/wiki/Symbolic_link) är en länk till en fil eller katalog som används istället för den riktiga filen. diff --git a/docs/guide/toolchain/monorepo.md b/docs/guide/toolchain/monorepo.md new file mode 100644 index 0000000000..dcf9afb629 --- /dev/null +++ b/docs/guide/toolchain/monorepo.md @@ -0,0 +1,430 @@ +--- +title: Monorepo +layout: content-with-menu +sortorder: 2 +--- + +Källkoden för FKUI är strukturerad i ett monorepo. +Det innebär att vi från ett och samma repo levererar flera leverabler (paket), dess versionsnummer är i synk med varandra samt att vi snabbt kan testa ändringar som slår över flera paket. + +Så här jobbar vi i monorepo + +## Versioner + +I FKUI så är använder vi [semantisk versionshantering][semver] och versioner som är i synk med varandra. +Det innebär att konsumenten vet att om man har version X.Y (exempelvis v5.1) av samtliga FKUI-paket så är de testade tillsammans och fungerar de alltid ihop. + +- Major versioner innehåller alltid brytande ändringar, oftast innebär detta att kodförändringar krävs men även förändrat SLA (exempelvis att IE11 stöd togs bort) innebär en brytande ändring. +- Minor versioner innehåller nya features men inget som kräver förändringar hos konsumenten, alla ändringar är bakåtkompertibla. Uppstår det trots allt förändringar som kräver ändringar ska detta ses som en bugg. +- Patch versioner innehåller enbart buggrättningar och här kan olika paket få olika patch-versioner, exempelvis 5.1.0 och 5.1.2 fungerar fortfarande ihop. + +Versioner hanteras automatiskt vid release utifrån commitmeddelanden. + +- Läs mer om [releasehantering](#release). +- Läs mer om [commitmeddelanden](#commits). + +[semver]: https://semver.org/ + +## Katalogstruktur + +I FKUI så använder vi följande katalogstruktur: + +``` +(root) +├── cypress +├── docs +├── etc +├── internal +│   ├── pkg-a +│   └── pkg-b +├── packages +│   ├── pkg-c +│   └── pkg-d +└── scripts +``` + +där: + +- `cypress` innehåller konfiguration och gemensamma E2E testfall. Läs mer om [testfall](#testfall). +- `docs` innehåller dokumentation och innehåll för denna siten. Läs mer om [dokumentation](#dokumentation). +- `etc` innehåller automatgenererade API deklarationer och manifest. Läs mer om [byggscript](#byggscript). +- `internal` innehåller interna paket, paket som inte publiceras extern men kan användas av andra paket. +- `packages` innehåller publika paket, paket som publiceras och kan användas av konsumenter. +- `scripts` innehåller gemensamma script för byggen och underhåll av repository. + +Namnsättningen för paket i `internal` och `packages` är att katalogens namn ska motsvara namnet i `package.json` utan scope, dvs om paketet har namnet `@fkui/foo-bar` ska katalogen ha namnet `foo-bar`. +Varje paket innehåller en egen `package.json` där paketets metadata, script och beroenden definieras. + +Det mesta av utvecklingsarbetet sker i `packages`. + +## NPM script + +TODO: ändra "kommando" till "script" + +Vi kör primärt alla kommandon direkt från root, endast i undantagsfall anropar vi något från en djupare katalog. + +Många kommandon kan köras för hela monorepot direkt: + +- `npm install` / `npm ci`: installerar beroenden för samtliga paket. +- `npm test` kör enhetstester, statisk kodanalys och lintning. +- `npm run build` bygger samtliga paket. +- `npm exec cypress open` startar cypress. + +### NPM Install + +Vi kör alltid [`npm install`][npm-install] (eller det besläktade [`npm ci`][npm-ci]) från root i monorepot. +Det kan orsaka problem i din miljö om du försöker köra `npm install` från en underkatalog (framförallt så bryts symlänkar till andra paket i monorepot och man jobbar därför mot gamla kopior och inte mot den faktiska koden i monorepot). +Senare version av `npm install` känner av att det körs från en underkatalog och agerar som att du hade kört från root men vi rekommenderar att alltid ha som vana att köra alla kommandon från root speciellt kommandon så som `npm install` som kan orsaka problem. + +I ett monorepo kan det finnas flera `node_modules` kataloger. +`npm install` kommer försöka att lägga alla beroenden i rootens `node_modules` (deduplication) men om det uppstår konflikter i versioner mellan två paket i monorepot kan den skapa upp djupare `node_modules` kataloger exempelvis `packages/vue/node_modules`. +Det kan exempelvis se ut så här: + +``` +(root) +├── node_modules +│   ├── dep-a +│   ├── dep-b # dep-b v1 +│   └── dep-c +└── packages + └── vue + └── node_modules + └── dep-b # dep-b v2 +``` + +När vi i koden använder `require` eller `import` så kommer både paketets egna `node_modules` och rootens `node_modules` katalog att användas. +(Rent tekniskt letar `require` och `import` rekursivt i filsystemet efter alla `node_modules` kataloger den kan nå.) + +I rootens `node_modules` kommer också symlänkar mot monorepots paket skapas upp. + +``` +(root) +└── node_modules + └── @fkui + ├── logic -> packages/logic + └── vue -> packages/vue +``` + +Detta möjliggör för `require` och `import` att hitta paketen trots att de egentligen inte är installerade och att de alltid pekar ut det som ligger i monorepot istället för föregående släppt version. + +> Notera: symlänken pekar bara ut var i monorepot paketet finns. För att paketet ska kunna importeras med `require` eller `import` måste paketet också byggas (så leverabler i respektive `lib` katalog skapas). Läs mer om att {@link byggscript bygga paket}. + +För utvecklingsmiljöer använder vi primärt [`npm install`][npm-install]. +Den behåller de existerande `node_modules` katalogerna och installerar det som är nytt samt att den uppdaterar `package-lock.json` om den inte är i synk med `package.json`. + +För CI-miljöer eller om man vill säkerställa att man har en ren miljö använder vi [`npm ci`][npm-ci] (clean install). +Skillnaden mot `install` är att `ci` tömmer existerande `node_modules` och undviker att beräkna om beroendeträdet genom att enbart läsa `package-lock.json`. + +`npm install` används också för att installera nya beroenden. +Läs mer om att {@link pakethantering#beroenden installera beroenden}. + +### Workspaces + +Eftersom många kommandon tar relativt långt tid att köra är det ofta fördelaktigt att köra det för ett enskilt paket. +Med `npm run --workspace PAKET` (kort `-w`) kan vi anropa script för ett eller flera paket exempelvis: + +```bash +npm run -w @fkui/vue build +``` + +> OBS! Vid byggen av individuella paket har vi ingen automatiskt detektering av att dess beroenden är byggda. De paketeten behöver byggas först eller så måste ett fullständigt bygge göras. + +Det går också att köra script för alla paket med `--workspaces` (kort `-ws`, notera plural). +Detta kan med fördel kombineras med `--if-present` som enbart kör scriptet om det finns definierat i paketets `package.json`. + +```bash +npm run -ws --if-present unit +``` + +Både `--workspace` och `workspaces` kan användas för de flesta NPM kommandon, bland annat: + +- `npm install -w @fkui/logic foobar`: installerar beroendet `foobar` i `@fkui/logic`. +- `npm test -w @fkui/date`: kör testfall för `@fkui/date`. +- `npm start -w @fkui/vue`: startar utvecklingsmiljö för `@fkui/vue`. +- osv + +Om än både `npm run test` och `npm run start` fungerar använder vi med fördel dess alias `npm test` samt `npm start`. + +### Parametrar + +Behöver man ange extra parametrar till något script måste man använda `--` före parametrar: + +```bash +npm run unit -w @fkui/vue -- --no-coverage -u +``` + +Utan `--` kommer parametrarna att skickas till `npm run` istället för det kommando som anropas av scriptet. + +### Exec + +Vissa NPM paket (beroenden) kommer med egna körbara script. +Dessa kan köras med hjälp av [`npm exec`][npm-exec] eller [`npx`][npx]. + +```bash +npm exec cypress open +``` + +`cypress` är namnet på scriptet och resten av raden är CLI argumenten till scriptet. +Notera att precis som med parametrar till `npm run` måste parametrar med `--` föregås av ett extra `--`. + +### Lerna + +Vi använder [Lerna][lerna] för vissa operationer så som `npm run build` för att köra kommandon som kräver att paketen hanteras i topologisk ordning. + +> Topologisk ordning: paketen bygger upp en riktad graf där noderna sorteras utifrån den ordning noderna måste besökas för alltid ha besökt dess beroenden innan sig själv. + +[lerna]: https://lerna.js.org/ + +Exempelvis så är `npm run build` implementerat som: + +```json +{ + "scripts": { + "build": "lerna run build" + } +} +``` + +För att köra motsvarande med CLI: + +```bash +npm exec lerna run build +``` + +Båda motsvarar då `npm run --workspaces build` fast garanterar att `build` anropats i en ordning som garanterar att beroenden byggts först. + +## Commits + +I FKUI använder vi commits som grund till både Changelog och för att automatiskt bestämma vilken nästkommande version blir. + +Läs mer om hur [Changelog genereras från commits](#changelog). + +Commitmeddelanden använder en modifierad variant av [Conventional Commits][conventional-commits] där skillnaden är att vi kräver en Jira-referens i slutet: + +[conventional-commits]: https://www.conventionalcommits.org/en/v1.0.0/ + +> ${type}: ${description} (${relation} ${jira}) + +där: + +- `${type}` är vilken typ av commit, vanligtvis `fix` eller `feat`. +- `${description}` är en kort summering av commit. +- `${relation}` är hur commit relaterat till en Jira, `refs` eller `fixes`. +- `${jira}` är den Jira som commit relaterar till. + +Scope sätter vi enbart i undantagsfall då det populeras automatiskt i Changelog. +Vanligt undantag är `chore(deps)` för beroenden, `chore(release)` för releaser samt `refactor(${verktyg})` och `style(${verktyg})`. + +
+Tillgängliga typer + +De ${type} vi använder är: + +- `fix` för buggrättningar. +- `feat` för nya features. +- `build` för ändringar av byggscript. +- `chore(deps)` för beroenden. +- `chore(release)` för releaser (ej manuellt). +- `chore` bör undvikas men tillåts för commits som inte passar in under andra typer. +- `ci` för ändringar av CI/CD-script. +- `docs` för ändringar av dokumentation. +- `style` för kosmetiska ändringar som ej påverkar konsumenter (dvs ej visuellt utseende). +- `refactor` för refaktorisering av kod som ej påverkar konsumenter. +- `perf` för ändingar som förbättrar prestanda men ej annars påverkar konsumenter. +- `test` för ändringar eller tillägg av testfall. + +
+ +Ett bra commitmeddelande ska: + +- Beskriva vilken komponent eller funktion den berör. Skriv "add new prop `foo` on component `FBar`" istället för `"add new prop"` eller "add new prop `foo`" eftersom läsaren inte känner till sammanhanget. + +
+
+ +::: info Bra meddelande + +- feat: add new prop `foo` on component `FBar` +- fix: fix styling issue when clicking on `FBaz` + +::: + +
+
+ +::: danger Undvik + +- feat: add new prop +- fix: fix styling + +::: + +
+
+ +Läs mer om [brytnade ändringar](#brytande-andringar). + +Vi använder [Commitlint][commitlint] för att upprätthålla formatet på commitmeddelanden. +Commitlint anropas från git `commit-msg` hook (via `husky` från `.husky/commit-msg`) och är konfigurerat med att använda [`@forsakringskassan/commitlint-config`][commitlint-config]. + +Läs mer om [git hooks](#git-hooks). + +[commitlint]: https://commitlint.js.org/ +[commitlint-config]: https://github.com/Forsakringskassan/commitlint-config + +Om det behövs kan man kringgå `commitlint` med `--no-verify`: + +```bash +git commit --no-verify -m 'non-conforming message' +``` + +För feature-branches rekommenderar vi detta arbetsflödet för dina commits: + +1. För varje distinkt feature eller buggrättning, skapa en specifik och fristående commit (tänk på det som att den skulle gå att lägga en egen PR och mergas separat från övriga commits i din branch). Denna commit ska använda `feat` eller `fix` som type. +2. Behöver du bygga vidare på en tidigare commit (i din branch) kan du antingen använda `git commit --fixup` eller skapar en ny commit med `refactor` som type. +3. Innan det är dags för merge gör du en sista rebase över master där du slår ihop lämpliga commits, framförallt fixups men även de commits som använder `refactor` (var syfte inte är att göra en refaktorisering av kod som inte skapats i denna branch). + +## Changelog + +Changelog genereras automatiskt med [conventional-changelog][conventional-changelog] vid release. +Konfigurationen kommer från [@forsakringskassan/semantic-release-config][semantic-release-config-changelog]. + +Changelogen genereras utifrån en filtrerad lista med commits från föregående release. +De commits som tas hänsyn till är commits där commitmeddelande använder: + +- Type `feat` (ny feature). +- Type `fix` (buggrättning). +- Type `perf (prestandaförbättring). +- Type `revert` (revert av tidigare commit). +- Commits som innehåller brytande ändringar. Läs mer om [brytande ändringar](#brytande-ändringar). + +Övriga commits visas ej i changelog. + +Den filtrerade listan grupperas därefter efter typ: + +1. Brytande ändringar +2. Features +3. Buggrättningar + +Exempelvis om vi har följande lista med commits sen föregående release: + +``` +fix: fix bug in component A (fixes XYZ-1234) +feat: new component B (refs XYZ-4321) +refactor: rewrite component C (refs XYZ-2345) +fix: fix another bug in component A (fixes XYZ-5432) +``` + +Efter filtrering kommer listan reduceras till: + +``` +fix: fix bug in component A (fixes XYZ-1234) +feat: new component B (refs XYZ-4321) +fix: fix another bug in component A (fixes XYZ-5432) +``` + +Scope, om det inte explicit är satt, fylls i automatiskt: + +``` +fix(@fkui/vue): fix bug in component A (fixes XYZ-1234) +feat(@fkui/design,@fkui/vue): new component B (refs XYZ-4321) +fix(@fkui/logic): fix another bug in component A (fixes XYZ-5432) +``` + +Efter gruppering kommer listan transformerats till: + +``` +feat: + - feat(@fkui/design,@fkui/vue): new component B (refs XYZ-4321) + +fix: + - fix(@fkui/vue): fix bug in component A (fixes XYZ-1234) + - fix(@fkui/logic): fix another bug in component A (fixes XYZ-5432) +``` + +och utifrån det genereras följande nya rader i Changelog: + +```md +## v1.2.3 (1999-12-31) + +### Features + +- **@fkui/design**, **@fkui/vue**: new component B (refs XYZ-4321) + +### Bug fixes + +- **@fkui/vue**: fix bug in component A (fixes XYZ-1234) +- **@fkui/logic**: fix another bug in component A (fixes XYZ-5432) +``` + +Kom ihåg att om du använder squash merge för att merga din Pull Request så måste du skriva ett nytt commit-meddelande (i korrekt [format](#commits)), använd inte det commitmeddelande som föreslås som default. + +[conventional-changelog]: https://github.com/conventional-changelog/conventional-changelog +[semantic-release-config-changelog]: https://github.com/Forsakringskassan/semantic-release-config/blob/main/packages/semantic-release-common/lib/changelog.js + +## Release + +Vi använder [Semantic Release][semantic-release] med [`semantic-release-lerna`][semantic-release-lerna] för att hantera releaser. + +Semantic release tar hand om: + +- Välja ut nästa versionsnummer utifrån de commits som skapats sen föregående release. +- Uppdatera `package.json` filer med nytt versionsnummer, inklusive beroenden mellan paket. +- Vid behov, bygga om leverabler (leverabler som är beroende av ett uppdaterat versionsnummer). +- Uppdatera Changelog. +- Skicka ut announcement till chatt "Ny release v1.2.3". +- Publicera NPM-paket som ändrats sen föregående release, inklusive dependee paket. +- Skapa tag i Git. + +Semantic release är konfigurerat med `@forsakringskassan/semantic-release-monorepo-config`, vars konfiguration ger: + +- Versioner är latched på minor-versioner, dvs alla paket kommer alltid ha samma major och minor men patch tillåts ändras. +- Nästkommande version använder `fix` för patch, `feat` för minor och breaking för major. +- Vilka commits som är relevanta att visa i changelog och vilket stycke. + +Semantic release inspekterar taggar för att avgöra vilken den företående versionen är. + +Vi går emot semantic release rekommendation och kör inte semantic-release vid varje commit på branchen utan vi triggar manuellt ett CI-jobb som kör semantic-release. +Motiveringen är att vårat arbetsflöde i git inte fungerar väl med att släppa löpande varje commit samt att det finns visst manuellt arbete som behöver utföras. + +Läs mer om releaseprocess. + +I FKUI använder vi `master` som primär branch och vanliga releaser utgår från den branchen. + +[semantic-release]: https://semantic-release.gitbook.io/semantic-release +[semantic-release-lerna]: https://github.com/ext/semantic-release-lerna/ + +### Maintenance releaser + +Semantic release är konfigurerat att utöver `master` tillåta releaser från brancher likt `release/N.x` (exempelvis `release/4.x`). +Det innebär att major versionen kommer vara v4. +Det är viktigt att behålla branchen efteråt om man vill släppa fler releaser, behåller man inte den är det viktigt att senaste git taggen används när man skapar om branchen annars får man konflikter i versioner. + +## Git hooks + +Vi använder `husky` för att hantera git hooks, i `.husky` katalogen hittar du uppsättningen hooks som används. + +- `commit-msg` anropar `commitlint` för att validera formatet på commitmeddelande. Läs mer om commitlint. +- `pre-commit` anropar `lint-staged` för att automatiskt korrigera formatering med prettier samt korrigera eslint fel. Läs mer om statisk kodanalys. + +## VSCode + +Vi använder Volar (`vue.volar`). + +Workspace kommer med en lista med rekommenderade extensions och är förinställd att fungera med dessa. + +## CI/CD + +:::alt toolchain-cicd + +::: + +## Underhåll + +I `scripts` finns repon lämpliga för diverse underhåll. +Se dokumentation för respektive vad de gör och hur det används. + +[npm-install]: https://docs.npmjs.com/cli/v10/commands/npm-install +[npm-ci]: https://docs.npmjs.com/cli/v10/commands/npm-ci +[npm-exec]: https://docs.npmjs.com/cli/v10/commands/npm-exec +[npx]: https://docs.npmjs.com/cli/v10/commands/npx diff --git a/docs/guide/toolchain/pakethantering.md b/docs/guide/toolchain/pakethantering.md new file mode 100644 index 0000000000..7c11442aa1 --- /dev/null +++ b/docs/guide/toolchain/pakethantering.md @@ -0,0 +1,75 @@ +--- +title: Pakethantering +layout: content-with-menu +--- + +## Beroenden + +alla beroenden som paketet använder ska läggas in paketets egna package.json + +--save-exact +--save-dev +--save-prod + +Läs mer om [npm install](https://docs.npmjs.com/cli/v8/commands/npm-install) + +vi använder renovate + +### Interna beroenden + +Interna beroenden mellan paket måste också deklareras i `package.json`: + +- `devDependency`: här deklarerar vi exakt den version av beroendet som ska användas och **måste** motsvara versionen som finns i monorepot. Denna används enbart för utveckling av FKUI och påverkar inte konsumenter. +- `peerDependency`: här deklarerar vi den major version av beroendet som ska användas. Konsumenten av FKUI nyttjar denna för att hålla ihop versioner. + +````json +{ + "name": "@fkui/foobar", + "version": "5.1.0", + "devDependencies": { + "@fkui/dependency": "5.1.0" + }, + "peerDependency": { + "@fkui/dependency": "^5" + } +} + +Kör `npm install` i root och verfiera i `package-lock.json` att inte en kopia installerats. + +Om din diff i `package-lock.json` lägger till rader likt nedan så installeras en kopia, se till att versionen av ditt beroende matchar versionen som finns i monorepot. + +```diff ++ "packages/vue/node_modules/@fkui/date": { ++ "version": "5.31.0", ++ "resolved": "https://registry.npmjs.com/@fkui/date/-/date-5.31.0.tgz", ++ "integrity": "sha512-DTQkWkHNIsR+OZiGLQKirKg/IJDBS2TY2zg6QLOVvTvwtgBFLsz2wlyyc9uMT09MVUUrRGnslThrZehhsd9TXg==", ++ "dev": true, ++ "license": "MIT", ++ "engines": { ++ "node": ">= 16", ++ "npm": ">= 7" ++ } ++ } +```` + +## Skapa nytt paket + +1. Skapa en ny katalog i `packages` eller `internal`. + +- `packages` används när paketet ska publiceras och användas av konsumenter. +- `internal` används när paketet ej ska publiceras men nyttjas internt av FKUI. + +2. Skapa en ny `package.json`: + 1. Sätt `name` till `@fkui/${namn}` där `${namn}` motsvarar katalogens namn + 2. Sätt `version` samma version som finns i root `package.json`. Om din PR är långlivad kom ihåg att uppdatera `version` varje gång en ny release släpps tills din PR är merged. + 3. Om paketet är internt sätt `private` flaggan till `true`. +3. Kör `npm install` + +Läs mer om package.json + +## Ta bort paket + +1. Ta bort eventuella beroenden till paketet. +2. Ta bort katalogen som innehåller paketet. +3. Kör `npm install`. +4. Eftersom NPM inte städar bort samtliga referenser i `package-lock.json` öppna filen i din editor och sök upp kvarstående block som refererar till paketet. diff --git a/docs/guide/toolchain/testverktyg.md b/docs/guide/toolchain/testverktyg.md new file mode 100644 index 0000000000..e8803c5f5b --- /dev/null +++ b/docs/guide/toolchain/testverktyg.md @@ -0,0 +1,123 @@ +--- +title: Testverktyg +layout: content-with-menu +--- + +## Testfall + +Testfall i FKUI implementeras med två verktyg: + +- Jest för enhetstester +- Cypress för komponenttester och E2E-tester + +Som en tumregel använder vi enhetstester för att testa logik, komponenttester för att testa interaktion och i undantagsfall E2E-tester för att testa integration. + +Samtliga tester körs från CI-miljö vid branch-byggen. +PR-byggen kör inte komponenttester eller E2E-tester. + +Läs mer om [testning](testning). + +### Jest + +Paket utan ramverksspecifika komponenter samt logik för Vue-komponenter testas med Jest. +Förrutom i undantagsfall testar vi inte interaktion med komponenter med Jest om än JSDOM och `@vue/test-utils` hanterar det. + +Enhetstester placeras i samma katalog som filen som ska testas och använder `${filename}.spec.ts` som filnamn. + +För Jest finns två färdiga presets: + +- `@forsakringskassan/jest-config`: för paket som är skriva i ren typescript, ej ramverksspecifikt. +- `@forsakringskassan/jest-config-vue`: för paket med Vue-komponenter. + +Båda konfigurationer genererar både coverage och test resultat i maskinläsbart format i `coverage` samt `test-results` katalogerna. +CI-miljö läser in samtliga filer. + +Jest anropas från respektive paket via `test` scriptet. +`test` scriptet i root anropar i sin tur `test` i respektive paket. + +Läs mer om [@fkui/test-utils](test-utils). + +### Komponenttester (Cypress) + +Paket med Vue-komponenter testar vi interaktion och utseende med komponenten med Cypress Komponenttest. + +Komponenttester placeras i samma katalog som komponenten för komponenten och använder `${component}.cy.ts` som filnamn. + +Varje komponent bör ha minst ett komponenttest som testar det visuella utseendet i form av ett screenshot sk "screenshottester" +Vi använder oss av `@forsakringskassan/cypress-visual-regression` för att skriva tester med skärmdumpar: visuell regressionstest. + +Läs mer om [screenshottester][testning]. + +Cypress är konfigurerat i rootens `cypress.config.ts` och anropas direkt från root med `npm exec cypress open` (headed) alternativt `npm exec cypress run` (headless). + +Cypress är konfigurerat med följande plugins: + +- `@forsakringskassan/cypress-axe` för tillgänglighetstester med Axe. +- `@forsakringskassan/cypress-visual-regression` för screenshottester (visuel regression). +- `cypress-html-validate` för HTML validering. + +Konfigurationen genererar test resultat i maskinläsbart format i `test-results` katalogen. +CI-miljö läser in filen. + +`tsconfig.json` i respektive paket med Cypress komponenttester pekar ut en separat `tsconfig.cypress.json` med specifik typescript konfiguration för Cypress: + +```json +{ + "extends": "../../cypress/tsconfig.json", + "compilerOptions": { + "composite": true + }, + "include": [ + "src/@types/cypress.d.ts", + "src/**/*.ts", + "src/**/*.vue", + "src/**/*.cy.ts" + ], + "exclude": ["src/**/*.spec.ts"] +} +``` + +Läs mer om [tsconfig.json](#tsconfig-json). + +### E2E (Cypress) + +I undantagsfall kan E2E-tester användas där man vill testa ett större sammanhang. +E2E-tester kör mot den genererade dokumentationen och kräver att den byggts och startats som en separat process. + +För att bygga och starta dokumentation: + +```bash +npm run build +npm run build:docs +npm start +``` + +Därefter i en annan terminal kan E2E-tester startas: + +```bash +npm exec cypress open +``` + +E2E-tester ska endast användas som en sista utväg. + +För konfiguration se [komponenttester](#komponenttester-cypress). + +## Statisk kodanalys och lintning + +FKUI använder flera verktyg för statisk kodanalys och lintning: + +- Prettier för att formatera kod. +- ESLint för lintning av javascript-, typescript- och Vue-filer. +- HTML-Validate för validering och analys av HTML i komponenter och exempel. +- Stylelint för lintning av css- och sass-filer. + +Samtliga verktyg körs och är konfigurerade från root men i undantagsfall konfigureras verktygen om i respektive paket. +Flera verktyg använder färdiga mallar för sin konfiguration, se respektive konfigurationsfil och dokumentation för detaljer. + +Vid commit anropas både Prettier och ESLint via husky (konfigurerat i `.husky/pre-commit`). Läs mer om git hooks. + +### Eslint + +Använder `@forsakringskassan/eslint-config`. + +Läs mer om dokumentationsexempel.