[{"data":1,"prerenderedAt":15041},["ShallowReactive",2],{"navigation":3,"blog-posts":35},[4,11,17,23,29],{"fields":5,"sys":9},{"navigationTitle":6,"slug":7,"external":8},"Om Nicky","nicky-christensen",false,{"id":10},"nav-1",{"fields":12,"sys":15},{"navigationTitle":13,"slug":14,"external":8},"Udvalgte projekter","referencer",{"id":16},"nav-2",{"fields":18,"sys":21},{"navigationTitle":19,"slug":20,"external":8},"Blog","blog",{"id":22},"nav-blog",{"fields":24,"sys":27},{"navigationTitle":25,"slug":26,"external":8},"Hvad koster det?","projekt-estimator",{"id":28},"nav-estimator",{"fields":30,"sys":33},{"navigationTitle":31,"slug":32,"external":8},"Kontakt","kontakt",{"id":34},"nav-3",[36,252,1002,1395,2007,2333,2444,3018,3554,3703,4709,5540,5748,8199,8565,8793,9042,9483,9580,9816,10209,13158,13218,13298,13458,14572,14998],{"id":37,"title":38,"body":39,"date":234,"description":235,"extension":236,"meta":237,"navigation":238,"noindex":8,"path":239,"seo":240,"seoDescription":241,"seoTitle":242,"slug":243,"stem":244,"tags":245,"thumbnail":250,"updated":234,"__hash__":251},"blog\u002Fblog\u002Ffra-freelance-udvikler-til-technical-director.md","Fra freelance udvikler til Technical Director — Min rejse",{"type":40,"value":41,"toc":216},"minimark",[42,47,51,54,57,61,64,71,77,83,89,93,96,102,108,114,118,123,126,129,133,136,139,143,146,149,153,156,159,163,171,175,178,184,190,196,200,203,206,210,213],[43,44,46],"h2",{"id":45},"en-rejse-der-startede-med-nysgerrighed","En rejse der startede med nysgerrighed",[48,49,50],"p",{},"Da jeg startede som webudvikler for over 19 år siden, var mit eneste mål at skrive god kode. Jeg ville lære alt om HTML, CSS og JavaScript, og jeg ville bygge ting der virkede.",[48,52,53],{},"I dag er jeg Technical Director hos Checkmate.dk, og selvom koden stadig er en vigtig del af mit arbejde, er det kun en del af billedet. Vejen hertil har været alt andet end lineær, og jeg har lært mindst lige så meget om mennesker, processer og forretning som om teknologi.",[48,55,56],{},"Her er de vigtigste lærdomme fra rejsen.",[43,58,60],{"id":59},"fra-bureau-til-enterprise-til-startup-til-freelance","Fra bureau til enterprise til startup til freelance",[48,62,63],{},"Min karriere har taget mig igennem mange forskellige miljøer:",[48,65,66,70],{},[67,68,69],"strong",{},"Bureauer"," (tidlige år) — Her lærte jeg at levere hurtigt, håndtere mange projekter samtidig og kommunikere med kunder der ikke altid vidste hvad de ville have. Det lærte mig at oversætte forretningsbehov til tekniske løsninger.",[48,72,73,76],{},[67,74,75],{},"Enterprise"," (Grundfos, Vestas) — Her oplevede jeg hvad der sker når systemer skal skalere til tusinder af brugere og hundredevis af udviklere. Processer, arkitekturbeslutninger og teknisk gæld får en helt anden vægt når konsekvenserne er store.",[48,78,79,82],{},[67,80,81],{},"Startups og SaaS"," (Playable, Harness) — Her lærte jeg at bygge produkter fra bunden, tage ejerskab over tekniske valg, og arbejde i teams hvor hastighed og kvalitet begge er afgørende. Som Tech Lead hos Playable og senere hos Harness fik jeg erfaring med at lede udviklingsteams og træffe de store tekniske beslutninger.",[48,84,85,88],{},[67,86,87],{},"Freelance"," (mange år) — Her lærte jeg at drive en forretning, styre kunderelationer, og tage fuldt ansvar for leverancen. Ingen at gemme sig bag — det var mig og kun mig.",[43,90,92],{"id":91},"hvad-freelance-lærte-mig-om-ledelse","Hvad freelance lærte mig om ledelse",[48,94,95],{},"Mange tænker på freelance som \"bare at kode for sig selv.\" Men virkeligheden er, at freelance er en masterclass i mange af de kompetencer man har brug for som leder:",[48,97,98,101],{},[67,99,100],{},"Kundehåndtering er stakeholder management."," Når du er freelance, lærer du at forstå hvad kunden virkelig har brug for (ikke bare hvad de beder om), at kommunikere proaktivt, og at styre forventninger. Det er præcis de samme skills du bruger som Technical Director.",[48,103,104,107],{},[67,105,106],{},"Estimering er strategisk tænkning."," At give et tilbud på et projekt kræver at du kan nedbryde kompleksitet, identificere risici og træffe de rigtige antagelser. Det er det samme du gør når du lægger en teknisk roadmap.",[48,109,110,113],{},[67,111,112],{},"Ansvar for hele leverancen er ledelse."," Når du er den eneste på projektet, lærer du at se helheden — design, kode, performance, SEO, deployment, vedligeholdelse. Den holistiske tankegang er uvurderlig som leder.",[43,115,117],{"id":116},"de-5-vigtigste-ting-jeg-lærte-på-vejen","De 5 vigtigste ting jeg lærte på vejen",[119,120,122],"h3",{"id":121},"_1-koden-er-ikke-produktet","1. Koden er ikke produktet",[48,124,125],{},"Det tog mig år at forstå dette fuldt ud. Kunden køber ikke kode — de køber en løsning på et problem. Den bedste kode i verden er værdiløs hvis den ikke løser det rigtige problem, for de rigtige mennesker, på det rigtige tidspunkt.",[48,127,128],{},"Som Technical Director er mit job at sikre at vi bygger det rigtige, ikke bare at vi bygger det rigtigt.",[119,130,132],{"id":131},"_2-kommunikation-er-vigtigere-end-teknisk-kunnen","2. Kommunikation er vigtigere end teknisk kunnen",[48,134,135],{},"Den dygtigste udvikler jeg nogensinde har arbejdet med var også den dårligste til at kommunikere. Resultatet? Projekter der gik galt fordi ingen forstod hvad der foregik.",[48,137,138],{},"Omvendt har jeg set middelmådige udviklere levere fantastiske resultater fordi de var gode til at stille de rigtige spørgsmål, kommunikere risici tidligt og holde alle informeret.",[119,140,142],{"id":141},"_3-sig-nej-oftere","3. Sig nej oftere",[48,144,145],{},"Både som freelance og som leder er evnen til at sige nej en superkraft. Nej til features der ikke skaber værdi. Nej til tekniske valg der føjer kompleksitet uden gevinst. Nej til projekter der ikke passer.",[48,147,148],{},"Hvert ja er et nej til noget andet. Vælg med omtanke.",[119,150,152],{"id":151},"_4-teknisk-gæld-er-en-forretningsbeslutning","4. Teknisk gæld er en forretningsbeslutning",[48,154,155],{},"Teknisk gæld er ikke altid dårligt. Nogen gange er det den rigtige beslutning at tage en genvej for at nå markedet hurtigere. Problemet opstår når gælden ikke er bevidst — når ingen har truffet et aktivt valg.",[48,157,158],{},"Som Technical Director er min rolle at gøre teknisk gæld synlig og sikre at det er en bevidst afvejning, ikke en tilfældighed.",[119,160,162],{"id":161},"_5-de-bedste-løsninger-kommer-fra-de-bedste-teams","5. De bedste løsninger kommer fra de bedste teams",[48,164,165,166,170],{},"Tidligt i karrieren troede jeg at den bedste udvikler leverede det bedste resultat. Nu ved jeg at det bedste ",[167,168,169],"em",{},"team"," leverer det bedste resultat. Min rolle er at skabe rammerne for at teamet kan gøre sit bedste arbejde — ikke at være den der skriver den smarteste kode.",[43,172,174],{"id":173},"hvad-er-en-technical-director","Hvad er en Technical Director?",[48,176,177],{},"Rollen varierer fra virksomhed til virksomhed, men for mig handler det om tre ting:",[48,179,180,183],{},[67,181,182],{},"Teknisk retning"," — At sætte den overordnede tekniske strategi og sikre at arkitekturbeslutninger understøtter forretningens mål. Ikke bare i dag, men også om 2-3 år.",[48,185,186,189],{},[67,187,188],{},"Team og mennesker"," — At hjælpe udviklere med at vokse, fjerne blokeringer, og skabe et miljø hvor folk kan gøre deres bedste arbejde.",[48,191,192,195],{},[67,193,194],{},"Bro mellem forretning og teknik"," — At oversætte forretningsstrategi til tekniske prioriteringer og omvendt. At sikre at tekniske beslutninger forstås af hele organisationen.",[43,197,199],{"id":198},"hvorfor-jeg-stadig-koder","Hvorfor jeg stadig koder",[48,201,202],{},"Selvom min rolle primært er strategisk og ledelsesmæssig, holder jeg mig skarp ved stadig at kode. Ikke fordi jeg skal, men fordi det giver mig bedre forudsætninger for at træffe gode tekniske beslutninger.",[48,204,205],{},"En Technical Director der ikke forstår koden, kan ikke vurdere arkitekturforslag, estimere kompleksitet eller have meningsfulde samtaler med sit team. Det er som en fodboldtræner der aldrig selv har spillet.",[43,207,209],{"id":208},"hvad-nu","Hvad nu?",[48,211,212],{},"Jeg er stadig tidligt i min rejse som Technical Director, og der er enormt meget at lære. Men en ting er jeg sikker på: de 19+ år som udvikler og freelance har givet mig et fundament der er svært at få andre steder.",[48,214,215],{},"Hvis du står et lignende sted i din karriere — mellem kode og ledelse, mellem freelance og fast rolle — så vil jeg gerne høre fra dig. Del gerne dine tanker og erfaringer.",{"title":217,"searchDepth":218,"depth":218,"links":219},"",2,[220,221,222,223,231,232,233],{"id":45,"depth":218,"text":46},{"id":59,"depth":218,"text":60},{"id":91,"depth":218,"text":92},{"id":116,"depth":218,"text":117,"children":224},[225,227,228,229,230],{"id":121,"depth":226,"text":122},3,{"id":131,"depth":226,"text":132},{"id":141,"depth":226,"text":142},{"id":151,"depth":226,"text":152},{"id":161,"depth":226,"text":162},{"id":173,"depth":218,"text":174},{"id":198,"depth":218,"text":199},{"id":208,"depth":218,"text":209},"2026-04-03","Efter 19+ år som freelance udvikler tog jeg springet til en fast rolle som Technical Director. Her er hvad jeg lærte, og hvad der ændrede sig.","md",{},true,"\u002Fblog\u002Ffra-freelance-udvikler-til-technical-director",{"title":38,"description":235},"Efter 19+ år som freelance udvikler blev jeg Technical Director hos Checkmate.dk. Her er de vigtigste lærdomme fra rejsen — og hvad der ændrede sig.","Fra Freelance Udvikler til Technical Director — Hvad Jeg Lærte","fra-freelance-udvikler-til-technical-director","blog\u002Ffra-freelance-udvikler-til-technical-director",[246,247,248,249],"karriere","ledelse","tech-lead","erfaring","\u002Fimages\u002Fcontentful\u002Fnickychristensen.png","SnOIMB1_iafUQB_RrXYn5xeF3yHiNgiiLAdr0ntziww",{"id":253,"title":254,"body":255,"date":234,"description":986,"extension":236,"meta":987,"navigation":238,"noindex":8,"path":988,"seo":989,"seoDescription":990,"seoTitle":991,"slug":992,"stem":993,"tags":994,"thumbnail":1000,"updated":234,"__hash__":1001},"blog\u002Fblog\u002Ffrontend-arkitektur-for-store-projekter.md","Frontend arkitektur for store projekter — Sådan skalerer du din kodebase",{"type":40,"value":256,"toc":975},[257,260,263,266,270,273,279,289,292,302,305,309,312,318,324,500,506,509,513,516,621,624,646,649,653,656,659,698,701,705,708,714,725,731,742,745,748,752,755,761,767,857,876,882,886,889,895,901,907,910,914,917,923,929,943,949,953,956,959,962,971],[48,258,259],{},"Når du arbejder på et frontend-projekt med 2-3 udviklere, kan du slippe afsted med mange ting. Mappestruktur? Det løser sig selv. State management? Props er fint. Kodekonventioner? Vi snakker bare sammen.",[48,261,262],{},"Men når teamet vokser til 10, 20 eller 50 udviklere, og kodebasen rammer hundredtusinder af linjer kode, så falder den tilgang fra hinanden. Pludselig er der konflikter i hver merge request, ingen kan finde noget, og performance er gået i stændig tilbagegang.",[48,264,265],{},"Jeg har arbejdet med frontend i enterprise-skala hos Grundfos, Vestas, Playable og Harness — og nu som Technical Director hos Checkmate.dk. Her er de vigtigste lærdomme om hvordan du arkitekterer frontend-applikationer der faktisk skalerer.",[43,267,269],{"id":268},"komponentarkitektur-og-mappestruktur","Komponentarkitektur og mappestruktur",[48,271,272],{},"Den første og mest grundlæggende beslutning er hvordan du organiserer dine komponenter. Jeg har set to primære tilgange:",[48,274,275,278],{},[67,276,277],{},"Feature-baseret struktur"," er næsten altid det rigtige valg for store projekter. I stedet for at gruppere efter type (alle buttons i en mappe, alle modals i en anden), grupperer du efter feature:",[280,281,286],"pre",{"className":282,"code":284,"language":285},[283],"language-text","components\u002F\n  Dashboard\u002F\n    DashboardView.vue\n    DashboardStats.vue\n    DashboardChart.vue\n    useDashboardData.ts\n  UserProfile\u002F\n    UserProfileView.vue\n    UserProfileForm.vue\n    useUserProfile.ts\n  UI\u002F\n    BaseButton.vue\n    BaseModal.vue\n    BaseInput.vue\n","text",[287,288,284],"code",{"__ignoreMap":217},[48,290,291],{},"Grunden er simpel: når en udvikler arbejder på en feature, skal de kun røre filer i en mappe. Det reducerer merge-konflikter drastisk og gør det nemmere at forstå konteksten.",[48,293,294,297,298,301],{},[67,295,296],{},"UI-komponenter"," (buttons, inputs, modals) lever for sig selv i en delt mappe, fordi de bruges på tværs af features. Men feature-specifikke komponenter hører til i feature-mappen — ikke i en generisk ",[287,299,300],{},"components\u002F"," rod.",[48,303,304],{},"En tommelfingerregel jeg bruger: Hvis en komponent kun bruges et sted, hører den til i den features mappe. Først når den bruges to eller flere steder, flyttes den til en delt mappe.",[43,306,308],{"id":307},"state-management-pinia-vs-composables-vs-props","State management — Pinia vs composables vs props",[48,310,311],{},"Et af de mest debatterede emner i frontend-verdenen. I Vue-økosystemet har vi Pinia, composables og props. I React er det Redux\u002FZustand, hooks og props. Men principperne er de samme.",[48,313,314,317],{},[67,315,316],{},"Props"," er førstevalget. Altid. Data der flyder fra forælder til barn er det simpleste og mest forudsigelige mønster. Når folk klager over \"prop drilling\", er det ofte et tegn på at komponenthierarkiet er forkert — ikke at du mangler global state.",[48,319,320,323],{},[67,321,322],{},"Composables (eller custom hooks)"," er næste trin. Når logik skal deles mellem komponenter der ikke har et direkte forælder-barn-forhold, er en composable perfekt. Den indkapsler logik og state uden at gøre det globalt.",[280,325,329],{"className":326,"code":327,"language":328,"meta":217,"style":217},"language-typescript shiki shiki-themes github-dark","\u002F\u002F useCurrentUser.ts\nexport function useCurrentUser() {\n  const user = ref\u003CUser | null>(null)\n  const isLoading = ref(false)\n\n  async function fetchUser() {\n    isLoading.value = true\n    user.value = await api.getCurrentUser()\n    isLoading.value = false\n  }\n\n  return { user, isLoading, fetchUser }\n}\n","typescript",[287,330,331,340,357,393,413,419,432,444,464,474,480,485,494],{"__ignoreMap":217},[332,333,336],"span",{"class":334,"line":335},"line",1,[332,337,339],{"class":338},"sAwPA","\u002F\u002F useCurrentUser.ts\n",[332,341,342,346,349,353],{"class":334,"line":218},[332,343,345],{"class":344},"snl16","export",[332,347,348],{"class":344}," function",[332,350,352],{"class":351},"svObZ"," useCurrentUser",[332,354,356],{"class":355},"s95oV","() {\n",[332,358,359,362,366,369,372,375,378,381,384,387,390],{"class":334,"line":226},[332,360,361],{"class":344},"  const",[332,363,365],{"class":364},"sDLfK"," user",[332,367,368],{"class":344}," =",[332,370,371],{"class":351}," ref",[332,373,374],{"class":355},"\u003C",[332,376,377],{"class":351},"User",[332,379,380],{"class":344}," |",[332,382,383],{"class":364}," null",[332,385,386],{"class":355},">(",[332,388,389],{"class":364},"null",[332,391,392],{"class":355},")\n",[332,394,396,398,401,403,405,408,411],{"class":334,"line":395},4,[332,397,361],{"class":344},[332,399,400],{"class":364}," isLoading",[332,402,368],{"class":344},[332,404,371],{"class":351},[332,406,407],{"class":355},"(",[332,409,410],{"class":364},"false",[332,412,392],{"class":355},[332,414,416],{"class":334,"line":415},5,[332,417,418],{"emptyLinePlaceholder":238},"\n",[332,420,422,425,427,430],{"class":334,"line":421},6,[332,423,424],{"class":344},"  async",[332,426,348],{"class":344},[332,428,429],{"class":351}," fetchUser",[332,431,356],{"class":355},[332,433,435,438,441],{"class":334,"line":434},7,[332,436,437],{"class":355},"    isLoading.value ",[332,439,440],{"class":344},"=",[332,442,443],{"class":364}," true\n",[332,445,447,450,452,455,458,461],{"class":334,"line":446},8,[332,448,449],{"class":355},"    user.value ",[332,451,440],{"class":344},[332,453,454],{"class":344}," await",[332,456,457],{"class":355}," api.",[332,459,460],{"class":351},"getCurrentUser",[332,462,463],{"class":355},"()\n",[332,465,467,469,471],{"class":334,"line":466},9,[332,468,437],{"class":355},[332,470,440],{"class":344},[332,472,473],{"class":364}," false\n",[332,475,477],{"class":334,"line":476},10,[332,478,479],{"class":355},"  }\n",[332,481,483],{"class":334,"line":482},11,[332,484,418],{"emptyLinePlaceholder":238},[332,486,488,491],{"class":334,"line":487},12,[332,489,490],{"class":344},"  return",[332,492,493],{"class":355}," { user, isLoading, fetchUser }\n",[332,495,497],{"class":334,"line":496},13,[332,498,499],{"class":355},"}\n",[48,501,502,505],{},[67,503,504],{},"Pinia\u002FRedux"," er kun til ægte global state — ting som den aktuelle bruger, tema-indstillinger, notifikationer. Hvis du har mere end 10-15 stores, har du sandsynligvis lagt for meget i global state.",[48,507,508],{},"Min erfaring fra Harness, hvor vi havde en stor Vue-applikation: Teamet startede med at lægge alt i Vuex (forgængeren til Pinia). Resultatet var en massiv, uforudsigelig state-graf hvor ingen vidste hvad der påvirkede hvad. Da vi refaktorerede til composables for feature-specifik state og kun beholdt ægte global state i stores, blev kodebasen markant nemmere at arbejde med.",[43,510,512],{"id":511},"code-splitting-og-lazy-loading","Code splitting og lazy loading",[48,514,515],{},"I en stor applikation er det afgørende at brugeren ikke skal downloade hele din kodebase for at se første side. Både Vue Router og React Router understøtter lazy loading af routes ud af boksen:",[280,517,519],{"className":326,"code":518,"language":328,"meta":217,"style":217},"\u002F\u002F Vue Router\nconst routes = [\n  {\n    path: '\u002Fdashboard',\n    component: () => import('.\u002Fpages\u002FDashboard.vue')\n  },\n  {\n    path: '\u002Fsettings',\n    component: () => import('.\u002Fpages\u002FSettings.vue')\n  }\n]\n",[287,520,521,526,539,544,556,577,582,586,595,612,616],{"__ignoreMap":217},[332,522,523],{"class":334,"line":335},[332,524,525],{"class":338},"\u002F\u002F Vue Router\n",[332,527,528,531,534,536],{"class":334,"line":218},[332,529,530],{"class":344},"const",[332,532,533],{"class":364}," routes",[332,535,368],{"class":344},[332,537,538],{"class":355}," [\n",[332,540,541],{"class":334,"line":226},[332,542,543],{"class":355},"  {\n",[332,545,546,549,553],{"class":334,"line":395},[332,547,548],{"class":355},"    path: ",[332,550,552],{"class":551},"sU2Wk","'\u002Fdashboard'",[332,554,555],{"class":355},",\n",[332,557,558,561,564,567,570,572,575],{"class":334,"line":415},[332,559,560],{"class":351},"    component",[332,562,563],{"class":355},": () ",[332,565,566],{"class":344},"=>",[332,568,569],{"class":344}," import",[332,571,407],{"class":355},[332,573,574],{"class":551},"'.\u002Fpages\u002FDashboard.vue'",[332,576,392],{"class":355},[332,578,579],{"class":334,"line":421},[332,580,581],{"class":355},"  },\n",[332,583,584],{"class":334,"line":434},[332,585,543],{"class":355},[332,587,588,590,593],{"class":334,"line":446},[332,589,548],{"class":355},[332,591,592],{"class":551},"'\u002Fsettings'",[332,594,555],{"class":355},[332,596,597,599,601,603,605,607,610],{"class":334,"line":466},[332,598,560],{"class":351},[332,600,563],{"class":355},[332,602,566],{"class":344},[332,604,569],{"class":344},[332,606,407],{"class":355},[332,608,609],{"class":551},"'.\u002Fpages\u002FSettings.vue'",[332,611,392],{"class":355},[332,613,614],{"class":334,"line":476},[332,615,479],{"class":355},[332,617,618],{"class":334,"line":482},[332,619,620],{"class":355},"]\n",[48,622,623],{},"Men routes er bare begyndelsen. I store projekter bør du også overveje:",[625,626,627,634,640],"ul",{},[628,629,630,633],"li",{},[67,631,632],{},"Lazy loading af tunge komponenter"," — Diagrammer, editorer, og lignende bør loades on-demand",[628,635,636,639],{},[67,637,638],{},"Prefetching af sandsynlige næste sider"," — Hvis 80% af brugerne går fra dashboard til rapporter, så prefetch rapporter-chunken",[628,641,642,645],{},[67,643,644],{},"Dynamiske imports for tredjepartsbiblioteker"," — Lad være med at bundle moment.js eller lodash ind i din hovedbundle hvis det kun bruges et sted",[48,647,648],{},"Den største fejl jeg ser er at teams optimerer for tidligt. Start med route-baseret code splitting. Mål din bundle-størrelse. Optimer derefter de største chunks først.",[43,650,652],{"id":651},"design-system-integration","Design system integration",[48,654,655],{},"Når du har mere end 3-4 frontend-udviklere, har du brug for et design system. Ikke et fancy Storybook-setup med 200 komponenter — men en fælles forståelse af de basale byggeklodser.",[48,657,658],{},"Et effektivt design system i praksis:",[660,661,662,668,674],"ol",{},[628,663,664,667],{},[67,665,666],{},"Tokens først"," — Definer farver, spacing, typografi og breakpoints som design tokens (CSS custom properties eller en theme-fil). Alt andet bygger på disse.",[628,669,670,673],{},[67,671,672],{},"Primitive komponenter"," — Button, Input, Select, Modal, Card. Maks 15-20 komponenter. De skal være veltestede og veldokumenterede.",[628,675,676,679,680,683,684,687,688,687,691,687,694,697],{},[67,677,678],{},"Kompositionsmønstret"," — Byg komplekse komponenter ved at kombinere primitive. Lad være med at lave en ",[287,681,682],{},"SuperTable"," der kan alt — lav i stedet ",[287,685,686],{},"Table",", ",[287,689,690],{},"TableHeader",[287,692,693],{},"TableRow",[287,695,696],{},"TableCell"," der kan sammensættes.",[48,699,700],{},"Det vigtigste er at design systemet lever tæt på koden. Jeg har set for mange teams hvor design systemet er et separat projekt der altid er bagud. Når det lever i en delt pakke i din monorepo (eller som en npm-pakke med hurtig release-cyklus), bliver det faktisk brugt.",[43,702,704],{"id":703},"monorepo-vs-polyrepo","Monorepo vs polyrepo",[48,706,707],{},"Det her er en beslutning der har store konsekvenser, og der er ikke et universelt svar.",[48,709,710,713],{},[67,711,712],{},"Monorepo"," (alle pakker i et repository) er bedst når:",[625,715,716,719,722],{},[628,717,718],{},"Teams deler meget kode (design system, utilities, typer)",[628,720,721],{},"Du vil have atomare ændringer på tværs af pakker",[628,723,724],{},"Du har værktøj til det (Nx, Turborepo, eller Lerna)",[48,726,727,730],{},[67,728,729],{},"Polyrepo"," (separate repositories) er bedst når:",[625,732,733,736,739],{},[628,734,735],{},"Teams er meget autonome og sjældent deler kode",[628,737,738],{},"Du har strikse deployment-boundaries",[628,740,741],{},"Teams bruger forskellige tech stacks",[48,743,744],{},"Min erfaring: For de fleste frontend-teams er en monorepo det rigtige valg. Værktøjerne (særligt Nx og Turborepo) er blevet så modne at overhead er minimal, og fordelen ved at kunne dele typer, konfiguration og design system-komponenter er enorm.",[48,746,747],{},"Hos Vestas arbejdede vi med en polyrepo-tilgang der betød at vi konstant kæmpede med at holde delte biblioteker i sync. Hos Playable skiftede vi til monorepo, og det var en game-changer for developer experience.",[43,749,751],{"id":750},"typescript-som-skaleringsværktøj","TypeScript som skaleringsværktøj",[48,753,754],{},"TypeScript er ikke bare \"JavaScript med typer.\" I store projekter er det et arkitekturværktøj.",[48,756,757,760],{},[67,758,759],{},"Interfaces som kontrakter."," Når team A bygger en API og team B bruger den, fungerer TypeScript-interfaces som en levende kontrakt. Hvis API'en ændrer sig, får team B en kompileringsfejl — ikke en runtime-fejl i produktion kl. 3 om natten.",[48,762,763,766],{},[67,764,765],{},"Strenge typer for domæneobjekter."," Definer dine domæneobjekter som TypeScript-typer og brug dem konsekvent:",[280,768,770],{"className":326,"code":769,"language":328,"meta":217,"style":217},"interface Order {\n  id: string\n  status: 'pending' | 'confirmed' | 'shipped' | 'delivered'\n  items: OrderItem[]\n  customer: Customer\n  createdAt: Date\n}\n",[287,771,772,783,795,820,833,843,853],{"__ignoreMap":217},[332,773,774,777,780],{"class":334,"line":335},[332,775,776],{"class":344},"interface",[332,778,779],{"class":351}," Order",[332,781,782],{"class":355}," {\n",[332,784,785,789,792],{"class":334,"line":218},[332,786,788],{"class":787},"s9osk","  id",[332,790,791],{"class":344},":",[332,793,794],{"class":364}," string\n",[332,796,797,800,802,805,807,810,812,815,817],{"class":334,"line":226},[332,798,799],{"class":787},"  status",[332,801,791],{"class":344},[332,803,804],{"class":551}," 'pending'",[332,806,380],{"class":344},[332,808,809],{"class":551}," 'confirmed'",[332,811,380],{"class":344},[332,813,814],{"class":551}," 'shipped'",[332,816,380],{"class":344},[332,818,819],{"class":551}," 'delivered'\n",[332,821,822,825,827,830],{"class":334,"line":395},[332,823,824],{"class":787},"  items",[332,826,791],{"class":344},[332,828,829],{"class":351}," OrderItem",[332,831,832],{"class":355},"[]\n",[332,834,835,838,840],{"class":334,"line":415},[332,836,837],{"class":787},"  customer",[332,839,791],{"class":344},[332,841,842],{"class":351}," Customer\n",[332,844,845,848,850],{"class":334,"line":421},[332,846,847],{"class":787},"  createdAt",[332,849,791],{"class":344},[332,851,852],{"class":351}," Date\n",[332,854,855],{"class":334,"line":434},[332,856,499],{"class":355},[48,858,859,860,863,864,867,868,871,872,875],{},"Når ",[287,861,862],{},"status"," er en union type i stedet for en ",[287,865,866],{},"string",", kan du ikke ved et uheld sætte den til ",[287,869,870],{},"\"PENDING\""," eller ",[287,873,874],{},"\"Shipped\"",". Det lyder som en lille ting, men i en kodebase med 50 udviklere forhindrer det hundredevis af bugs.",[48,877,878,881],{},[67,879,880],{},"Generics for genbrugelig kode."," Composables og utility-funktioner der bruger generics er mærkbart nemmere at genbruge korrekt i store teams.",[43,883,885],{"id":884},"teststrategi-i-skala","Teststrategi i skala",[48,887,888],{},"Store projekter har brug for en strategi — ikke bare \"vi skriver tests.\" Her er den pyramide jeg anbefaler:",[48,890,891,894],{},[67,892,893],{},"Unit tests (70%)"," — Test composables, utility-funktioner og forretningslogik. De er hurtige, stabile og giver mest værdi per tidsenhed.",[48,896,897,900],{},[67,898,899],{},"Komponent-tests (20%)"," — Test at komponenter renderer korrekt med forskellige props og håndterer brugerinteraktion. Brug Vue Test Utils eller React Testing Library.",[48,902,903,906],{},[67,904,905],{},"End-to-end tests (10%)"," — Test kritiske brugerflows (login, checkout, osv.) med Playwright eller Cypress. Hold antallet lavt — de er langsomme og skrøbelige.",[48,908,909],{},"Den største fejl er at starte med E2E-tests. De er dyre at vedligeholde og giver falsk tryghed. Start med unit tests af din forretningslogik, og tilføj E2E-tests for de mest kritiske flows.",[43,911,913],{"id":912},"teamkonventioner-og-code-review","Teamkonventioner og code review",[48,915,916],{},"Værktøj og arkitektur er kun halvdelen. Den anden halvdel er mennesker og processer.",[48,918,919,922],{},[67,920,921],{},"Automatiser hvad der kan automatiseres."," ESLint, Prettier, husky pre-commit hooks. Diskuter ikke formatering i code reviews — lad værktøjerne håndtere det.",[48,924,925,928],{},[67,926,927],{},"Brug ADR'er (Architecture Decision Records)."," Når teamet træffer en større beslutning (f.eks. \"vi bruger Pinia i stedet for composables til global state\"), skriv det ned med kontekst og begrundelse. Nye teammedlemmer vil takke dig.",[48,930,931,934,935,938,939,942],{},[67,932,933],{},"Code reviews er læring, ikke gatekeeping."," De bedste teams jeg har arbejdet med bruger code reviews som en mulighed for videndeling. Forklar ",[167,936,937],{},"hvorfor"," du foreslår en ændring, ikke bare ",[167,940,941],{},"hvad",". Og vær åben for at lære noget nyt fra den der har skrevet koden.",[48,944,945,948],{},[67,946,947],{},"Definer \"done\" for komponenter."," En komponent er ikke færdig når den virker. Den er færdig når den har typer, er testet, er dokumenteret (mindst en kommentar med et eksempel), og er reviewet.",[43,950,952],{"id":951},"afslutningstanker","Afslutningstanker",[48,954,955],{},"God frontend-arkitektur handler ikke om at vælge det rigtige framework eller det nyeste værktøj. Det handler om at skabe struktur der gør det muligt for mange mennesker at arbejde effektivt på den samme kodebase over lang tid.",[48,957,958],{},"Start simpelt. Tilføj kompleksitet når du har bevist at du har brug for det. Og husk: den bedste arkitektur er den dit team faktisk forstår og følger.",[960,961],"hr",{},[48,963,964,965,970],{},"Har du brug for hjælp med at skalere din frontend-arkitektur? Jeg arbejder til dagligt med disse udfordringer som Technical Director hos Checkmate.dk, og jeg deler regelmæssigt mine erfaringer her på bloggen. ",[966,967,969],"a",{"href":968},"\u002Fkontakt","Kontakt mig"," hvis du vil diskutere dit projekt, eller følg med her for flere artikler om frontend i enterprise-skala.",[972,973,974],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":217,"searchDepth":218,"depth":218,"links":976},[977,978,979,980,981,982,983,984,985],{"id":268,"depth":218,"text":269},{"id":307,"depth":218,"text":308},{"id":511,"depth":218,"text":512},{"id":651,"depth":218,"text":652},{"id":703,"depth":218,"text":704},{"id":750,"depth":218,"text":751},{"id":884,"depth":218,"text":885},{"id":912,"depth":218,"text":913},{"id":951,"depth":218,"text":952},"Hvordan arkitekterer du frontend-applikationer der skalerer? Her er mine erfaringer fra 19+ år med enterprise-projekter hos Grundfos, Vestas, Playable og Harness.",{},"\u002Fblog\u002Ffrontend-arkitektur-for-store-projekter",{"title":254,"description":986},"Lær at arkitektere frontend-applikationer der skalerer. Praktiske tips om komponentarkitektur, state management, TypeScript og teamkonventioner.","Frontend Arkitektur for Store Projekter — Skalering, Patterns og Best Practices","frontend-arkitektur-for-store-projekter","blog\u002Ffrontend-arkitektur-for-store-projekter",[995,996,328,997,998,999],"frontend","arkitektur","vue","react","enterprise","\u002Fimages\u002Fcontentful\u002Fblog-typescript.png","iudtKHtProPWl3tsX982-Uk__W7bE_DaSy3xhLasrGU",{"id":1003,"title":1004,"body":1005,"date":234,"description":1383,"extension":236,"meta":1384,"navigation":238,"noindex":8,"path":1385,"seo":1386,"seoDescription":1387,"seoTitle":1388,"slug":1389,"stem":1390,"tags":1391,"thumbnail":1000,"updated":234,"__hash__":1394},"blog\u002Fblog\u002Freact-vs-vue-i-2026.md","React vs Vue i 2026 — En erfaren udviklers perspektiv",{"type":40,"value":1006,"toc":1358},[1007,1011,1014,1017,1020,1024,1150,1154,1158,1161,1164,1168,1171,1175,1178,1182,1185,1189,1193,1196,1199,1203,1206,1210,1213,1217,1234,1238,1270,1274,1306,1310,1314,1317,1321,1324,1328,1331,1335,1342,1345,1349,1352,1355],[43,1008,1010],{"id":1009},"jeg-har-brugt-begge-i-mange-år","Jeg har brugt begge — i mange år",[48,1012,1013],{},"Dette er ikke en af de artikler der er skrevet af nogen der har læst dokumentationen og sammenlignet bullet points. Jeg har brugt både React og Vue professionelt i adskillige år — Vue hos Playable og i mine egne projekter, React hos Grundfos, Vestas og Harness.",[48,1015,1016],{},"Jeg har bygget SaaS-platforme, enterprise-løsninger og websites med begge frameworks. Og mit svar på \"hvad er bedst?\" er det samme som altid: det kommer an på.",[48,1018,1019],{},"Men lad mig være mere specifik end det.",[43,1021,1023],{"id":1022},"hurtigt-overblik","Hurtigt overblik",[1025,1026,1027,1042],"table",{},[1028,1029,1030],"thead",{},[1031,1032,1033,1036,1039],"tr",{},[1034,1035],"th",{},[1034,1037,1038],{},"React",[1034,1040,1041],{},"Vue",[1043,1044,1045,1059,1072,1085,1098,1111,1124,1137],"tbody",{},[1031,1046,1047,1053,1056],{},[1048,1049,1050],"td",{},[67,1051,1052],{},"Skabt af",[1048,1054,1055],{},"Meta (Facebook)",[1048,1057,1058],{},"Evan You \u002F community",[1031,1060,1061,1066,1069],{},[1048,1062,1063],{},[67,1064,1065],{},"Første release",[1048,1067,1068],{},"2013",[1048,1070,1071],{},"2014",[1031,1073,1074,1079,1082],{},[1048,1075,1076],{},[67,1077,1078],{},"Popularitet",[1048,1080,1081],{},"Størst community og jobmarked",[1048,1083,1084],{},"Større i Asien, voksende i Europa",[1031,1086,1087,1092,1095],{},[1048,1088,1089],{},[67,1090,1091],{},"Læringskurve",[1048,1093,1094],{},"Stejlere",[1048,1096,1097],{},"Blødere",[1031,1099,1100,1105,1108],{},[1048,1101,1102],{},[67,1103,1104],{},"Rendering",[1048,1106,1107],{},"JSX (JavaScript + HTML)",[1048,1109,1110],{},"Templates (HTML + directives)",[1031,1112,1113,1118,1121],{},[1048,1114,1115],{},[67,1116,1117],{},"State management",[1048,1119,1120],{},"Mange valg (Redux, Zustand, Jotai)",[1048,1122,1123],{},"Pinia (officiel)",[1031,1125,1126,1131,1134],{},[1048,1127,1128],{},[67,1129,1130],{},"Meta-framework",[1048,1132,1133],{},"Next.js",[1048,1135,1136],{},"Nuxt",[1031,1138,1139,1144,1147],{},[1048,1140,1141],{},[67,1142,1143],{},"TypeScript",[1048,1145,1146],{},"Førsteklasses support",[1048,1148,1149],{},"Førsteklasses support (fra Vue 3)",[43,1151,1153],{"id":1152},"hvor-react-udmærker-sig","Hvor React udmærker sig",[119,1155,1157],{"id":1156},"større-økosystem-og-jobmarked","Større økosystem og jobmarked",[48,1159,1160],{},"React har det største økosystem i frontend-verdenen. Der er flere biblioteker, flere tutorials, flere svar på Stack Overflow, og langt flere jobopslag. Hvis du optimerer for karrieremuligheder, er React det sikre valg.",[48,1162,1163],{},"I Danmark er React stadig det mest efterspurgte frontend-framework på jobmarkedet — særligt i enterprise-segmentet.",[119,1165,1167],{"id":1166},"fleksibilitet","Fleksibilitet",[48,1169,1170],{},"React er et bibliotek, ikke et framework. Det giver dig frihed til at vælge din egen state management, routing, og arkitektur. For erfarne teams der ved hvad de vil, er den fleksibilitet en styrke.",[119,1172,1174],{"id":1173},"react-server-components-og-server-actions","React Server Components og Server Actions",[48,1176,1177],{},"React har med Server Components taget et stort skridt mod server-side rendering der føles naturligt. Det er en arkitektonisk innovation der giver mulighed for at blande server- og klient-kode på en måde der er unik for React.",[119,1179,1181],{"id":1180},"react-native","React Native",[48,1183,1184],{},"Hvis du har brug for at bygge mobile apps, er React Native det største cross-platform framework. At dele kode mellem web og mobil med samme team er en reel fordel.",[43,1186,1188],{"id":1187},"hvor-vue-udmærker-sig","Hvor Vue udmærker sig",[119,1190,1192],{"id":1191},"læringskurven-er-kortere","Læringskurven er kortere",[48,1194,1195],{},"Vue er lettere at lære for både nye og erfarne udviklere. Template-syntaksen er mere intuitiv end JSX, og Vue's Composition API giver den samme kraft som React Hooks, men med en blødere læringskurve.",[48,1197,1198],{},"Jeg har onboardet mange udviklere til begge frameworks, og Vue-teams er konsekvent produktive hurtigere.",[119,1200,1202],{"id":1201},"bedre-batteries-included","Bedre \"batteries included\"",[48,1204,1205],{},"Vue har officielle løsninger for de fleste behov: Pinia til state management, Vue Router til routing, og Nuxt som meta-framework. Du slipper for at evaluere og vælge mellem 10 forskellige state management-biblioteker.",[119,1207,1209],{"id":1208},"composition-api-er-elegant","Composition API er elegant",[48,1211,1212],{},"Vue 3's Composition API er efter min mening den reneste måde at skrive reaktiv logik på. Composables (Vue's svar på custom hooks) er nemmere at læse, teste og genbruge end React hooks, primært fordi du slipper for at tænke på dependency arrays og re-renders.",[119,1214,1216],{"id":1215},"reaktivitetssystem","Reaktivitetssystem",[48,1218,1219,1220,1222,1223,687,1226,1229,1230,1233],{},"Vue's fine-grained reaktivitet er smartere end React's re-rendering model. Vue ved præcis ",[167,1221,941],{}," der har ændret sig og opdaterer kun det nødvendige. React re-renderer hele komponenten og dens børn, hvilket kræver at du tænker over ",[287,1224,1225],{},"useMemo",[287,1227,1228],{},"useCallback"," og ",[287,1231,1232],{},"React.memo"," for at undgå performance-problemer.",[43,1235,1237],{"id":1236},"hvornår-skal-du-vælge-react","Hvornår skal du vælge React?",[625,1239,1240,1246,1252,1258,1264],{},[628,1241,1242,1245],{},[67,1243,1244],{},"Dit team kender allerede React"," — Det vigtigste argument. Skift ikke framework for sjov",[628,1247,1248,1251],{},[67,1249,1250],{},"Du har brug for React Native"," — Hvis mobil er en del af planen",[628,1253,1254,1257],{},[67,1255,1256],{},"Du ansætter i et stort marked"," — Der er flere React-udviklere at vælge imellem",[628,1259,1260,1263],{},[67,1261,1262],{},"Du bygger på et eksisterende React-økosystem"," — Mange virksomheder har interne React-biblioteker og tooling",[628,1265,1266,1269],{},[67,1267,1268],{},"Enterprise med mange teams"," — React's fleksibilitet giver teams mulighed for at vælge deres egne patterns",[43,1271,1273],{"id":1272},"hvornår-skal-du-vælge-vue","Hvornår skal du vælge Vue?",[625,1275,1276,1282,1288,1294,1300],{},[628,1277,1278,1281],{},[67,1279,1280],{},"Du starter et nyt projekt"," — Vue's opinionated tilgang giver hurtigere time-to-market",[628,1283,1284,1287],{},[67,1285,1286],{},"Dit team har blandet erfaring"," — Vue er lettere at lære for juniors og backendudviklere",[628,1289,1290,1293],{},[67,1291,1292],{},"Du bygger et content-site eller marketing-site"," — Nuxt's statiske generering og SEO-support er fremragende",[628,1295,1296,1299],{},[67,1297,1298],{},"Performance er kritisk"," — Vue's reaktivitetssystem giver bedre out-of-the-box performance",[628,1301,1302,1305],{},[67,1303,1304],{},"Du vil have en sammenhængende stack"," — Vue + Pinia + Nuxt er en tight integration uden compatibility-sorger",[43,1307,1309],{"id":1308},"hvad-med-andre-frameworks","Hvad med andre frameworks?",[119,1311,1313],{"id":1312},"sveltesveltekit","Svelte\u002FSvelteKit",[48,1315,1316],{},"Svelte er et fantastisk framework der kompilerer væk sit eget runtime. Det giver ekstremt let output og en behagelig udvikleroplevelse. Men økosystemet er stadig lille sammenlignet med React og Vue, og jobmarkedet er begrænset.",[119,1318,1320],{"id":1319},"angular","Angular",[48,1322,1323],{},"Angular er stadig stort i enterprise-verdenen, særligt i backend-tunge organisationer. Men i den bredere frontend-verden er det blevet mindre relevant.",[119,1325,1327],{"id":1326},"solid-qwik-og-andre","Solid, Qwik og andre",[48,1329,1330],{},"Spændende teknologier der løser reelle problemer, men for de fleste projekter i 2026 er React eller Vue stadig det pragmatiske valg.",[43,1332,1334],{"id":1333},"min-personlige-præference","Min personlige præference",[48,1336,1337,1338,1341],{},"Hvis jeg starter et nyt projekt i dag og har frit valg, vælger jeg ",[67,1339,1340],{},"Vue 3 med Nuxt",". Det er det jeg kender bedst, og Composition API + Nuxt's DX er efter min mening den bedste udvikleroplevelse i frontend-verdenen.",[48,1343,1344],{},"Men hvis et team allerede bruger React, eller hvis projektet kræver React Native, ville jeg aldrig foreslå at skifte til Vue. Det vigtigste er ikke hvilket framework du vælger — det er at du bruger det godt.",[43,1346,1348],{"id":1347},"konklusion","Konklusion",[48,1350,1351],{},"Både React og Vue er modne, velunderstøttede frameworks der kan bygge hvad som helst. I 2026 er forskellen mellem dem mindre end nogensinde — begge har TypeScript-support, server-side rendering, og store økosystemer.",[48,1353,1354],{},"Vælg det der passer til dit team, dit projekt og dine krav. Ikke det der er mest hypet på Twitter.",[48,1356,1357],{},"Har du spørgsmål om valg af framework til dit næste projekt? Skriv til mig — jeg rådgiver gerne baseret på dine specifikke behov.",{"title":217,"searchDepth":218,"depth":218,"links":1359},[1360,1361,1362,1368,1374,1375,1376,1381,1382],{"id":1009,"depth":218,"text":1010},{"id":1022,"depth":218,"text":1023},{"id":1152,"depth":218,"text":1153,"children":1363},[1364,1365,1366,1367],{"id":1156,"depth":226,"text":1157},{"id":1166,"depth":226,"text":1167},{"id":1173,"depth":226,"text":1174},{"id":1180,"depth":226,"text":1181},{"id":1187,"depth":218,"text":1188,"children":1369},[1370,1371,1372,1373],{"id":1191,"depth":226,"text":1192},{"id":1201,"depth":226,"text":1202},{"id":1208,"depth":226,"text":1209},{"id":1215,"depth":226,"text":1216},{"id":1236,"depth":218,"text":1237},{"id":1272,"depth":218,"text":1273},{"id":1308,"depth":218,"text":1309,"children":1377},[1378,1379,1380],{"id":1312,"depth":226,"text":1313},{"id":1319,"depth":226,"text":1320},{"id":1326,"depth":226,"text":1327},{"id":1333,"depth":218,"text":1334},{"id":1347,"depth":218,"text":1348},"Jeg har brugt både React og Vue professionelt i mange år. Her er min ærlige sammenligning i 2026 — uden fanboy-bias.",{},"\u002Fblog\u002Freact-vs-vue-i-2026",{"title":1004,"description":1383},"React vs Vue sammenligning fra en udvikler med 19+ års erfaring i begge. Lær forskelle, fordele og ulemper, og hvornår du skal vælge hvad i 2026.","React vs Vue i 2026 — Hvilket framework skal du vælge?","react-vs-vue-i-2026","blog\u002Freact-vs-vue-i-2026",[998,997,1392,995,1393],"javascript","framework","H2b6Ass22LWn2bRwdep2gTqn61AIsH5pFcDxpAYYhvQ",{"id":1396,"title":1397,"body":1398,"date":234,"description":1994,"extension":236,"meta":1995,"navigation":238,"noindex":8,"path":1996,"seo":1997,"seoDescription":1998,"seoTitle":1999,"slug":2000,"stem":2001,"tags":2002,"thumbnail":1000,"updated":234,"__hash__":2006},"blog\u002Fblog\u002Fsaadan-vaelger-du-den-rigtige-tech-stack.md","Sådan vælger du den rigtige tech stack i 2026",{"type":40,"value":1399,"toc":1967},[1400,1404,1407,1410,1442,1445,1449,1452,1456,1459,1462,1467,1478,1482,1489,1492,1496,1513,1517,1520,1524,1538,1542,1545,1549,1560,1564,1568,1575,1579,1582,1586,1589,1593,1596,1600,1603,1607,1610,1614,1640,1643,1647,1671,1675,1705,1708,1712,1735,1738,1742,1749,1754,1768,1773,1787,1792,1803,1808,1819,1823,1826,1832,1838,1844,1850,1854,1857,1863,1869,1875,1878,1882,1885,1940,1943,1947,1950,1957,1959],[43,1401,1403],{"id":1402},"hvorfor-tech-stack-valget-er-vigtigere-end-du-tror","Hvorfor tech stack-valget er vigtigere end du tror",[48,1405,1406],{},"At vælge en tech stack er ikke bare et teknisk valg — det er en forretningsbeslutning. Jeg har set virksomheder spilde hundredtusindvis af kroner fordi de valgte den forkerte teknologi. Og jeg har set små teams levere hurtigere end store teams, fordi de valgte klogt.",[48,1408,1409],{},"Her er hvad der står på spil:",[625,1411,1412,1418,1424,1430,1436],{},[628,1413,1414,1417],{},[67,1415,1416],{},"Udviklingsomkostninger"," — Den forkerte stack kan fordoble din udviklingstid",[628,1419,1420,1423],{},[67,1421,1422],{},"Hastighed til markedet"," — Rigtig teknologi betyder hurtigere launch",[628,1425,1426,1429],{},[67,1427,1428],{},"Rekruttering"," — Kan du finde udviklere der kender stakken? Og hvad koster de?",[628,1431,1432,1435],{},[67,1433,1434],{},"Skalerbarhed"," — Kan teknologien vokse med din forretning?",[628,1437,1438,1441],{},[67,1439,1440],{},"Vedligeholdelse"," — Hvad koster det at holde systemet kørende om 3-5 år?",[48,1443,1444],{},"I min karriere — fra Grundfos og Vestas til Playable og Harness, og nu som Technical Director hos Checkmate.dk — har jeg truffet denne beslutning mange gange. Her er det framework jeg bruger.",[43,1446,1448],{"id":1447},"mit-framework-til-at-evaluere-tech-stack","Mit framework til at evaluere tech stack",[48,1450,1451],{},"Før du overhovedet tænker på specifikke teknologier, skal du stille de rigtige spørgsmål. Her er min tjekliste:",[119,1453,1455],{"id":1454},"_1-hvad-kan-dit-team","1. Hvad kan dit team?",[48,1457,1458],{},"Det vigtigste spørgsmål. Punkt. Teknologi dit team allerede kender vil næsten altid slå \"den bedste\" teknologi dit team ikke kender.",[48,1460,1461],{},"Hos Grundfos arvede vi et projekt bygget i et framework teamet ikke havde erfaring med. Resultatet? 6 måneders forsinkelse og en komplet omskrivning. Havde nogen spurgt \"hvad kan teamet?\", var det aldrig sket.",[48,1463,1464],{},[67,1465,1466],{},"Spørgsmål du skal stille:",[625,1468,1469,1472,1475],{},[628,1470,1471],{},"Hvad har teamet erfaring med?",[628,1473,1474],{},"Hvad kan de lære realistisk inden for projektets tidsramme?",[628,1476,1477],{},"Er der nogen i teamet der kan drive den tekniske retning?",[119,1479,1481],{"id":1480},"_2-hvad-kræver-projektet-reelt","2. Hvad kræver projektet reelt?",[48,1483,1484,1485,1488],{},"Ikke hvad det ",[167,1486,1487],{},"måske"," kræver om 3 år. Hvad kræver det nu?",[48,1490,1491],{},"Mange teams over-engineerer fordi de forbereder sig på skaleringsudfordringer de aldrig får. Byg til dine næste 12 måneder, ikke til et hypotetisk scenarie.",[48,1493,1494],{},[67,1495,1466],{},[625,1497,1498,1501,1504,1507,1510],{},[628,1499,1500],{},"Hvor mange brugere skal systemet håndtere?",[628,1502,1503],{},"Hvor kompleks er forretningslogikken?",[628,1505,1506],{},"Er der real-time krav?",[628,1508,1509],{},"Skal det integreres med eksisterende systemer?",[628,1511,1512],{},"Hvad er tidsplanen?",[119,1514,1516],{"id":1515},"_3-hvor-modent-er-økosystemet","3. Hvor modent er økosystemet?",[48,1518,1519],{},"Et framework kan være teknisk overlegent, men hvis der ikke er gode biblioteker, dokumentation og community support, betaler du prisen i udvikling.",[48,1521,1522],{},[67,1523,1466],{},[625,1525,1526,1529,1532,1535],{},[628,1527,1528],{},"Hvor gammel er teknologien? (Under 2 år = risiko)",[628,1530,1531],{},"Er der aktiv udvikling og regelmæssige releases?",[628,1533,1534],{},"Hvor stort er communityet?",[628,1536,1537],{},"Er der gode biblioteker til dine kernebehov?",[119,1539,1541],{"id":1540},"_4-kan-du-ansætte-folk","4. Kan du ansætte folk?",[48,1543,1544],{},"I Danmark er der stor forskel på hvor mange udviklere der kan de forskellige teknologier. Det skal du tænke ind fra start.",[48,1546,1547],{},[67,1548,1466],{},[625,1550,1551,1554,1557],{},[628,1552,1553],{},"Hvor mange ledige stillinger bruger denne teknologi i dit område?",[628,1555,1556],{},"Hvad er lønniveauet for udviklere med denne kompetence?",[628,1558,1559],{},"Kan du træne eksisterende medarbejdere?",[43,1561,1563],{"id":1562},"de-5-mest-almindelige-fejl","De 5 mest almindelige fejl",[119,1565,1567],{"id":1566},"fejl-1-at-vælge-baseret-på-hype","Fejl 1: At vælge baseret på hype",[48,1569,1570,1571,1574],{},"\"Vi skal bruge ",[332,1572,1573],{},"nyeste framework"," fordi alle taler om det.\" Nej. Medmindre der er en reel teknisk grund, er popularitet på Twitter ikke et argument.",[119,1576,1578],{"id":1577},"fejl-2-over-engineering-fra-dag-1","Fejl 2: Over-engineering fra dag 1",[48,1580,1581],{},"Du bygger en marketing-side og vælger microservices med Kubernetes? Stop. Start simpelt, tilføj kompleksitet når du har brug for det.",[119,1583,1585],{"id":1584},"fejl-3-at-ignorere-teamets-kompetencer","Fejl 3: At ignorere teamets kompetencer",[48,1587,1588],{},"Jeg gentager det gerne: dit teams erfaring trækker mere end noget frameworks features. En middelmådig stack i hænderne på et godt team slår en perfekt stack i hænderne på et team der fumler.",[119,1590,1592],{"id":1591},"fejl-4-at-lade-en-enkelt-udvikler-diktere-valget","Fejl 4: At lade en enkelt udvikler diktere valget",[48,1594,1595],{},"Undgå \"resume-driven development\" — hvor nogen vælger en teknologi fordi de gerne vil have den på deres CV, ikke fordi den er rigtig for projektet.",[119,1597,1599],{"id":1598},"fejl-5-at-glemme-exit-strategien","Fejl 5: At glemme exit-strategien",[48,1601,1602],{},"Hvad sker der hvis frameworket dør, eller den primære maintainer stopper? Kan du migrere? Hvor låst er du inde?",[43,1604,1606],{"id":1605},"konkrete-anbefalinger-efter-projekttype","Konkrete anbefalinger efter projekttype",[48,1608,1609],{},"Her er mine anbefalinger baseret på det jeg ser virke i 2026. Husk: disse er udgangspunkter, ikke dogmer.",[119,1611,1613],{"id":1612},"marketing-site-portfolio","Marketing-site \u002F portfolio",[625,1615,1616,1622,1628,1634],{},[628,1617,1618,1621],{},[67,1619,1620],{},"Frontend:"," Nuxt 3 (Vue) eller Next.js (React) med statisk generering",[628,1623,1624,1627],{},[67,1625,1626],{},"CMS:"," Headless CMS som Storyblok, Contentful eller Sanity",[628,1629,1630,1633],{},[67,1631,1632],{},"Hosting:"," Netlify eller Vercel",[628,1635,1636,1639],{},[67,1637,1638],{},"Hvorfor:"," Hurtig udvikling, god SEO ud af boksen, billig hosting, ingen server at vedligeholde",[48,1641,1642],{},"Dette site (nickychristensen.dk) er bygget præcis sådan — Nuxt 3, statisk generering, deployeret på Netlify. Det er hurtigt, billigt at drive og nemt at vedligeholde.",[119,1644,1646],{"id":1645},"e-commerce-webshop","E-commerce \u002F webshop",[625,1648,1649,1655,1660,1666],{},[628,1650,1651,1654],{},[67,1652,1653],{},"Platform:"," Shopify (simpel) eller headless Shopify \u002F Medusa med custom frontend",[628,1656,1657,1659],{},[67,1658,1620],{}," Nuxt eller Next.js",[628,1661,1662,1665],{},[67,1663,1664],{},"Betalinger:"," Stripe eller Adyen",[628,1667,1668,1670],{},[67,1669,1638],{}," E-commerce er et løst problem. Brug en platform der håndterer det tunge (betaling, lager, ordre), og byg custom UI ovenpå",[119,1672,1674],{"id":1673},"saas-produkt","SaaS-produkt",[625,1676,1677,1682,1688,1694,1700],{},[628,1678,1679,1681],{},[67,1680,1620],{}," Vue 3 + Pinia eller React + Zustand\u002FJotai",[628,1683,1684,1687],{},[67,1685,1686],{},"Backend:"," Node.js (Express\u002FFastify) eller Go for høj performance",[628,1689,1690,1693],{},[67,1691,1692],{},"Database:"," PostgreSQL med Prisma eller Drizzle ORM",[628,1695,1696,1699],{},[67,1697,1698],{},"Auth:"," Auth0, Clerk eller Supabase Auth",[628,1701,1702,1704],{},[67,1703,1638],{}," Her skal du tænke langsigtet. Vælg det dit team er stærkest i, og prioriter god arkitektur fra start",[48,1706,1707],{},"Hos Playable byggede vi SaaS-produktet i Vue med en Node-backend. Det fungerede fremragende fordi teamet kendte stakken.",[119,1709,1711],{"id":1710},"enterprise-applikation","Enterprise-applikation",[625,1713,1714,1719,1724,1730],{},[628,1715,1716,1718],{},[67,1717,1620],{}," React (størst talentpool) eller Vue 3 med TypeScript",[628,1720,1721,1723],{},[67,1722,1686],{}," .NET, Java Spring eller Node.js — afhængig af organisationens kompetencer",[628,1725,1726,1729],{},[67,1727,1728],{},"Infrastruktur:"," Cloud (AWS\u002FAzure\u002FGCP) med CI\u002FCD",[628,1731,1732,1734],{},[67,1733,1638],{}," Her handler det om stabilitet, skalerbarhed og muligheden for at ansætte. Vælg modne teknologier med lang track record",[48,1736,1737],{},"Hos Vestas og Grundfos oplevede jeg værdien af at vælge kedeligt og gennemprøvet. Nye og spændende teknologier har en højere pris når hundredevis af udviklere skal arbejde med dem.",[43,1739,1741],{"id":1740},"vue-vs-react-vs-andre-frameworks-i-2026","Vue vs React vs andre frameworks i 2026",[48,1743,1744,1745,1748],{},"Jeg har skrevet en hel artikel om ",[966,1746,1747],{"href":1385},"React vs Vue i 2026",", men her er den korte version:",[48,1750,1751],{},[67,1752,1753],{},"Vælg Vue hvis:",[625,1755,1756,1759,1762,1765],{},[628,1757,1758],{},"Dit team er mindre (2-10 udviklere)",[628,1760,1761],{},"Du vil have en blødere læringskurve",[628,1763,1764],{},"Du foretrækker convention over configuration",[628,1766,1767],{},"Du bygger med Nuxt og vil have \"batteries included\"",[48,1769,1770],{},[67,1771,1772],{},"Vælg React hvis:",[625,1774,1775,1778,1781,1784],{},[628,1776,1777],{},"Du ansætter i stor skala og har brug for den største talentpool",[628,1779,1780],{},"Du har brug for React Native til mobil",[628,1782,1783],{},"Dit team allerede kender React",[628,1785,1786],{},"Du arbejder i et enterprise-miljø med eksisterende React-infrastruktur",[48,1788,1789],{},[67,1790,1791],{},"Overvej Svelte\u002FSvelteKit hvis:",[625,1793,1794,1797,1800],{},[628,1795,1796],{},"Du bygger et mindre projekt med fokus på performance",[628,1798,1799],{},"Dit team er nysgerrige og villige til at lære noget nyt",[628,1801,1802],{},"Du ikke har brug for et kæmpe økosystem af tredjepartsbiblioteker",[48,1804,1805],{},[67,1806,1807],{},"Angular er stadig relevant hvis:",[625,1809,1810,1813,1816],{},[628,1811,1812],{},"Du arbejder i et stort enterprise-miljø (særligt .NET-shops)",[628,1814,1815],{},"Dit team kender det allerede",[628,1817,1818],{},"Du værdsætter streng struktur og opinionated arkitektur",[43,1820,1822],{"id":1821},"backend-overvejelser","Backend-overvejelser",[48,1824,1825],{},"Frontend får al opmærksomheden, men backend-valget er mindst lige så vigtigt.",[48,1827,1828,1831],{},[67,1829,1830],{},"Node.js"," er det oplagte valg hvis dit team allerede skriver JavaScript\u002FTypeScript. Du får kodedeling mellem frontend og backend, og der er et enormt økosystem.",[48,1833,1834,1837],{},[67,1835,1836],{},"Headless CMS"," (Storyblok, Contentful, Sanity) er rigtige for content-drevne sites. Lad redaktørerne arbejde i en editor de forstår, og byg en custom frontend.",[48,1839,1840,1843],{},[67,1841,1842],{},"Backend-as-a-Service"," (Supabase, Firebase) er fantastisk til prototyper og mindre SaaS-produkter. Du får database, auth og API uden at bygge det selv. Men vær opmærksom på vendor lock-in.",[48,1845,1846,1849],{},[67,1847,1848],{},"Go eller Rust"," giver mening hvis performance er kritisk og dit team har kompetencen. For de fleste projekter er Node.js rigeligt.",[43,1851,1853],{"id":1852},"ai-værktøjers-rolle-i-tech-stack-valget-2026-perspektiv","AI-værktøjers rolle i tech stack-valget (2026-perspektiv)",[48,1855,1856],{},"I 2026 har AI-assistenter som GitHub Copilot, Cursor og Claude fundamentalt ændret hvordan vi skriver kode. Det påvirker også tech stack-valget:",[48,1858,1859,1862],{},[67,1860,1861],{},"Større økosystem = bedre AI-support."," AI-modeller er trænet på offentlig kode. React og Vue har mere træningsdata end nicheframeworks, hvilket betyder bedre autokomplettering og fejlfinding.",[48,1864,1865,1868],{},[67,1866,1867],{},"AI reducerer læringskurven."," Det er nemmere at komme i gang med et nyt framework når AI kan forklare kode, generere boilerplate og finde fejl. Men det erstatter ikke dyb forståelse — du skal stadig vide hvad du laver.",[48,1870,1871,1874],{},[67,1872,1873],{},"Vælg ikke kun baseret på AI-support."," Det er fristende at vælge den teknologi AI er bedst til at generere. Men AI er et værktøj, ikke en arkitekt. De fundamentale kriterier (team, krav, økosystem, rekruttering) er stadig vigtigere.",[48,1876,1877],{},"Mit råd: Brug AI som accelerator, men lad det ikke diktere dine teknologiske valg.",[43,1879,1881],{"id":1880},"din-tjekliste","Din tjekliste",[48,1883,1884],{},"Før du træffer den næste tech stack-beslutning, gå denne liste igennem:",[625,1886,1889,1898,1904,1910,1916,1922,1928,1934],{"className":1887},[1888],"contains-task-list",[628,1890,1893,1897],{"className":1891},[1892],"task-list-item",[1894,1895],"input",{"disabled":238,"type":1896},"checkbox"," Hvad kan dit team allerede?",[628,1899,1901,1903],{"className":1900},[1892],[1894,1902],{"disabled":238,"type":1896}," Hvad kræver projektet reelt (ikke hypotetisk)?",[628,1905,1907,1909],{"className":1906},[1892],[1894,1908],{"disabled":238,"type":1896}," Er økosystemet modent nok?",[628,1911,1913,1915],{"className":1912},[1892],[1894,1914],{"disabled":238,"type":1896}," Kan du ansætte folk med denne kompetence?",[628,1917,1919,1921],{"className":1918},[1892],[1894,1920],{"disabled":238,"type":1896}," Har du overvejet vedligeholdelsesomkostninger?",[628,1923,1925,1927],{"className":1924},[1892],[1894,1926],{"disabled":238,"type":1896}," Er du sikker på du ikke over-engineerer?",[628,1929,1931,1933],{"className":1930},[1892],[1894,1932],{"disabled":238,"type":1896}," Har du en exit-strategi?",[628,1935,1937,1939],{"className":1936},[1892],[1894,1938],{"disabled":238,"type":1896}," Har du spurgt teamet (og ikke kun den mest højlydte udvikler)?",[48,1941,1942],{},"Hvis du kan svare ja til de fleste af disse, er du på rette vej.",[43,1944,1946],{"id":1945},"afsluttende-tanker","Afsluttende tanker",[48,1948,1949],{},"I 19+ år som udvikler og nu som Technical Director har jeg lært en ting: den bedste tech stack er den der lader dit team levere værdi hurtigt og pålideligt. Det lyder kedeligt. Det er det også. Men det virker.",[48,1951,1952,1953,1956],{},"Stop med at lede efter den perfekte teknologi. Find den rigtige teknologi ",[167,1954,1955],{},"for dig, dit team og dit projekt",".",[960,1958],{},[48,1960,1961],{},[167,1962,1963,1964,1966],{},"Har du brug for sparring på dit næste teknologivalg? Jeg hjælper virksomheder med at træffe de rigtige tekniske beslutninger. ",[966,1965,969],{"href":968}," for en uforpligtende snak.",{"title":217,"searchDepth":218,"depth":218,"links":1968},[1969,1970,1976,1983,1989,1990,1991,1992,1993],{"id":1402,"depth":218,"text":1403},{"id":1447,"depth":218,"text":1448,"children":1971},[1972,1973,1974,1975],{"id":1454,"depth":226,"text":1455},{"id":1480,"depth":226,"text":1481},{"id":1515,"depth":226,"text":1516},{"id":1540,"depth":226,"text":1541},{"id":1562,"depth":218,"text":1563,"children":1977},[1978,1979,1980,1981,1982],{"id":1566,"depth":226,"text":1567},{"id":1577,"depth":226,"text":1578},{"id":1584,"depth":226,"text":1585},{"id":1591,"depth":226,"text":1592},{"id":1598,"depth":226,"text":1599},{"id":1605,"depth":218,"text":1606,"children":1984},[1985,1986,1987,1988],{"id":1612,"depth":226,"text":1613},{"id":1645,"depth":226,"text":1646},{"id":1673,"depth":226,"text":1674},{"id":1710,"depth":226,"text":1711},{"id":1740,"depth":218,"text":1741},{"id":1821,"depth":218,"text":1822},{"id":1852,"depth":218,"text":1853},{"id":1880,"depth":218,"text":1881},{"id":1945,"depth":218,"text":1946},"En praktisk guide til at vælge den rigtige teknologi til dit næste projekt. Baseret på 19+ års erfaring med alt fra enterprise-løsninger til startups.",{},"\u002Fblog\u002Fsaadan-vaelger-du-den-rigtige-tech-stack",{"title":1397,"description":1994},"Lær at vælge den rigtige tech stack i 2026. Praktisk framework med konkrete anbefalinger til marketing sites, webshops, SaaS og enterprise.","Sådan vælger du den rigtige tech stack i 2026 — Praktisk guide","saadan-vaelger-du-den-rigtige-tech-stack","blog\u002Fsaadan-vaelger-du-den-rigtige-tech-stack",[2003,2004,995,997,998,2005],"tech-stack","strategi","webudvikling","YEW7CxxBTR1_9m_6gqtGIaVBwqx6qvpwQQFhlWkwHs8",{"id":2008,"title":2009,"body":2010,"date":2323,"description":2324,"extension":236,"meta":2325,"navigation":238,"noindex":8,"path":2326,"seo":2327,"seoDescription":2324,"seoTitle":2009,"slug":2328,"stem":2329,"tags":2330,"thumbnail":2331,"updated":2323,"__hash__":2332},"blog\u002Fblog\u002Fdestrukturer-props-i-vue-3.md","Sådan destrukturerer du props i Vue 3 uden at miste reaktivitet",{"type":40,"value":2011,"toc":2318},[2012,2015,2018,2022,2025,2028,2032,2042,2045,2228,2250,2258,2272,2278,2282,2288,2294,2303,2309,2315],[48,2013,2014],{},"Hvis du har arbejdet med Vue 3, ved du, at hvis du destrukturerer props, mister du reaktivitet, hvilket kan være et problem og føre til uventede problemer i din applikation. For ikke så længe siden skrev jeg en artikel om dette, som du kan læse her.",[48,2016,2017],{},"I Vue 3 sker overførsel af data mellem komponenter via props. Når en komponent modtager props, kan du destrukturere dem for at få adgang til de enkelte stykker data. Men hvis du ikke er forsigtig, kan destrukturering af props få reaktivitetssystemet i Vue til at bryde sammen, som nævnt. I denne artikel udforsker vi, hvorfor dette sker, og hvordan du destrukturerer props på en måde, der bevarer reaktiviteten.",[43,2019,2021],{"id":2020},"hvorfor-destrukturering-af-props-kan-bryde-reaktiviteten","Hvorfor destrukturering af props kan bryde reaktiviteten",[48,2023,2024],{},"Vues reaktivitetssystem er baseret på proxies og er afhængigt af, at det kan spore, hvilke egenskaber på et objekt der tilgås, og når de ændres. Når en komponent modtager et objekt som prop, opretter Vue en reaktiv getter og setter for hver egenskab på det objekt. Det giver Vue mulighed for at detektere, når en egenskab ændres, og opdatere komponenten i overensstemmelse hermed.",[48,2026,2027],{},"Når du destrukturerer en objekt-prop, opretter du i bund og grund et nyt objekt, der ikke længere er reaktivt. Det skyldes, at de reaktive getters og setters, som Vue oprettede for det originale objekt, ikke overføres til det nye objekt. Som resultat vil ændringer foretaget på det destrukturerede objekt ikke udløse reaktivitetsopdateringer. Hvis du ikke er bevidst om dette som udvikler, vil du højst sandsynligt opleve utilsigtede fejl og sideeffekter i din applikation.",[43,2029,2031],{"id":2030},"sådan-destrukturerer-du-props-uden-at-bryde-reaktiviteten","Sådan destrukturerer du props uden at bryde reaktiviteten",[48,2033,2034,2035,2038,2039,2041],{},"For at destrukturere props i Vue 3 uden at miste reaktivitet kan du bruge ",[287,2036,2037],{},"toRefs","-funktionen. ",[287,2040,2037],{}," tager et objekt og returnerer et nyt objekt, hvor hver egenskab er en ref. En ref er et reaktivt objekt, der indeholder en enkelt værdi.",[48,2043,2044],{},"Lad os se på et eksempel på, hvordan dette gøres!",[280,2046,2049],{"className":2047,"code":2048,"language":1392,"meta":217,"style":217},"language-javascript shiki shiki-themes github-dark","\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cp>{{ firstName }}\u003C\u002Fp>\n    \u003Cp>{{ lastName }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport { toRefs } from 'vue';\n\nexport default {\n  props: {\n    person: {\n      type: Object,\n      required: true,\n    },\n  },\n  setup(props) {\n    const { firstName, lastName } = toRefs(props.person);\n    return { firstName, lastName };\n  },\n};\n\u003C\u002Fscript>\n",[287,2050,2051,2062,2072,2086,2099,2108,2117,2121,2130,2135,2139,2144,2149,2154,2160,2171,2177,2182,2191,2202,2208,2213,2219],{"__ignoreMap":217},[332,2052,2053,2055,2059],{"class":334,"line":335},[332,2054,374],{"class":355},[332,2056,2058],{"class":2057},"s4JwU","template",[332,2060,2061],{"class":355},">\n",[332,2063,2064,2067,2070],{"class":334,"line":218},[332,2065,2066],{"class":355},"  \u003C",[332,2068,2069],{"class":2057},"div",[332,2071,2061],{"class":355},[332,2073,2074,2077,2079,2082,2084],{"class":334,"line":226},[332,2075,2076],{"class":355},"    \u003C",[332,2078,48],{"class":2057},[332,2080,2081],{"class":355},">{{ firstName }}\u003C\u002F",[332,2083,48],{"class":2057},[332,2085,2061],{"class":355},[332,2087,2088,2090,2092,2095,2097],{"class":334,"line":395},[332,2089,2076],{"class":355},[332,2091,48],{"class":2057},[332,2093,2094],{"class":355},">{{ lastName }}\u003C\u002F",[332,2096,48],{"class":2057},[332,2098,2061],{"class":355},[332,2100,2101,2104,2106],{"class":334,"line":415},[332,2102,2103],{"class":355},"  \u003C\u002F",[332,2105,2069],{"class":2057},[332,2107,2061],{"class":355},[332,2109,2110,2113,2115],{"class":334,"line":421},[332,2111,2112],{"class":355},"\u003C\u002F",[332,2114,2058],{"class":2057},[332,2116,2061],{"class":355},[332,2118,2119],{"class":334,"line":434},[332,2120,418],{"emptyLinePlaceholder":238},[332,2122,2123,2125,2128],{"class":334,"line":446},[332,2124,374],{"class":355},[332,2126,2127],{"class":2057},"script",[332,2129,2061],{"class":355},[332,2131,2132],{"class":334,"line":466},[332,2133,2134],{"class":355},"import { toRefs } from 'vue';\n",[332,2136,2137],{"class":334,"line":476},[332,2138,418],{"emptyLinePlaceholder":238},[332,2140,2141],{"class":334,"line":482},[332,2142,2143],{"class":355},"export default {\n",[332,2145,2146],{"class":334,"line":487},[332,2147,2148],{"class":355},"  props: {\n",[332,2150,2151],{"class":334,"line":496},[332,2152,2153],{"class":355},"    person: {\n",[332,2155,2157],{"class":334,"line":2156},14,[332,2158,2159],{"class":355},"      type: Object,\n",[332,2161,2163,2166,2169],{"class":334,"line":2162},15,[332,2164,2165],{"class":355},"      required: ",[332,2167,2168],{"class":364},"true",[332,2170,555],{"class":355},[332,2172,2174],{"class":334,"line":2173},16,[332,2175,2176],{"class":355},"    },\n",[332,2178,2180],{"class":334,"line":2179},17,[332,2181,581],{"class":355},[332,2183,2185,2188],{"class":334,"line":2184},18,[332,2186,2187],{"class":351},"  setup",[332,2189,2190],{"class":355},"(props) {\n",[332,2192,2194,2197,2199],{"class":334,"line":2193},19,[332,2195,2196],{"class":355},"    const { firstName, lastName } = ",[332,2198,2037],{"class":351},[332,2200,2201],{"class":355},"(props.person);\n",[332,2203,2205],{"class":334,"line":2204},20,[332,2206,2207],{"class":355},"    return { firstName, lastName };\n",[332,2209,2211],{"class":334,"line":2210},21,[332,2212,581],{"class":355},[332,2214,2216],{"class":334,"line":2215},22,[332,2217,2218],{"class":355},"};\n",[332,2220,2222,2224,2226],{"class":334,"line":2221},23,[332,2223,2112],{"class":355},[332,2225,2127],{"class":2057},[332,2227,2061],{"class":355},[48,2229,2230,2231,2233,2234,2237,2238,2241,2242,2245,2246,2249],{},"I ovenstående eksempel bruger vi ",[287,2232,2037],{},"-funktionen til at destrukturere ",[287,2235,2236],{},"person","-proppen til ",[287,2239,2240],{},"firstName","- og ",[287,2243,2244],{},"lastName","-refs. Ved at returnere disse refs fra ",[287,2247,2248],{},"setup","-funktionen kan vi bruge dem i vores template uden at miste reaktivitet.",[48,2251,2252,2253,2255,2256,1956],{},"Det betyder, at hvis ",[287,2254,2236],{},"-proppen ændres udefra på denne komponent, vil det propagere korrekt ind i denne komponent og rendere ændringerne til ",[287,2257,2236],{},[48,2259,2260,2261,2263,2264,1229,2266,2268,2269,2271],{},"Hvis for eksempel ",[287,2262,2236],{},"-proppen opdateres i parent-komponenten, vil de nye værdier for ",[287,2265,2240],{},[287,2267,2244],{}," automatisk blive opdateret i child-komponenten uden yderligere opsætning eller konfiguration. Det skyldes, at ",[287,2270,2037],{}," opretter reaktive refs, der stadig er forbundet til det originale objekt-prop, så eventuelle ændringer foretaget på det originale objekt vil blive afspejlet i de reaktive refs.",[48,2273,2274,2275,2277],{},"Overordnet set er brugen af ",[287,2276,2037],{}," til at destrukturere props i Vue 3 en fremragende måde at bevare reaktivitet og sikre, at dine komponenter forbliver synkroniserede med ændringer foretaget på deres props udefra.",[43,2279,2281],{"id":2280},"hvad-med-ydeevnen","Hvad med ydeevnen?",[48,2283,2284,2285,2287],{},"At bruge ",[287,2286,2037],{}," til at destrukturere props i Vue 3 har en lille ydeevneomkostning, men den er generelt acceptabel i de fleste tilfælde.",[48,2289,2290,2291,2293],{},"Når du destrukturerer en objekt-prop med ",[287,2292,2037],{},", skal Vue oprette en ny ref for hver egenskab på objektet. Det betyder, at der skal oprettes flere reaktive objekter, hvilket kan øge hukommelsesforbruget og en smule forsinke reaktivitetssystemet.",[48,2295,2296,2297,2299,2300,2302],{},"Dog er ydeevnepåvirkningen ved at bruge ",[287,2298,2037],{}," normalt minimal, især sammenlignet med fordelene ved at bevare reaktivitet, når man destrukturerer props. Faktisk er ",[287,2301,2037],{},"-funktionen indbygget i Vue 3 specifikt for at hjælpe med at løse de reaktivitetsproblemer, der kan opstå ved destrukturering af props, så det er en anbefalet tilgang i mange brugsscenarier.",[48,2304,2305,2306,2308],{},"Når det er sagt, er det altid en god idé at holde øje med ydeevnen af dine Vue-komponenter, især hvis de renderer store mængder data eller håndterer kompleks logik. Hvis du bemærker væsentlige forsinkelser eller hukommelsesproblemer, kan du overveje alternative tilgange eller optimeringer. Men i de fleste tilfælde bør brugen af ",[287,2307,2037],{}," til at destrukturere props ikke forårsage nogen væsentlige ydeevneproblemer.",[48,2310,2311,2312,2314],{},"Destrukturering af props i Vue 3 kan være en bekvem måde at få adgang til individuelle stykker data. Men hvis du ikke er forsigtig, kan det få reaktivitetssystemet til at bryde sammen. Ved at bruge ",[287,2313,2037],{},"-funktionen kan du destrukturere props uden at miste reaktivitet. Det giver dig mulighed for at skrive mere koncis og læsbar kode uden at gå på kompromis med ydeevne eller funktionalitet.",[972,2316,2317],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":217,"searchDepth":218,"depth":218,"links":2319},[2320,2321,2322],{"id":2020,"depth":218,"text":2021},{"id":2030,"depth":218,"text":2031},{"id":2280,"depth":218,"text":2281},"2023-02-20","Hvis du har arbejdet med Vue 3, ved du, at destrukturering af props kan få dig til at miste reaktivitet. Lær hvordan du undgår det.",{},"\u002Fblog\u002Fdestrukturer-props-i-vue-3",{"title":2009,"description":2324},"destrukturer-props-i-vue-3","blog\u002Fdestrukturer-props-i-vue-3",[997,1392,995],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*PHUQQPHoU-Q6_kXEGual0g.png","rRV6g_z-tGhfucjqfU8Ix4kr2esf_QRMy0na3_ZDLmM",{"id":2334,"title":2335,"body":2336,"date":2432,"description":2433,"extension":236,"meta":2434,"navigation":238,"noindex":8,"path":2435,"seo":2436,"seoDescription":2437,"seoTitle":2335,"slug":2438,"stem":2439,"tags":2440,"thumbnail":2442,"updated":2432,"__hash__":2443},"blog\u002Fblog\u002F10-ting-som-frontend-teamlead.md","10 ting jeg ville ønske jeg vidste før jeg blev Frontend Team Lead",{"type":40,"value":2337,"toc":2420},[2338,2341,2347,2351,2354,2358,2361,2365,2368,2372,2375,2379,2382,2386,2389,2393,2396,2400,2403,2407,2410,2414,2417],[48,2339,2340],{},"Så du tror du vil have titlen som Frontend Team Lead? Som udvikler kan det at blive teamleder være en spændende men også skræmmende overgang. Der er mange nye ansvarsområder og udfordringer at navigere i, og det kan være svært at vide præcis hvad du kan forvente. Du er højst sandsynligt vant til at bruge 90-95% af din tid som ekspertudvikler, en specialist så at sige. At være teamleder betyder at dine ansvarsområder rækker ud over at være ekspert i udvikling.",[48,2342,2343,2344],{},"I dag tager jeg dig igennem ",[67,2345,2346],{},"10 ting jeg ville ønske jeg havde vidst før jeg blev frontend team lead",[43,2348,2350],{"id":2349},"udvikl-dine-kommunikationsevner","Udvikl dine kommunikationsevner",[48,2352,2353],{},"Effektiv kommunikation er afgørende for enhver teamleder, men det kan være særligt vigtigt i den hurtige verden af softwareudvikling. Som teamleder vil du være ansvarlig for at facilitere kommunikation inden for dit team og med andre interessenter. Sørg for klart at formulere dine forventninger og mål, og opfordr til åben og ærlig kommunikation i dit team. Sørg også for at holde kontakten med dine teammedlemmer gennem 1-1 samtaler.",[43,2355,2357],{"id":2356},"værdien-af-delegering","Værdien af delegering",[48,2359,2360],{},"Som teamleder vil du have meget på din tallerken, og det er vigtigt at lære at delegere opgaver til dit team effektivt. Det vil sikre at dine teammedlemmer føler sig værdsat og empowered, og det vil også hjælpe dig med at håndtere din egen arbejdsbyrde mere effektivt. Du behøver ikke være ekspert i alting! Stol på dit team og giv dem mulighed for at tage nye udfordringer på sig.",[43,2362,2364],{"id":2363},"du-har-brug-for-teknisk-ekspertise","Du har brug for teknisk ekspertise",[48,2366,2367],{},"Det siger sig selv! Det er vigtigt at have en stærk forståelse af frontend-teknologier og best practices. Sørg for at holde dig opdateret med den nyeste udvikling inden for dit felt, og vær villig til at fortsætte med at lære og vokse som udvikler. Det vil ikke kun hjælpe dig med at lede dit team mere effektivt, men det vil også hjælpe dig med at opnå respekt og tillid fra dine teammedlemmer. Du behøver ikke nødvendigvis have hands-on erfaring med alt, men at have viden og interesse for hvad der sker i frontend-verdenen vil hjælpe.",[43,2369,2371],{"id":2370},"team-building-er-vigtigt","Team building er vigtigt!",[48,2373,2374],{},"En positiv og samarbejdende teamkultur er essentiel for succesen af ethvert projekt eller team. Det vil være op til dig at skabe et miljø hvor teammedlemmer føler sig trygge ved at dele ideer og støtte hinanden. Det kan indebære at organisere team-building aktiviteter eller skabe muligheder for at dine teammedlemmer kan lære hinanden bedre at kende. Hvis folk stoler på og kan lide hinanden, er der ingen grænse for hvad teamet kan opnå.",[43,2376,2378],{"id":2377},"du-skal-forstå-projektledelse","Du skal forstå projektledelse",[48,2380,2381],{},"Du vil sandsynligvis være ansvarlig for at styre et eller flere projekter. Det vil indebære at sætte projektmål og tidslinjer, håndtere ressourcer og kommunikere fremskridt til interessenter. Sørg for at være organiseret og på forkant med dine projektopgaver, og vær ikke bange for at bede om hjælp når du har brug for det. Hvis du kender en projektleder, så ring til vedkommende og sørg for at høste al den viden du kan om at være struktureret omkring projekter og hvordan man driver projekter fremad.",[43,2383,2385],{"id":2384},"problemløsningsevner","Problemløsningsevner",[48,2387,2388],{},"Før eller siden vil du støde på en række udfordringer og forhindringer. Det er vigtigt at have stærke problemløsningsevner for at overkomme disse udfordringer og holde dit team i bevægelse fremad. Sørg for at gå til problemer med et klart og logisk mindset, og vær ikke bange for at bede om hjælp når du har brug for det.",[43,2390,2392],{"id":2391},"vigtigheden-af-mentorskab","Vigtigheden af mentorskab",[48,2394,2395],{},"Du bliver nødt til at mentore junior teammedlemmer og hjælpe dem med at vokse og udvikle sig i deres roller. Tag dig tid til at støtte og guide dine teammedlemmer, og vær åben for at lære af dem også. Husk at mentorskab er en tovejsproces, og du kan lære lige så meget af dine teammedlemmer som de kan lære af dig. Hav et åbent mindset — bare fordi du er mere erfaren, betyder det ikke at du altid har ret. Husk at være ydmyg!",[43,2397,2399],{"id":2398},"værdien-af-diversitet-og-inklusion","Værdien af diversitet og inklusion",[48,2401,2402],{},"At skabe en teamkultur der er inkluderende og imødekommende over for mennesker fra alle baggrunde er essentielt for ethvert teams succes. Som teamleder er det op til dig aktivt at opsøge og opfordre til diversitet i dit team, og at være en allieret for underrepræsenterede grupper. Husk at et diverst team kan bringe et bredere udvalg af perspektiver og erfaringer til bordet, hvilket kan føre til mere kreative og effektive løsninger.",[43,2404,2406],{"id":2405},"etabler-psykologisk-tryghed","Etabler psykologisk tryghed",[48,2408,2409],{},"At skabe et trygt og støttende miljø for dine teammedlemmer er essentielt for deres trivsel og succes. Som teamleder er det op til dig at skabe en kultur med psykologisk tryghed, hvor teammedlemmer føler sig trygge ved at dele ideer og bekymringer uden frygt for repressalier. Det kan indebære aktivt at opfordre til åben og ærlig kommunikation, håndtere konflikter på en respektfuld måde, og være åben for feedback og kontinuerlig forbedring.",[43,2411,2413],{"id":2412},"pas-på-dit-helbred","Pas på dit helbred",[48,2415,2416],{},"At lede et team kan være givende, men også stressende til tider. Sørg for at prioritere dit eget velvære og pas på dig selv for at opretholde en sund work-life balance. Det kan indebære at sætte grænser, holde pauser og finde tid til at slappe af og lade op. Husk at det at passe på dig selv ikke kun gavner dig, men det vil også hjælpe dig med at være en mere effektiv og støttende teamleder.",[48,2418,2419],{},"At blive frontend team lead kan være en udfordrende men givende oplevelse. Ved at have disse 10 ting i tankerne kan du sætte dig selv op til succes og hjælpe med at skabe et positivt og produktivt teammiljø. Husk at bare fordi du er teamleder, behøver du ikke være den klogeste person i rummet — det er vigtigt at fremme en kultur med samarbejde og læring, hvor alles ideer og indsigter værdsættes.",{"title":217,"searchDepth":218,"depth":218,"links":2421},[2422,2423,2424,2425,2426,2427,2428,2429,2430,2431],{"id":2349,"depth":218,"text":2350},{"id":2356,"depth":218,"text":2357},{"id":2363,"depth":218,"text":2364},{"id":2370,"depth":218,"text":2371},{"id":2377,"depth":218,"text":2378},{"id":2384,"depth":218,"text":2385},{"id":2391,"depth":218,"text":2392},{"id":2398,"depth":218,"text":2399},{"id":2405,"depth":218,"text":2406},{"id":2412,"depth":218,"text":2413},"2023-01-09","Så du tror du vil være Frontend Team Lead? At gå fra udvikler til teamleder kan være både spændende og skræmmende. Her er 10 ting du bør vide.",{},"\u002Fblog\u002F10-ting-som-frontend-teamlead",{"title":2335,"description":2433},"Så du tror du vil være Frontend Team Lead? Her er 10 ting du bør vide før du tager springet fra udvikler til teamleder. Kommunikation, delegering og mere.","10-ting-som-frontend-teamlead","blog\u002F10-ting-som-frontend-teamlead",[246,995,2441],"produktivitet","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*FmkJ93Uzv3LKdeSRxE5Y4A.png","Z71aPxDkPTxk4Qkkfmn0FddqePWSnIJ3RoAdLXjeQvA",{"id":2445,"title":2446,"body":2447,"date":3006,"description":3007,"extension":236,"meta":3008,"navigation":238,"noindex":8,"path":3009,"seo":3010,"seoDescription":3011,"seoTitle":2446,"slug":3012,"stem":3013,"tags":3014,"thumbnail":3016,"updated":3006,"__hash__":3017},"blog\u002Fblog\u002Fvue3-computed-funktioner.md","Vue 3 — derfor kan computed funktioner gøre din kode renere",{"type":40,"value":2448,"toc":3004},[2449,2452,2455,2458,2598,2956,2974,2989,2992,2995,2998,3001],[48,2450,2451],{},"Vue 3 er den nyeste version af det populære JavaScript-framework til at bygge webapplikationer. En af de funktioner, der får Vue 3 til at skille sig ud, er understøttelsen af computed funktioner (Vue 2 har også dette), som kan hjælpe med at gøre din kode meget renere og mere effektiv.",[48,2453,2454],{},"For at forklare det kort, er computed funktioner i Vue 3 funktioner, der automatisk genberegnes, når en af deres afhængigheder ændres. Det giver dig mulighed for deklarativt at specificere kompleks logik i dine templates, i stedet for manuelt at skulle opdatere værdier eller udføre beregninger i din kode.",[48,2456,2457],{},"Overvej for eksempel en simpel Vue 3-komponent, der viser en liste af elementer og det samlede antal:",[280,2459,2462],{"className":2460,"code":2461,"language":997,"meta":217,"style":217},"language-vue shiki shiki-themes github-dark","\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv v-if=\"loading\">Loading...\u003C\u002Fdiv>\n    \u003Cdiv v-else>\n      \u003Cul>\n        \u003Cli v-for=\"item in items\" :key=\"item.id\">{{ item.name }}\u003C\u002Fli>\n      \u003C\u002Ful>\n      \u003Cp>Total count: {{ totalCount }}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[287,2463,2464,2472,2480,2501,2512,2521,2551,2560,2573,2582,2590],{"__ignoreMap":217},[332,2465,2466,2468,2470],{"class":334,"line":335},[332,2467,374],{"class":355},[332,2469,2058],{"class":2057},[332,2471,2061],{"class":355},[332,2473,2474,2476,2478],{"class":334,"line":218},[332,2475,2066],{"class":355},[332,2477,2069],{"class":2057},[332,2479,2061],{"class":355},[332,2481,2482,2484,2486,2489,2491,2494,2497,2499],{"class":334,"line":226},[332,2483,2076],{"class":355},[332,2485,2069],{"class":2057},[332,2487,2488],{"class":351}," v-if",[332,2490,440],{"class":355},[332,2492,2493],{"class":551},"\"loading\"",[332,2495,2496],{"class":355},">Loading...\u003C\u002F",[332,2498,2069],{"class":2057},[332,2500,2061],{"class":355},[332,2502,2503,2505,2507,2510],{"class":334,"line":395},[332,2504,2076],{"class":355},[332,2506,2069],{"class":2057},[332,2508,2509],{"class":351}," v-else",[332,2511,2061],{"class":355},[332,2513,2514,2517,2519],{"class":334,"line":415},[332,2515,2516],{"class":355},"      \u003C",[332,2518,625],{"class":2057},[332,2520,2061],{"class":355},[332,2522,2523,2526,2528,2531,2533,2536,2539,2541,2544,2547,2549],{"class":334,"line":421},[332,2524,2525],{"class":355},"        \u003C",[332,2527,628],{"class":2057},[332,2529,2530],{"class":351}," v-for",[332,2532,440],{"class":355},[332,2534,2535],{"class":551},"\"item in items\"",[332,2537,2538],{"class":351}," :key",[332,2540,440],{"class":355},[332,2542,2543],{"class":551},"\"item.id\"",[332,2545,2546],{"class":355},">{{ item.name }}\u003C\u002F",[332,2548,628],{"class":2057},[332,2550,2061],{"class":355},[332,2552,2553,2556,2558],{"class":334,"line":434},[332,2554,2555],{"class":355},"      \u003C\u002F",[332,2557,625],{"class":2057},[332,2559,2061],{"class":355},[332,2561,2562,2564,2566,2569,2571],{"class":334,"line":446},[332,2563,2516],{"class":355},[332,2565,48],{"class":2057},[332,2567,2568],{"class":355},">Total count: {{ totalCount }}\u003C\u002F",[332,2570,48],{"class":2057},[332,2572,2061],{"class":355},[332,2574,2575,2578,2580],{"class":334,"line":466},[332,2576,2577],{"class":355},"    \u003C\u002F",[332,2579,2069],{"class":2057},[332,2581,2061],{"class":355},[332,2583,2584,2586,2588],{"class":334,"line":476},[332,2585,2103],{"class":355},[332,2587,2069],{"class":2057},[332,2589,2061],{"class":355},[332,2591,2592,2594,2596],{"class":334,"line":482},[332,2593,2112],{"class":355},[332,2595,2058],{"class":2057},[332,2597,2061],{"class":355},[280,2599,2601],{"className":2047,"code":2600,"language":1392,"meta":217,"style":217},"\u003Cscript lang=\"ts\">\nimport { computed, defineComponent } from 'vue';\n\ninterface Item {\n  name: string;\n  description: string;\n}\n\nexport default defineComponent({\n  name: 'SomeComponentName',\n  setup() {\n    const items = ref\u003CItem>([]);\n\n    const isLoading = computed(() => {\n      return items.value.length === 0;\n    });\n\n    const totalCount = computed(() => {\n      return items.value.length;\n    });\n\n    const fetchItems = async () => {\n      try {\n        const res = await axios.get('\u002Fapi\u002Fitems');\n        items.value = res.data as Item[];\n      } catch (e) {\n        throw new Error('an error happened' + e);\n      }\n    };\n\n    fetchItems();\n    \n    return {\n      isLoading,\n      totalCount\n    };\n  }\n});\n\u003C\u002Fscript>\n",[287,2602,2603,2619,2624,2628,2633,2638,2643,2647,2651,2656,2666,2672,2689,2693,2710,2730,2735,2739,2754,2764,2768,2772,2792,2799,2826,2846,2858,2881,2887,2893,2898,2907,2913,2919,2925,2931,2936,2941,2947],{"__ignoreMap":217},[332,2604,2605,2607,2609,2612,2614,2617],{"class":334,"line":335},[332,2606,374],{"class":355},[332,2608,2127],{"class":2057},[332,2610,2611],{"class":351}," lang",[332,2613,440],{"class":344},[332,2615,2616],{"class":551},"\"ts\"",[332,2618,2061],{"class":355},[332,2620,2621],{"class":334,"line":218},[332,2622,2623],{"class":355},"import { computed, defineComponent } from 'vue';\n",[332,2625,2626],{"class":334,"line":226},[332,2627,418],{"emptyLinePlaceholder":238},[332,2629,2630],{"class":334,"line":395},[332,2631,2632],{"class":355},"interface Item {\n",[332,2634,2635],{"class":334,"line":415},[332,2636,2637],{"class":355},"  name: string;\n",[332,2639,2640],{"class":334,"line":421},[332,2641,2642],{"class":355},"  description: string;\n",[332,2644,2645],{"class":334,"line":434},[332,2646,499],{"class":355},[332,2648,2649],{"class":334,"line":446},[332,2650,418],{"emptyLinePlaceholder":238},[332,2652,2653],{"class":334,"line":466},[332,2654,2655],{"class":355},"export default defineComponent({\n",[332,2657,2658,2661,2664],{"class":334,"line":476},[332,2659,2660],{"class":355},"  name: ",[332,2662,2663],{"class":551},"'SomeComponentName'",[332,2665,555],{"class":355},[332,2667,2668,2670],{"class":334,"line":482},[332,2669,2187],{"class":351},[332,2671,356],{"class":355},[332,2673,2674,2677,2679,2681,2683,2686],{"class":334,"line":487},[332,2675,2676],{"class":355},"    const items ",[332,2678,440],{"class":344},[332,2680,371],{"class":351},[332,2682,374],{"class":355},[332,2684,2685],{"class":351},"Item",[332,2687,2688],{"class":355},">([]);\n",[332,2690,2691],{"class":334,"line":496},[332,2692,418],{"emptyLinePlaceholder":238},[332,2694,2695,2698,2700,2703,2706,2708],{"class":334,"line":2156},[332,2696,2697],{"class":355},"    const isLoading ",[332,2699,440],{"class":344},[332,2701,2702],{"class":351}," computed",[332,2704,2705],{"class":355},"(() ",[332,2707,566],{"class":344},[332,2709,782],{"class":355},[332,2711,2712,2715,2718,2721,2724,2727],{"class":334,"line":2162},[332,2713,2714],{"class":344},"      return",[332,2716,2717],{"class":355}," items.value.",[332,2719,2720],{"class":364},"length",[332,2722,2723],{"class":344}," ===",[332,2725,2726],{"class":364}," 0",[332,2728,2729],{"class":355},";\n",[332,2731,2732],{"class":334,"line":2173},[332,2733,2734],{"class":355},"    });\n",[332,2736,2737],{"class":334,"line":2179},[332,2738,418],{"emptyLinePlaceholder":238},[332,2740,2741,2744,2746,2748,2750,2752],{"class":334,"line":2184},[332,2742,2743],{"class":355},"    const totalCount ",[332,2745,440],{"class":344},[332,2747,2702],{"class":351},[332,2749,2705],{"class":355},[332,2751,566],{"class":344},[332,2753,782],{"class":355},[332,2755,2756,2758,2760,2762],{"class":334,"line":2193},[332,2757,2714],{"class":344},[332,2759,2717],{"class":355},[332,2761,2720],{"class":364},[332,2763,2729],{"class":355},[332,2765,2766],{"class":334,"line":2204},[332,2767,2734],{"class":355},[332,2769,2770],{"class":334,"line":2210},[332,2771,418],{"emptyLinePlaceholder":238},[332,2773,2774,2777,2780,2782,2785,2788,2790],{"class":334,"line":2215},[332,2775,2776],{"class":355},"    const ",[332,2778,2779],{"class":351},"fetchItems",[332,2781,368],{"class":344},[332,2783,2784],{"class":344}," async",[332,2786,2787],{"class":355}," () ",[332,2789,566],{"class":344},[332,2791,782],{"class":355},[332,2793,2794,2797],{"class":334,"line":2221},[332,2795,2796],{"class":344},"      try",[332,2798,782],{"class":355},[332,2800,2802,2805,2808,2810,2812,2815,2818,2820,2823],{"class":334,"line":2801},24,[332,2803,2804],{"class":344},"        const",[332,2806,2807],{"class":364}," res",[332,2809,368],{"class":344},[332,2811,454],{"class":344},[332,2813,2814],{"class":355}," axios.",[332,2816,2817],{"class":351},"get",[332,2819,407],{"class":355},[332,2821,2822],{"class":551},"'\u002Fapi\u002Fitems'",[332,2824,2825],{"class":355},");\n",[332,2827,2829,2832,2834,2837,2840,2843],{"class":334,"line":2828},25,[332,2830,2831],{"class":355},"        items.value ",[332,2833,440],{"class":344},[332,2835,2836],{"class":355}," res.data ",[332,2838,2839],{"class":344},"as",[332,2841,2842],{"class":351}," Item",[332,2844,2845],{"class":355},"[];\n",[332,2847,2849,2852,2855],{"class":334,"line":2848},26,[332,2850,2851],{"class":355},"      } ",[332,2853,2854],{"class":344},"catch",[332,2856,2857],{"class":355}," (e) {\n",[332,2859,2861,2864,2867,2870,2872,2875,2878],{"class":334,"line":2860},27,[332,2862,2863],{"class":344},"        throw",[332,2865,2866],{"class":344}," new",[332,2868,2869],{"class":351}," Error",[332,2871,407],{"class":355},[332,2873,2874],{"class":551},"'an error happened'",[332,2876,2877],{"class":344}," +",[332,2879,2880],{"class":355}," e);\n",[332,2882,2884],{"class":334,"line":2883},28,[332,2885,2886],{"class":355},"      }\n",[332,2888,2890],{"class":334,"line":2889},29,[332,2891,2892],{"class":355},"    };\n",[332,2894,2896],{"class":334,"line":2895},30,[332,2897,418],{"emptyLinePlaceholder":238},[332,2899,2901,2904],{"class":334,"line":2900},31,[332,2902,2903],{"class":351},"    fetchItems",[332,2905,2906],{"class":355},"();\n",[332,2908,2910],{"class":334,"line":2909},32,[332,2911,2912],{"class":355},"    \n",[332,2914,2916],{"class":334,"line":2915},33,[332,2917,2918],{"class":355},"    return {\n",[332,2920,2922],{"class":334,"line":2921},34,[332,2923,2924],{"class":355},"      isLoading,\n",[332,2926,2928],{"class":334,"line":2927},35,[332,2929,2930],{"class":355},"      totalCount\n",[332,2932,2934],{"class":334,"line":2933},36,[332,2935,2892],{"class":355},[332,2937,2939],{"class":334,"line":2938},37,[332,2940,479],{"class":355},[332,2942,2944],{"class":334,"line":2943},38,[332,2945,2946],{"class":355},"});\n",[332,2948,2950,2952,2954],{"class":334,"line":2949},39,[332,2951,2112],{"class":355},[332,2953,2127],{"class":2057},[332,2955,2061],{"class":355},[48,2957,2958,2959,2962,2963,2966,2967,2970,2971,2973],{},"I dette eksempel er ",[287,2960,2961],{},"totalCount"," computed funktionen ansvarlig for at beregne det samlede antal elementer i ",[287,2964,2965],{},"items","-arrayet. ",[287,2968,2969],{},"isLoading"," computed funktionen returnerer en boolean-værdi, der angiver, om komponenten er i en loading-tilstand eller ej, baseret på længden af ",[287,2972,2965],{},"-arrayet.",[48,2975,2976,2977,2979,2980,2982,2983,2985,2986,2988],{},"Læg mærke til, hvordan vi bruger den computed ",[287,2978,2969],{}," til at definere, om applikationen loader. Normalt ser jeg mange udviklere definere en ",[287,2981,2969],{},"-variabel og sætte variablen ",[287,2984,2969],{}," til true, når de kalder ",[287,2987,2779],{},", og derefter sætte den til false igen, når API-kaldet er færdigt. At lave en computed funktion til dette gør din kode meget renere.",[48,2990,2991],{},"Ikke kun med ovenstående eksempel, men i mange andre tilfælde kan brugen af computed funktioner hjælpe med at gøre din kode renere på flere måder. For det første giver det dig mulighed for deklarativt at specificere kompleks logik i dine templates, i stedet for manuelt at skulle opdatere værdier eller udføre beregninger i din kode. Det kan gøre dine templates nemmere at læse og forstå, da logikken bag dem er tydeligt adskilt fra præsentationen.",[48,2993,2994],{},"For det andet er computed funktioner mere effektive end manuelt at opdatere værdier eller udføre beregninger i din kode. Vue 3 cacher automatisk computed funktioner, så de kun genberegnes, når deres afhængigheder ændres. Det kan hjælpe med at forbedre din applikations ydeevne, især hvis du har komplekse eller tunge beregninger, der skal udføres ofte.",[48,2996,2997],{},"Endelig kan computed funktioner gøre din kode mere vedligeholdelsesvenlig ved at give en klar adskillelse af ansvar. Ved at indkapsle kompleks logik i computed funktioner kan du gøre det nemmere at ændre eller opdatere den logik uden at påvirke resten af din kode.",[48,2999,3000],{},"Kort sagt er computed funktioner en kraftfuld funktion i Vue 3, der kan hjælpe med at gøre din kode renere, mere effektiv og mere vedligeholdelsesvenlig. Ved at bruge computed funktioner kan du deklarativt specificere kompleks logik i dine templates og drage fordel af Vue 3's automatiske caching for at forbedre din applikations ydeevne.",[972,3002,3003],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":217,"searchDepth":218,"depth":218,"links":3005},[],"2022-12-23","Lær hvordan du får mest ud af Vue og computed funktioner. Gør din kode renere og mere vedligeholdelsesvenlig.",{},"\u002Fblog\u002Fvue3-computed-funktioner",{"title":2446,"description":3007},"Lær hvordan du får mest ud af computed funktioner i Vue 3. Gør din kode renere, mere læsbar og vedligeholdelsesvenlig med praktiske eksempler.","vue3-computed-funktioner","blog\u002Fvue3-computed-funktioner",[997,3015,1392],"best-practices","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*Ht8T-vqbqy5iG7FzNQGjFA.png","fZNo7ASBoKuvBwCHBUDJgv6CHkobeWC_kaRTBiJLMqw",{"id":3019,"title":3020,"body":3021,"date":3543,"description":3544,"extension":236,"meta":3545,"navigation":238,"noindex":8,"path":3546,"seo":3547,"seoDescription":3544,"seoTitle":3020,"slug":3548,"stem":3549,"tags":3550,"thumbnail":3552,"updated":3543,"__hash__":3553},"blog\u002Fblog\u002Fderfor-bor-du-bruge-vue-3-composition-api.md","Derfor bør du bruge Vue 3's Composition API",{"type":40,"value":3022,"toc":3536},[3023,3026,3029,3032,3035,3038,3042,3190,3222,3226,3229,3232,3234,3237,3241,3488,3526,3530,3533],[48,3024,3025],{},"Som udvikler, der bruger Vue i mit daglige arbejde, har jeg fundet Composition API til at være en game-changer, når det kommer til at organisere og bygge komponenter.",[48,3027,3028],{},"Composition API er en ny funktion introduceret i Vue 3, der giver en anden måde at organisere og bygge Vue-komponenter på. Det giver udviklere mulighed for at udtrække logik fra komponenter og genbruge den på tværs af flere komponenter, hvilket kan forbedre læsbarhed og vedligeholdelse af koden.",[48,3030,3031],{},"En af de vigtigste fordele er, at det gør det nemmere at håndtere state og logik inden for en komponent ved at give dig mulighed for at definere reaktive egenskaber og funktioner direkte i den. Det forbedrer ikke kun kodens læsbarhed og vedligeholdelse, men kan også gøre det nemmere at forstå, hvordan en komponent fungerer, og hvad dens afhængigheder er.",[48,3033,3034],{},"En anden fordel ved Composition API er, at det giver udviklere mulighed for at udtrække og genbruge logik på tværs af flere komponenter. Det kan være særligt nyttigt i store applikationer, hvor det er almindeligt at have flere komponenter, der skal dele den samme funktionalitet. Ved at udtrække den delte logik i en composition-funktion kan den nemt genbruges i et vilkårligt antal komponenter, hvilket reducerer duplikering og gør det nemmere at vedligeholde kodebasen.",[48,3036,3037],{},"Ud over at forbedre kodeorganisering og genbrug tilbyder Composition API også forbedret ydeevne takket være sin deklarative syntaks, som giver Vues reaktive system mulighed for mere effektivt at spore ændringer og opdatere komponentens state. Det kan resultere i hurtigere rendering og bedre ydeevne, især i store applikationer.",[119,3039,3041],{"id":3040},"et-lille-eksempel-på-brug-af-composition-api","Et lille eksempel på brug af Composition API:",[280,3043,3045],{"className":2047,"code":3044,"language":1392,"meta":217,"style":217},"import { ref, computed } from 'vue'\n\nexport default {\n  setup() {\n    const count = ref(0)\n    const doubleCount = computed(() => count.value * 2)\n\n    function increment() {\n      count.value++\n    }\n\n    return {\n      count,\n      doubleCount,\n      increment\n    }\n  }\n}\n",[287,3046,3047,3061,3065,3074,3080,3099,3125,3129,3139,3147,3152,3156,3163,3168,3173,3178,3182,3186],{"__ignoreMap":217},[332,3048,3049,3052,3055,3058],{"class":334,"line":335},[332,3050,3051],{"class":344},"import",[332,3053,3054],{"class":355}," { ref, computed } ",[332,3056,3057],{"class":344},"from",[332,3059,3060],{"class":551}," 'vue'\n",[332,3062,3063],{"class":334,"line":218},[332,3064,418],{"emptyLinePlaceholder":238},[332,3066,3067,3069,3072],{"class":334,"line":226},[332,3068,345],{"class":344},[332,3070,3071],{"class":344}," default",[332,3073,782],{"class":355},[332,3075,3076,3078],{"class":334,"line":395},[332,3077,2187],{"class":351},[332,3079,356],{"class":355},[332,3081,3082,3085,3088,3090,3092,3094,3097],{"class":334,"line":415},[332,3083,3084],{"class":344},"    const",[332,3086,3087],{"class":364}," count",[332,3089,368],{"class":344},[332,3091,371],{"class":351},[332,3093,407],{"class":355},[332,3095,3096],{"class":364},"0",[332,3098,392],{"class":355},[332,3100,3101,3103,3106,3108,3110,3112,3114,3117,3120,3123],{"class":334,"line":421},[332,3102,3084],{"class":344},[332,3104,3105],{"class":364}," doubleCount",[332,3107,368],{"class":344},[332,3109,2702],{"class":351},[332,3111,2705],{"class":355},[332,3113,566],{"class":344},[332,3115,3116],{"class":355}," count.value ",[332,3118,3119],{"class":344},"*",[332,3121,3122],{"class":364}," 2",[332,3124,392],{"class":355},[332,3126,3127],{"class":334,"line":434},[332,3128,418],{"emptyLinePlaceholder":238},[332,3130,3131,3134,3137],{"class":334,"line":446},[332,3132,3133],{"class":344},"    function",[332,3135,3136],{"class":351}," increment",[332,3138,356],{"class":355},[332,3140,3141,3144],{"class":334,"line":466},[332,3142,3143],{"class":355},"      count.value",[332,3145,3146],{"class":344},"++\n",[332,3148,3149],{"class":334,"line":476},[332,3150,3151],{"class":355},"    }\n",[332,3153,3154],{"class":334,"line":482},[332,3155,418],{"emptyLinePlaceholder":238},[332,3157,3158,3161],{"class":334,"line":487},[332,3159,3160],{"class":344},"    return",[332,3162,782],{"class":355},[332,3164,3165],{"class":334,"line":496},[332,3166,3167],{"class":355},"      count,\n",[332,3169,3170],{"class":334,"line":2156},[332,3171,3172],{"class":355},"      doubleCount,\n",[332,3174,3175],{"class":334,"line":2162},[332,3176,3177],{"class":355},"      increment\n",[332,3179,3180],{"class":334,"line":2173},[332,3181,3151],{"class":355},[332,3183,3184],{"class":334,"line":2179},[332,3185,479],{"class":355},[332,3187,3188],{"class":334,"line":2184},[332,3189,499],{"class":355},[48,3191,3192,3193,3196,3197,3200,3201,3204,3205,3208,3209,3211,3212,3215,3216,3218,3219,3221],{},"I dette eksempel bruger vi ",[287,3194,3195],{},"ref","-funktionen til at oprette en reaktiv egenskab kaldet ",[287,3198,3199],{},"count",", og ",[287,3202,3203],{},"computed","-funktionen til at oprette en afledt værdi kaldet ",[287,3206,3207],{},"doubleCount",", der er baseret på værdien af ",[287,3210,3199],{},". Vi definerer også en funktion kaldet ",[287,3213,3214],{},"increment",", der forhøjer værdien af ",[287,3217,3199],{},". Disse reaktive egenskaber og funktioner returneres fra ",[287,3220,2248],{},"-funktionen og kan bruges i komponentens template.",[43,3223,3225],{"id":3224},"composition-api-vs-options-api","Composition API vs Options API",[48,3227,3228],{},"Composition API er ikke en erstatning for Options API, som er den traditionelle måde at organisere og bygge Vue-komponenter på. Begge tilgange har deres egne styrker og svagheder, og det er op til den enkelte udvikler at beslutte, hvilken tilgang der passer bedst til deres behov.",[48,3230,3231],{},"En af de vigtigste fordele ved Composition API er, at det kan forbedre kodens læsbarhed og vedligeholdelse. Composition API giver udviklere mulighed for at udtrække logik fra komponenter og definere den i en deklarativ syntaks, hvilket kan gøre det nemmere at forstå, hvordan en komponent fungerer, og hvad dens afhængigheder er. Til sammenligning kan Options API nogle gange resultere i store, komplekse komponenter, der er svære at forstå og vedligeholde.",[48,3233,3034],{},[48,3235,3236],{},"På den anden side er Options API velkendt for mange udviklere og er bredt brugt i Vue-økosystemet. Det er en gennemprøvet tilgang, der har eksisteret siden Vues tidlige dage, og det er stadig en gyldig måde at bygge Vue-komponenter på.",[119,3238,3240],{"id":3239},"herunder-er-et-grundlæggende-eksempel-hvor-vi-sammenligner-options-api-vs-composition-api","Herunder er et grundlæggende eksempel, hvor vi sammenligner Options API vs Composition API.",[280,3242,3244],{"className":2047,"code":3243,"language":1392,"meta":217,"style":217},"\u002F\u002F Using the Options API\nexport default {\n  data() {\n    return {\n      count: 0\n    }\n  },\n  computed: {\n    doubleCount() {\n      return this.count * 2\n    }\n  },\n  methods: {\n    increment() {\n      this.count++\n    }\n  }\n}\n\n\u002F\u002F Using the Composition API\nimport { ref, computed } from 'vue'\n\nexport default {\n  setup() {\n    const count = ref(0)\n    const doubleCount = computed(() => count.value * 2)\n\n    function increment() {\n      count.value++\n    }\n\n    return {\n      count,\n      doubleCount,\n      increment\n    }\n  }\n}\n",[287,3245,3246,3251,3259,3266,3272,3280,3284,3288,3293,3300,3315,3319,3323,3328,3335,3345,3349,3353,3357,3361,3366,3376,3380,3388,3394,3410,3432,3436,3444,3450,3454,3458,3464,3468,3472,3476,3480,3484],{"__ignoreMap":217},[332,3247,3248],{"class":334,"line":335},[332,3249,3250],{"class":338},"\u002F\u002F Using the Options API\n",[332,3252,3253,3255,3257],{"class":334,"line":218},[332,3254,345],{"class":344},[332,3256,3071],{"class":344},[332,3258,782],{"class":355},[332,3260,3261,3264],{"class":334,"line":226},[332,3262,3263],{"class":351},"  data",[332,3265,356],{"class":355},[332,3267,3268,3270],{"class":334,"line":395},[332,3269,3160],{"class":344},[332,3271,782],{"class":355},[332,3273,3274,3277],{"class":334,"line":415},[332,3275,3276],{"class":355},"      count: ",[332,3278,3279],{"class":364},"0\n",[332,3281,3282],{"class":334,"line":421},[332,3283,3151],{"class":355},[332,3285,3286],{"class":334,"line":434},[332,3287,581],{"class":355},[332,3289,3290],{"class":334,"line":446},[332,3291,3292],{"class":355},"  computed: {\n",[332,3294,3295,3298],{"class":334,"line":466},[332,3296,3297],{"class":351},"    doubleCount",[332,3299,356],{"class":355},[332,3301,3302,3304,3307,3310,3312],{"class":334,"line":476},[332,3303,2714],{"class":344},[332,3305,3306],{"class":364}," this",[332,3308,3309],{"class":355},".count ",[332,3311,3119],{"class":344},[332,3313,3314],{"class":364}," 2\n",[332,3316,3317],{"class":334,"line":482},[332,3318,3151],{"class":355},[332,3320,3321],{"class":334,"line":487},[332,3322,581],{"class":355},[332,3324,3325],{"class":334,"line":496},[332,3326,3327],{"class":355},"  methods: {\n",[332,3329,3330,3333],{"class":334,"line":2156},[332,3331,3332],{"class":351},"    increment",[332,3334,356],{"class":355},[332,3336,3337,3340,3343],{"class":334,"line":2162},[332,3338,3339],{"class":364},"      this",[332,3341,3342],{"class":355},".count",[332,3344,3146],{"class":344},[332,3346,3347],{"class":334,"line":2173},[332,3348,3151],{"class":355},[332,3350,3351],{"class":334,"line":2179},[332,3352,479],{"class":355},[332,3354,3355],{"class":334,"line":2184},[332,3356,499],{"class":355},[332,3358,3359],{"class":334,"line":2193},[332,3360,418],{"emptyLinePlaceholder":238},[332,3362,3363],{"class":334,"line":2204},[332,3364,3365],{"class":338},"\u002F\u002F Using the Composition API\n",[332,3367,3368,3370,3372,3374],{"class":334,"line":2210},[332,3369,3051],{"class":344},[332,3371,3054],{"class":355},[332,3373,3057],{"class":344},[332,3375,3060],{"class":551},[332,3377,3378],{"class":334,"line":2215},[332,3379,418],{"emptyLinePlaceholder":238},[332,3381,3382,3384,3386],{"class":334,"line":2221},[332,3383,345],{"class":344},[332,3385,3071],{"class":344},[332,3387,782],{"class":355},[332,3389,3390,3392],{"class":334,"line":2801},[332,3391,2187],{"class":351},[332,3393,356],{"class":355},[332,3395,3396,3398,3400,3402,3404,3406,3408],{"class":334,"line":2828},[332,3397,3084],{"class":344},[332,3399,3087],{"class":364},[332,3401,368],{"class":344},[332,3403,371],{"class":351},[332,3405,407],{"class":355},[332,3407,3096],{"class":364},[332,3409,392],{"class":355},[332,3411,3412,3414,3416,3418,3420,3422,3424,3426,3428,3430],{"class":334,"line":2848},[332,3413,3084],{"class":344},[332,3415,3105],{"class":364},[332,3417,368],{"class":344},[332,3419,2702],{"class":351},[332,3421,2705],{"class":355},[332,3423,566],{"class":344},[332,3425,3116],{"class":355},[332,3427,3119],{"class":344},[332,3429,3122],{"class":364},[332,3431,392],{"class":355},[332,3433,3434],{"class":334,"line":2860},[332,3435,418],{"emptyLinePlaceholder":238},[332,3437,3438,3440,3442],{"class":334,"line":2883},[332,3439,3133],{"class":344},[332,3441,3136],{"class":351},[332,3443,356],{"class":355},[332,3445,3446,3448],{"class":334,"line":2889},[332,3447,3143],{"class":355},[332,3449,3146],{"class":344},[332,3451,3452],{"class":334,"line":2895},[332,3453,3151],{"class":355},[332,3455,3456],{"class":334,"line":2900},[332,3457,418],{"emptyLinePlaceholder":238},[332,3459,3460,3462],{"class":334,"line":2909},[332,3461,3160],{"class":344},[332,3463,782],{"class":355},[332,3465,3466],{"class":334,"line":2915},[332,3467,3167],{"class":355},[332,3469,3470],{"class":334,"line":2921},[332,3471,3172],{"class":355},[332,3473,3474],{"class":334,"line":2927},[332,3475,3177],{"class":355},[332,3477,3478],{"class":334,"line":2933},[332,3479,3151],{"class":355},[332,3481,3482],{"class":334,"line":2938},[332,3483,479],{"class":355},[332,3485,3486],{"class":334,"line":2943},[332,3487,499],{"class":355},[48,3489,3490,3491,3493,3494,3208,3496,3498,3499,3502,3503,2241,3505,3508,3509,2241,3511,3513,3514,3516,3517,3519,3520,3522,3523,3525],{},"I dette eksempel kan vi se, at Options API og Composition API begge definerer en reaktiv egenskab kaldet ",[287,3492,3199],{}," og en afledt værdi kaldet ",[287,3495,3207],{},[287,3497,3199],{},". Dog bruger Options API ",[287,3500,3501],{},"data","-, ",[287,3504,3203],{},[287,3506,3507],{},"methods","-options til at definere disse værdier, mens Composition API bruger ",[287,3510,3195],{},[287,3512,3203],{},"-funktionerne til at definere dem inden for ",[287,3515,2248],{},"-funktionen. Composition API giver os også mulighed for at definere ",[287,3518,3214],{},"-funktionen direkte inden for ",[287,3521,2248],{},"-funktionen, i stedet for at bruge ",[287,3524,3507],{},"-optionen.",[43,3527,3529],{"id":3528},"opsummering","Opsummering",[48,3531,3532],{},"Afslutningsvis er Composition API en værdifuld tilføjelse til Vue-økosystemet, der tilbyder forbedret kodeorganisering, forbedret ydeevne og muligheden for nemt at genbruge logik på tværs af flere komponenter. Selvom det ikke er en erstatning for Options API, er det et kraftfuldt værktøj, der er værd at overveje for enhver Vue-udvikler. Om du vælger at bruge Composition API eller Options API (eller en kombination af begge) afhænger af dine specifikke behov og præferencer, men Composition API er absolut en funktion, der er værd at udforske.",[972,3534,3535],{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":217,"searchDepth":218,"depth":218,"links":3537},[3538,3539,3542],{"id":3040,"depth":226,"text":3041},{"id":3224,"depth":218,"text":3225,"children":3540},[3541],{"id":3239,"depth":226,"text":3240},{"id":3528,"depth":218,"text":3529},"2022-12-16","Se hvorfor jeg foretrækker det nye Composition API frem for Options API, hvad forskellene er, og hvordan du kommer i gang!",{},"\u002Fblog\u002Fderfor-bor-du-bruge-vue-3-composition-api",{"title":3020,"description":3544},"derfor-bor-du-bruge-vue-3-composition-api","blog\u002Fderfor-bor-du-bruge-vue-3-composition-api",[997,3551,995],"komposition-api","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*sl1r7xdgVW5HWxbvtwJkVQ.png","Cvf5fpXoUCiLYW48JlZ8IIQqCpxYWSqY7ZhBjNk5dd0",{"id":3555,"title":3556,"body":3557,"date":3691,"description":3692,"extension":236,"meta":3693,"navigation":238,"noindex":8,"path":3694,"seo":3695,"seoDescription":3692,"seoTitle":3696,"slug":3697,"stem":3698,"tags":3699,"thumbnail":3701,"updated":3691,"__hash__":3702},"blog\u002Fblog\u002Fpinia-state-management-for-vue.md","Pinia, det nye (og bedre) state management system til Vue",{"type":40,"value":3558,"toc":3686},[3559,3562,3565,3569,3572,3575,3578,3581,3586,3589,3595,3598,3603,3606,3611,3614,3620,3623,3627,3630,3633,3639,3642,3648,3651,3657,3660,3663,3668,3671,3675,3678,3683],[48,3560,3561],{},"Har du endnu ikke hørt om Pinia, eller overvejer du at skifte fra Vuex til Pinia? Så kan denne artikel hjælpe dig.",[48,3563,3564],{},"Jeg vil forsøge at give dig en ordentlig introduktion til det nye state management system, Pinia til Vue. Hvorfor jeg synes det er et fantastisk værktøj, og hvorfor du bør bruge det allerede i dag.",[43,3566,3568],{"id":3567},"hvad-er-pinia","Hvad er Pinia",[48,3570,3571],{},"Pinia er et nyt store\u002Fstate management system til Vue. Det er et fantastisk værktøj, når du vil dele data mellem komponenter i din applikation. En af grundene til at bruge et værktøj som Pinia (eller Vuex for den sags skyld) er, at det hurtigt kan blive rodet og ustruktureret at sende events rundt og lytte efter dem i din applikation. State management systemer som Pinia (Vuex, Redux osv.) kan hjælpe med at løse dette.",[48,3573,3574],{},"Pinia er nu også det anbefalede valg fra Vue og er officielt en del af hele Vue-økosystemet, vedligeholdt og udviklet af kernemedlemmer i Vue-teamet. Sidst men ikke mindst er Pinia super letvægtigt - kun 1kb i størrelse, hvilket er helt fantastisk.",[48,3576,3577],{},"Hvorfor har vi brug for Pinia?",[48,3579,3580],{},"Hvis du har været i Vue-communityet, ved du, at det foretrukne valg har været Vuex, når det kommer til state management, og communityet har været glade for at bruge det. Så hvorfor har vi egentlig brug for Pinia? Ja... Vuex kan være... besværligt at arbejde med! Lad mig gå lidt dybere ind i hvorfor.",[48,3582,3583],{},[67,3584,3585],{},"Dataflow",[48,3587,3588],{},"Dataflowet i Vuex kan være noget svært at forstå.",[48,3590,3591],{},[3592,3593],"img",{"alt":217,"src":3594},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F0*M29gr5IH-oc9-1pX",[48,3596,3597],{},"Bliver du overvældet af diagrammet? Det forstår jeg godt - Ved første øjekast kan det se noget kompliceret og skræmmende ud - Og når man begynder at arbejde med Vuex og principperne omkring Vuex, kan det tage noget tid virkelig at forstå, hvordan du ændrer state, bruger actions og mutations osv.",[48,3599,3600],{},[67,3601,3602],{},"Meget opsætning",[48,3604,3605],{},"Vuex tager tid at sætte op! Det tager tid at skabe en god solid arkitektur, oprette moduler, opdele filer og sætte namespacing op - Moduler indeholder også ofte meget af den samme boilerplate-kode. En ting der virkelig er tidskrævende, er at få Vuex til at fungere ordentligt i et TypeScript-projekt. Du vil ofte finde dig selv i at skulle manuelt inferere typer over det hele - på din state, getters, mutations og actions. Et rigtigt besvær!",[48,3607,3608],{},[67,3609,3610],{},"Afhængig af string-værdier! Usikkert!",[48,3612,3613],{},"Når du har defineret dine mutations og actions, finder du ofte dig selv i at sende string-værdier, når du vil kalde en action eller committe:",[280,3615,3618],{"className":3616,"code":3617,"language":285},[283],"store.dispatch('utils\u002FaddBodyClass', 'some-class'); \u002F\u002Faction\nstore.commit('utils\u002FsetData', response); \u002F\u002Fmutation\nstore.getters['user\u002FuserId'] \u002F\u002Fgetter\n",[287,3619,3617],{"__ignoreMap":217},[48,3621,3622],{},"Som du kan se ovenfor, bruger vi string-værdier, hvilket er meget usikkert. Hvad hvis du har en tastefejl? Du får heller ikke intellisense\u002Fcode completion ud af boksen, medmindre du manuelt har typet alle actions, mutations osv. Forstår du pointen? Det er meget udsat for manuelle fejl, som kan føre til bugs! Mange ville foreslå at bruge konstanter i stedet for at undgå dette, men det ville også være meget tidskrævende at sætte op.",[43,3624,3626],{"id":3625},"pinia-fjerner-besværet","Pinia fjerner besværet",[48,3628,3629],{},"Pinia løser mange af de ting, der er besværlige ved Vuex. Det har en meget simplere API, og hvis du har arbejdet med composables i Vue 3, vil Pinia føles meget velkendt. Det kræver langt mindre opsætning end Vuex, hvilket sparer dig tid! Pinia kommer også med førsteklasses TypeScript-support ud af boksen, hvilket er rigtig rart, og du får bedre code completion i dit IDE på grund af den måde, Pinia er bygget på!",[48,3631,3632],{},"Storens actions dispatches som almindelige funktionskald i stedet for at bruge dispatch\u002Fcommit-metoden eller MapAction\u002FMapMutation-hjælpefunktioner, som er normalt i Vuex. Det betyder også, at når du kalder en action, behøver du ikke stole på at sende string-værdier som i Vuex! En kæmpe gevinst!",[48,3634,3635],{},[3592,3636],{"alt":3637,"src":3638},"Simpleste eksempel på Vuex & Pinia","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*7Wz0P4DbmXHovQFn2F1XSA.png",[48,3640,3641],{},"Udover at det er nemmere at sætte op, vil dit IDE også give dig meget bedre autocompletion og support for TypeScript - Det dykker vi ned i senere:",[48,3643,3644],{},[3592,3645],{"alt":3646,"src":3647},"Simpelt eksempel på at kalde en action i Pinia","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*RYJGvLN4uYtC0W8PIPccPg.png",[48,3649,3650],{},"I Vuex har du kun 1 store - Hvis du har brug for bedre adskillelse og mere struktur, skal du oprette Vuex-moduler. I Pinia har du flere stores. Det betyder også, at du ikke behøver at sætte en index.ts-fil op og importere alle moduler for at kunne bruge dem, som i Vuex. I Pinia importerer du bare din store i din fil, som vist på skærmbilledet ovenfor:",[48,3652,3653],{},[3592,3654],{"alt":3655,"src":3656},"Vuex vs Pinia - Opsætning af stores","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*5pz0ih6TUClcPyS9yF-Wmg.png",[48,3658,3659],{},"Ligesom Vuex integrerer Pinia også rigtig godt med Vue Devtools, så du kan udnytte alle funktioner, som du gjorde med Vuex - Ikke den største forskel på det område.",[48,3661,3662],{},"Som jeg også nævnte tidligere: Hvis du har arbejdet med Vue composables, bør Pinia-syntaksen føles meget velkendt - Se selv herunder:",[48,3664,3665],{},[3592,3666],{"alt":217,"src":3667},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*5Uw0kU635WlOviC6gVIszw.png",[48,3669,3670],{},"Jeg synes virkelig, at Pinia er et skridt i den rigtige retning sammenlignet med Vuex. Det løser virkelig mange af de \"problemer\", man tidligere har haft med Vuex. Jeg glæder mig til at følge de næste udgivelser af Pinia for at se, hvilken retning det tager, og hvilke muligheder det vil bringe til udviklere. Jeg er også spændt på at se, hvilke plugins Vue-communityet vil skabe til Pinia. Der er mange rigtig gode plugins til Vuex, så jeg håber, de også bliver tilgængelige i Pinia med tiden.",[43,3672,3674],{"id":3673},"_1-ting-ved-pinia","1 ting ved Pinia",[48,3676,3677],{},"Nu hvor jeg har dykket lidt ned i Pinia, fandt jeg en ting, som jeg synes er lidt mærkelig, eller som man kunne betragte som bad practice. I Pinia kan du direkte fra dine komponenter mutere staten i din store:",[48,3679,3680],{},[3592,3681],{"alt":217,"src":3682},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*mFsGrlsvjxjr64DUb0tm4A.png",[48,3684,3685],{},"Jeg er ikke sikker på, om jeg kan lide det eller ej. Måske er det fordi man i Vuex, hvis man vil ændre noget state, skal lave en mutation, hvilket man ikke behøver i Pinia. Jeg ved ikke, om jeg ville betragte det som bad practice på nogen måde, men jeg tror det kan være farligt, da det kan forårsage utilsigtede sideeffekter. Jeg har dog ikke brugt det i et stort projekt endnu, så jeg er også tilbageholdende med at sige, at det er bad practice, bare fordi jeg har været vant til noget andet. Jeg ville elske at høre din holdning til dette?",{"title":217,"searchDepth":218,"depth":218,"links":3687},[3688,3689,3690],{"id":3567,"depth":218,"text":3568},{"id":3625,"depth":218,"text":3626},{"id":3673,"depth":218,"text":3674},"2022-05-21","Har du endnu ikke hørt om Pinia, eller overvejer du at skifte fra Vuex til Pinia? Så kan denne artikel hjælpe dig med at komme i gang.",{},"\u002Fblog\u002Fpinia-state-management-for-vue",{"title":3556,"description":3692},"Pinia - Det nye og bedre state management system til Vue","pinia-state-management-for-vue","blog\u002Fpinia-state-management-for-vue",[997,3700,995],"state-management","https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*TOGHpRhMF0wGXhsrCga94w.png","8jQ8mXf5ia7jGM1xzA4sVDZ5qq-tByBmCHUTz05kr30",{"id":3704,"title":3705,"body":3706,"date":4697,"description":4698,"extension":236,"meta":4699,"navigation":238,"noindex":8,"path":4700,"seo":4701,"seoDescription":4702,"seoTitle":4703,"slug":4704,"stem":4705,"tags":4706,"thumbnail":4707,"updated":4697,"__hash__":4708},"blog\u002Fblog\u002Fvue-3-tips-og-tricks.md","Vue 3 Tips & Tricks",{"type":40,"value":3707,"toc":4688},[3708,3711,3714,3717,3721,3730,3799,3817,4685],[48,3709,3710],{},"Bliv en bedre og mere effektiv Vue-udvikler med disse tips og tricks.",[48,3712,3713],{},"Jeg har arbejdet med Vue i mange år og har arbejdet specifikt med Vue 3 det seneste år. I den tid har jeg lært en masse.",[48,3715,3716],{},"Jeg har tidligere lavet artikler om Vue og Vue 3 med tips og best practices. Denne artikel tager det et skridt videre og går ind i nogle ting, der ikke nødvendigvis er dækket i de andre artikler. Jeg håber, du finder det nyttigt.",[43,3718,3720],{"id":3719},"script-setup-shorthand","Script Setup Shorthand",[48,3722,3723,3724,1229,3727,791],{},"Hvis du har arbejdet med Composition API'et før, har du måske bemærket, at du altid skal gøre noget som det følgende for at få det sat op — du skal altid bruge ",[67,3725,3726],{},"defineComponent",[67,3728,3729],{},"setup() {}",[280,3731,3733],{"className":2047,"code":3732,"language":1392,"meta":217,"style":217},"\u003Cscript lang=\"ts\">\nimport {defineComponent} from 'vue';\n\nexport default defineComponent({\n  name: 'Test',\n  setup() {\n    \u002F\u002FAdd business logic\n  }\n})\n\u003C\u002Fscript>\n",[287,3734,3735,3749,3754,3758,3762,3771,3777,3782,3786,3791],{"__ignoreMap":217},[332,3736,3737,3739,3741,3743,3745,3747],{"class":334,"line":335},[332,3738,374],{"class":355},[332,3740,2127],{"class":2057},[332,3742,2611],{"class":351},[332,3744,440],{"class":344},[332,3746,2616],{"class":551},[332,3748,2061],{"class":355},[332,3750,3751],{"class":334,"line":218},[332,3752,3753],{"class":355},"import {defineComponent} from 'vue';\n",[332,3755,3756],{"class":334,"line":226},[332,3757,418],{"emptyLinePlaceholder":238},[332,3759,3760],{"class":334,"line":395},[332,3761,2655],{"class":355},[332,3763,3764,3766,3769],{"class":334,"line":415},[332,3765,2660],{"class":355},[332,3767,3768],{"class":551},"'Test'",[332,3770,555],{"class":355},[332,3772,3773,3775],{"class":334,"line":421},[332,3774,2187],{"class":351},[332,3776,356],{"class":355},[332,3778,3779],{"class":334,"line":434},[332,3780,3781],{"class":338},"    \u002F\u002FAdd business logic\n",[332,3783,3784],{"class":334,"line":446},[332,3785,479],{"class":355},[332,3787,3788],{"class":334,"line":466},[332,3789,3790],{"class":355},"})\n",[332,3792,3793,3795,3797],{"class":334,"line":476},[332,3794,2112],{"class":355},[332,3796,2127],{"class":2057},[332,3798,2061],{"class":355},[48,3800,3801,3802,3808],{},"Det kan være ret besværligt at gøre dette for hver komponent, og du kan faktisk undgå det. Du kan bruge ",[167,3803,3804],{},[67,3805,3806],{},[2127,3807],{"setup":217},[67,3809,3810,3811,3816],{},", som er en shorthand for det samme som vist ovenfor. Det er grundlæggende bare syntaktisk sukker ovenpå, så du ikke skal lave den manuelle opsætning hver gang. Med ",[167,3812,3813],{},[67,3814,3815],{},"\u003Cscript setup>"," bliver din komponent forenklet til:",[67,3818,3819,3854,3858,3861,4107,4115,4119,4122,4194,4198,4201,4204,4294,4303,4307,4310,4317,4321,4324,4330,4463,4469,4505,4515,4519,4528,4531,4592,4599],{},[280,3820,3822],{"className":2460,"code":3821,"language":997,"meta":217,"style":217},"\u003Cscript lang=\"ts\" setup>\n  \u002F\u002FAdd business logic\n\u003C\u002Fscript>\n",[287,3823,3824,3841,3846],{"__ignoreMap":217},[332,3825,3826,3828,3830,3832,3834,3836,3839],{"class":334,"line":335},[332,3827,374],{"class":355},[332,3829,2127],{"class":2057},[332,3831,2611],{"class":351},[332,3833,440],{"class":355},[332,3835,2616],{"class":551},[332,3837,3838],{"class":351}," setup",[332,3840,2061],{"class":355},[332,3842,3843],{"class":334,"line":218},[332,3844,3845],{"class":338},"  \u002F\u002FAdd business logic\n",[332,3847,3848,3850,3852],{"class":334,"line":226},[332,3849,2112],{"class":355},[332,3851,2127],{"class":2057},[332,3853,2061],{"class":355},[43,3855,3857],{"id":3856},"sådan-overskriver-du-et-reactive-objekt","Sådan overskriver du et reactive objekt",[48,3859,3860],{},"Som standard kan du ikke overskrive et helt reactive objekt, og hvis du gør det, mister du reaktiviteten.",[280,3862,3864],{"className":2047,"code":3863,"language":1392,"meta":217,"style":217},"\u003Cscript lang=\"ts\">\nimport { defineComponent, reactive, onMounted } from \"vue\";\n\nexport default defineComponent({\n  name: \"HelloWorld\",\n  setup() {\n    let myReactiveObject = reactive({\n      name: \"Nicky\",\n      age: \"37\",\n      country: \"DK\",\n    });\n\n    let newObject = {\n      name: \"Nicky Christensen\",\n      age: \"36\",\n      country: \"DA-DK\",\n    };\n\n    onMounted(() => {\n      setTimeout(() => {\n        \u002F\u002FmyReactiveObject = newObject \u002F\u002FWont work\n        Object.assign(myReactiveObject, newObject) \u002F\u002FWill work\n      }, 2000)\n    })\n\n    return {\n      myReactiveObject,\n    };\n  },\n});\n\u003C\u002Fscript>\n",[287,3865,3866,3880,3885,3889,3893,3902,3908,3921,3931,3941,3951,3955,3959,3968,3977,3986,3995,3999,4003,4014,4025,4033,4059,4069,4074,4078,4082,4087,4091,4095,4099],{"__ignoreMap":217},[332,3867,3868,3870,3872,3874,3876,3878],{"class":334,"line":335},[332,3869,374],{"class":355},[332,3871,2127],{"class":2057},[332,3873,2611],{"class":351},[332,3875,440],{"class":344},[332,3877,2616],{"class":551},[332,3879,2061],{"class":355},[332,3881,3882],{"class":334,"line":218},[332,3883,3884],{"class":355},"import { defineComponent, reactive, onMounted } from \"vue\";\n",[332,3886,3887],{"class":334,"line":226},[332,3888,418],{"emptyLinePlaceholder":238},[332,3890,3891],{"class":334,"line":395},[332,3892,2655],{"class":355},[332,3894,3895,3897,3900],{"class":334,"line":415},[332,3896,2660],{"class":355},[332,3898,3899],{"class":551},"\"HelloWorld\"",[332,3901,555],{"class":355},[332,3903,3904,3906],{"class":334,"line":421},[332,3905,2187],{"class":351},[332,3907,356],{"class":355},[332,3909,3910,3913,3915,3918],{"class":334,"line":434},[332,3911,3912],{"class":355},"    let myReactiveObject ",[332,3914,440],{"class":344},[332,3916,3917],{"class":351}," reactive",[332,3919,3920],{"class":355},"({\n",[332,3922,3923,3926,3929],{"class":334,"line":446},[332,3924,3925],{"class":355},"      name: ",[332,3927,3928],{"class":551},"\"Nicky\"",[332,3930,555],{"class":355},[332,3932,3933,3936,3939],{"class":334,"line":466},[332,3934,3935],{"class":355},"      age: ",[332,3937,3938],{"class":551},"\"37\"",[332,3940,555],{"class":355},[332,3942,3943,3946,3949],{"class":334,"line":476},[332,3944,3945],{"class":355},"      country: ",[332,3947,3948],{"class":551},"\"DK\"",[332,3950,555],{"class":355},[332,3952,3953],{"class":334,"line":482},[332,3954,2734],{"class":355},[332,3956,3957],{"class":334,"line":487},[332,3958,418],{"emptyLinePlaceholder":238},[332,3960,3961,3964,3966],{"class":334,"line":496},[332,3962,3963],{"class":355},"    let newObject ",[332,3965,440],{"class":344},[332,3967,782],{"class":355},[332,3969,3970,3972,3975],{"class":334,"line":2156},[332,3971,3925],{"class":355},[332,3973,3974],{"class":551},"\"Nicky Christensen\"",[332,3976,555],{"class":355},[332,3978,3979,3981,3984],{"class":334,"line":2162},[332,3980,3935],{"class":355},[332,3982,3983],{"class":551},"\"36\"",[332,3985,555],{"class":355},[332,3987,3988,3990,3993],{"class":334,"line":2173},[332,3989,3945],{"class":355},[332,3991,3992],{"class":551},"\"DA-DK\"",[332,3994,555],{"class":355},[332,3996,3997],{"class":334,"line":2179},[332,3998,2892],{"class":355},[332,4000,4001],{"class":334,"line":2184},[332,4002,418],{"emptyLinePlaceholder":238},[332,4004,4005,4008,4010,4012],{"class":334,"line":2193},[332,4006,4007],{"class":351},"    onMounted",[332,4009,2705],{"class":355},[332,4011,566],{"class":344},[332,4013,782],{"class":355},[332,4015,4016,4019,4021,4023],{"class":334,"line":2204},[332,4017,4018],{"class":351},"      setTimeout",[332,4020,2705],{"class":355},[332,4022,566],{"class":344},[332,4024,782],{"class":355},[332,4026,4027,4030],{"class":334,"line":2210},[332,4028,4029],{"class":338},"        \u002F\u002FmyReactiveObject = newObject",[332,4031,4032],{"class":338}," \u002F\u002FWont work\n",[332,4034,4035,4038,4040,4043,4045,4048,4050,4053,4056],{"class":334,"line":2215},[332,4036,4037],{"class":351},"        Object",[332,4039,1956],{"class":355},[332,4041,4042],{"class":351},"assign",[332,4044,407],{"class":355},[332,4046,4047],{"class":787},"myReactiveObject",[332,4049,687],{"class":355},[332,4051,4052],{"class":787},"newObject",[332,4054,4055],{"class":355},") ",[332,4057,4058],{"class":338},"\u002F\u002FWill work\n",[332,4060,4061,4064,4067],{"class":334,"line":2221},[332,4062,4063],{"class":355},"      }, ",[332,4065,4066],{"class":364},"2000",[332,4068,392],{"class":355},[332,4070,4071],{"class":334,"line":2801},[332,4072,4073],{"class":355},"    })\n",[332,4075,4076],{"class":334,"line":2828},[332,4077,418],{"emptyLinePlaceholder":238},[332,4079,4080],{"class":334,"line":2848},[332,4081,2918],{"class":355},[332,4083,4084],{"class":334,"line":2860},[332,4085,4086],{"class":355},"      myReactiveObject,\n",[332,4088,4089],{"class":334,"line":2883},[332,4090,2892],{"class":355},[332,4092,4093],{"class":334,"line":2889},[332,4094,581],{"class":355},[332,4096,4097],{"class":334,"line":2895},[332,4098,2946],{"class":355},[332,4100,4101,4103,4105],{"class":334,"line":2900},[332,4102,2112],{"class":355},[332,4104,2127],{"class":2057},[332,4106,2061],{"class":355},[48,4108,4109,4110],{},"Tjek denne Codesandbox for at se det i aktion: ",[966,4111,4112],{"href":4112,"rel":4113},"https:\u002F\u002Fcodesandbox.io\u002Fs\u002Flingering-http-ryf2bj?file=\u002Fsrc\u002Fcomponents\u002FHelloWorld.vue",[4114],"nofollow",[43,4116,4118],{"id":4117},"reactive-css","Reactive CSS",[48,4120,4121],{},"En virkelig fantastisk ting i den nye version af Vue er, at du kan binde CSS direkte til dine variabler. Jeg har fundet dette super nyttigt i flere af de applikationer, jeg har bygget det seneste år.",[280,4123,4125],{"className":2047,"code":4124,"language":1392,"meta":217,"style":217},"........\nconst color = ref('#f000');\u003Cstyle>\n.text {\n  color: v-bind(color); \n}\n\u003C\u002Fstyle>\n",[287,4126,4127,4135,4160,4165,4182,4186],{"__ignoreMap":217},[332,4128,4129,4132],{"class":334,"line":335},[332,4130,4131],{"class":344},"......",[332,4133,4134],{"class":355},"..\n",[332,4136,4137,4139,4142,4144,4146,4148,4151,4154,4156,4158],{"class":334,"line":218},[332,4138,530],{"class":344},[332,4140,4141],{"class":364}," color",[332,4143,368],{"class":344},[332,4145,371],{"class":351},[332,4147,407],{"class":355},[332,4149,4150],{"class":551},"'#f000'",[332,4152,4153],{"class":355},");",[332,4155,374],{"class":344},[332,4157,972],{"class":355},[332,4159,2061],{"class":344},[332,4161,4162],{"class":334,"line":226},[332,4163,4164],{"class":355},".text {\n",[332,4166,4167,4170,4173,4176,4179],{"class":334,"line":395},[332,4168,4169],{"class":351},"  color",[332,4171,4172],{"class":355},": v",[332,4174,4175],{"class":344},"-",[332,4177,4178],{"class":351},"bind",[332,4180,4181],{"class":355},"(color); \n",[332,4183,4184],{"class":334,"line":415},[332,4185,499],{"class":355},[332,4187,4188,4190,4192],{"class":334,"line":421},[332,4189,2112],{"class":344},[332,4191,972],{"class":355},[332,4193,2061],{"class":344},[43,4195,4197],{"id":4196},"globale-komponenter","Globale komponenter",[48,4199,4200],{},"Ind imellem vil vi gerne have komponenter, der er globalt tilgængelige, i stedet for at skulle importere dem hver gang vi har brug for dem.",[48,4202,4203],{},"Du kan nemt gøre dette ved at gå til din main.ts og gøre følgende:",[280,4205,4207],{"className":2047,"code":4206,"language":1392,"meta":217,"style":217},"import App from \".\u002FApp.vue\";\nimport MyGlobalSection from '@\u002Fcomponents\u002FMyGlobalSection.vue';\n\nconst app = createApp(App);\n\n\u002F\u002F Make our \u003CMyGlobalSection \u002F> component globally available.\napp.component(MyGlobalSection.name, MyGlobalSection);\n\napp.mount(\"#app\");\n",[287,4208,4209,4223,4237,4241,4256,4260,4265,4276,4280],{"__ignoreMap":217},[332,4210,4211,4213,4216,4218,4221],{"class":334,"line":335},[332,4212,3051],{"class":344},[332,4214,4215],{"class":355}," App ",[332,4217,3057],{"class":344},[332,4219,4220],{"class":551}," \".\u002FApp.vue\"",[332,4222,2729],{"class":355},[332,4224,4225,4227,4230,4232,4235],{"class":334,"line":218},[332,4226,3051],{"class":344},[332,4228,4229],{"class":355}," MyGlobalSection ",[332,4231,3057],{"class":344},[332,4233,4234],{"class":551}," '@\u002Fcomponents\u002FMyGlobalSection.vue'",[332,4236,2729],{"class":355},[332,4238,4239],{"class":334,"line":226},[332,4240,418],{"emptyLinePlaceholder":238},[332,4242,4243,4245,4248,4250,4253],{"class":334,"line":395},[332,4244,530],{"class":344},[332,4246,4247],{"class":364}," app",[332,4249,368],{"class":344},[332,4251,4252],{"class":351}," createApp",[332,4254,4255],{"class":355},"(App);\n",[332,4257,4258],{"class":334,"line":415},[332,4259,418],{"emptyLinePlaceholder":238},[332,4261,4262],{"class":334,"line":421},[332,4263,4264],{"class":338},"\u002F\u002F Make our \u003CMyGlobalSection \u002F> component globally available.\n",[332,4266,4267,4270,4273],{"class":334,"line":434},[332,4268,4269],{"class":355},"app.",[332,4271,4272],{"class":351},"component",[332,4274,4275],{"class":355},"(MyGlobalSection.name, MyGlobalSection);\n",[332,4277,4278],{"class":334,"line":446},[332,4279,418],{"emptyLinePlaceholder":238},[332,4281,4282,4284,4287,4289,4292],{"class":334,"line":466},[332,4283,4269],{"class":355},[332,4285,4286],{"class":351},"mount",[332,4288,407],{"class":355},[332,4290,4291],{"class":551},"\"#app\"",[332,4293,2825],{"class":355},[48,4295,4296,4297,4302],{},"Nu burde du kunne bruge komponenten globalt ved at skrive ",[67,4298,4299],{},[4300,4301],"my-global-section",{}," i templaten i de komponenter, hvor du vil bruge den globale komponent.",[43,4304,4306],{"id":4305},"composition-api-over-options-api","Composition API over Options API",[48,4308,4309],{},"Med Vue 3 har vi fået Composition API'et. Det er en virkelig fantastisk tilføjelse til Vue, og jeg vil argumentere for altid at vælge Composition API'et over Options API'et. En ting jeg elsker ved Composition API'et er, at jeg finder det mere fleksibelt at bruge, og jeg kan bruge composables, som anses for at være en erstatning for mixins. Virkelig kraftfuldt og en rigtig fed tilføjelse.",[48,4311,4312,4313],{},"Er du interesseret i at lære mere om Composition API'et, så tjek denne video: ",[966,4314,4315],{"href":4315,"rel":4316},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=bwItFdPt-6M&ab_channel=Academind",[4114],[43,4318,4320],{"id":4319},"forbedr-performance-med-v-once-eller-v-memo","Forbedr performance med v-once eller v-memo",[48,4322,4323],{},"Hvis du bekymrer dig om hurtig rendering, vil du måske bruge et af Vues indbyggede directives som v-once eller v-memo til at forbedre renderingsperformancen i din applikation.",[48,4325,4326,4329],{},[67,4327,4328],{},"v-once;"," bruges, hvis du vil rendere et element, men ikke have det til at være reaktivt, hvilket betyder, at det ikke indgår i fremtidige renderingscyklusser og derfor er \"statisk\". Du kan anvende v-once på flere elementer, såsom almindelige elementer, i en løkke eller på en komponent.",[280,4331,4333],{"className":2460,"code":4332,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n  \u003C!-- single -->\n  \u003Cp v-once>{{ someProperty }}\u003C\u002Fp>\n\n  \u003C!-- with children -->\n  \u003Cdiv v-once>\n    \u003Cp>{{ someProperty}}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\n  \u003C!-- components -->\n  \u003Cmy-component v-once \u002F>\n\n  \u003C!-- v-for directives -->\n  \u003Cli v-for=\"item in items\" v-once>{{item}}\u003C\u002Fli>\n\u003C\u002Ftemplate>\n",[287,4334,4335,4343,4348,4364,4368,4373,4383,4396,4404,4408,4413,4425,4429,4434,4455],{"__ignoreMap":217},[332,4336,4337,4339,4341],{"class":334,"line":335},[332,4338,374],{"class":355},[332,4340,2058],{"class":2057},[332,4342,2061],{"class":355},[332,4344,4345],{"class":334,"line":218},[332,4346,4347],{"class":338},"  \u003C!-- single -->\n",[332,4349,4350,4352,4354,4357,4360,4362],{"class":334,"line":226},[332,4351,2066],{"class":355},[332,4353,48],{"class":2057},[332,4355,4356],{"class":351}," v-once",[332,4358,4359],{"class":355},">{{ someProperty }}\u003C\u002F",[332,4361,48],{"class":2057},[332,4363,2061],{"class":355},[332,4365,4366],{"class":334,"line":395},[332,4367,418],{"emptyLinePlaceholder":238},[332,4369,4370],{"class":334,"line":415},[332,4371,4372],{"class":338},"  \u003C!-- with children -->\n",[332,4374,4375,4377,4379,4381],{"class":334,"line":421},[332,4376,2066],{"class":355},[332,4378,2069],{"class":2057},[332,4380,4356],{"class":351},[332,4382,2061],{"class":355},[332,4384,4385,4387,4389,4392,4394],{"class":334,"line":434},[332,4386,2076],{"class":355},[332,4388,48],{"class":2057},[332,4390,4391],{"class":355},">{{ someProperty}}\u003C\u002F",[332,4393,48],{"class":2057},[332,4395,2061],{"class":355},[332,4397,4398,4400,4402],{"class":334,"line":446},[332,4399,2103],{"class":355},[332,4401,2069],{"class":2057},[332,4403,2061],{"class":355},[332,4405,4406],{"class":334,"line":466},[332,4407,418],{"emptyLinePlaceholder":238},[332,4409,4410],{"class":334,"line":476},[332,4411,4412],{"class":338},"  \u003C!-- components -->\n",[332,4414,4415,4417,4420,4422],{"class":334,"line":482},[332,4416,2066],{"class":355},[332,4418,4419],{"class":2057},"my-component",[332,4421,4356],{"class":351},[332,4423,4424],{"class":355}," \u002F>\n",[332,4426,4427],{"class":334,"line":487},[332,4428,418],{"emptyLinePlaceholder":238},[332,4430,4431],{"class":334,"line":496},[332,4432,4433],{"class":338},"  \u003C!-- v-for directives -->\n",[332,4435,4436,4438,4440,4442,4444,4446,4448,4451,4453],{"class":334,"line":2156},[332,4437,2066],{"class":355},[332,4439,628],{"class":2057},[332,4441,2530],{"class":351},[332,4443,440],{"class":355},[332,4445,2535],{"class":551},[332,4447,4356],{"class":351},[332,4449,4450],{"class":355},">{{item}}\u003C\u002F",[332,4452,628],{"class":2057},[332,4454,2061],{"class":355},[332,4456,4457,4459,4461],{"class":334,"line":2162},[332,4458,2112],{"class":355},[332,4460,2058],{"class":2057},[332,4462,2061],{"class":355},[48,4464,4465,4468],{},[67,4466,4467],{},"v-memo;"," Kort sagt bruges v-memo til at memoize et undertræ af templaten — hvilket betyder, at det gemmer resultatet af tidligere renderinger for at fremskynde fremtidige. v-memo direktivet kan bruges på både elementer og komponenter. v-memo tager et array ind og vil kun re-rendere, hvis en af værdierne i arrayet ændrer sig.",[280,4470,4474],{"className":4471,"code":4472,"language":4473,"meta":217,"style":217},"language-html shiki shiki-themes github-dark","\u003Cdiv v-memo=\"[valueA, valueB]\">\n  ...\n\u003C\u002Fdiv>\n","html",[287,4475,4476,4492,4497],{"__ignoreMap":217},[332,4477,4478,4480,4482,4485,4487,4490],{"class":334,"line":335},[332,4479,374],{"class":355},[332,4481,2069],{"class":2057},[332,4483,4484],{"class":351}," v-memo",[332,4486,440],{"class":355},[332,4488,4489],{"class":551},"\"[valueA, valueB]\"",[332,4491,2061],{"class":355},[332,4493,4494],{"class":334,"line":218},[332,4495,4496],{"class":355},"  ...\n",[332,4498,4499,4501,4503],{"class":334,"line":226},[332,4500,2112],{"class":355},[332,4502,2069],{"class":2057},[332,4504,2061],{"class":355},[48,4506,4507,4508,871,4511,4514],{},"Hvis ",[67,4509,4510],{},"valueA",[67,4512,4513],{},"valueB"," ændrer sig, vil det opdatere. Vær dog opmærksom på, at v-memo ikke virker inde i en v-for løkke.",[43,4516,4518],{"id":4517},"asynkron-indlæsning-af-komponenter","Asynkron indlæsning af komponenter",[48,4520,4521,4522,4527],{},"For at gøre din app mere performant og for at minimere dit main bundle, er det en god ide at lazy loade dine komponenter. I Vue 3 kan vi bruge ",[167,4523,4524],{},[67,4525,4526],{},"defineAsyncComponent"," til at lazy loade en komponent. Det betyder, at komponenten først indlæses, når der er brug for den. Ved at bruge denne teknik kan du dramatisk forbedre indlæsningen af din applikation.",[48,4529,4530],{},"Den simpleste måde at definere en async komponent på kan gøres sådan:",[280,4532,4534],{"className":2047,"code":4533,"language":1392,"meta":217,"style":217},"import { defineAsyncComponent } from \"vue\";\n\n\u002F\u002F Lazy Load\nconst myComponent = defineAsyncComponent(() =>\n  import(\".\u002Fcomponents\u002FmyComponent.vue\")\n);\n",[287,4535,4536,4550,4554,4559,4576,4588],{"__ignoreMap":217},[332,4537,4538,4540,4543,4545,4548],{"class":334,"line":335},[332,4539,3051],{"class":344},[332,4541,4542],{"class":355}," { defineAsyncComponent } ",[332,4544,3057],{"class":344},[332,4546,4547],{"class":551}," \"vue\"",[332,4549,2729],{"class":355},[332,4551,4552],{"class":334,"line":218},[332,4553,418],{"emptyLinePlaceholder":238},[332,4555,4556],{"class":334,"line":226},[332,4557,4558],{"class":338},"\u002F\u002F Lazy Load\n",[332,4560,4561,4563,4566,4568,4571,4573],{"class":334,"line":395},[332,4562,530],{"class":344},[332,4564,4565],{"class":364}," myComponent",[332,4567,368],{"class":344},[332,4569,4570],{"class":351}," defineAsyncComponent",[332,4572,2705],{"class":355},[332,4574,4575],{"class":344},"=>\n",[332,4577,4578,4581,4583,4586],{"class":334,"line":415},[332,4579,4580],{"class":344},"  import",[332,4582,407],{"class":355},[332,4584,4585],{"class":551},"\".\u002Fcomponents\u002FmyComponent.vue\"",[332,4587,392],{"class":355},[332,4589,4590],{"class":334,"line":421},[332,4591,2825],{"class":355},[48,4593,4594,4595,791],{},"Hvis du har brug for det, kan du gøre endnu mere ved at sende et objekt til ",[167,4596,4597],{},[67,4598,4526],{},[280,4600,4602],{"className":2047,"code":4601,"language":1392,"meta":217,"style":217},"const myComponent = defineAsyncComponent({\n  loader: () => import(\".\u002FmyComponent.vue\"),\n  loadingComponent: myLoadingComponent \u002F* shows while loading *\u002F,\n  errorComponent: myErrorComponent \u002F* shows if there's an error *\u002F,\n  delay: 1000 \u002F* delay in ms before showing loading component *\u002F,\n  timeout: 3000 \u002F* timeout after this many ms *\u002F,\n});\n",[287,4603,4604,4616,4635,4645,4655,4668,4681],{"__ignoreMap":217},[332,4605,4606,4608,4610,4612,4614],{"class":334,"line":335},[332,4607,530],{"class":344},[332,4609,4565],{"class":364},[332,4611,368],{"class":344},[332,4613,4570],{"class":351},[332,4615,3920],{"class":355},[332,4617,4618,4621,4623,4625,4627,4629,4632],{"class":334,"line":218},[332,4619,4620],{"class":351},"  loader",[332,4622,563],{"class":355},[332,4624,566],{"class":344},[332,4626,569],{"class":344},[332,4628,407],{"class":355},[332,4630,4631],{"class":551},"\".\u002FmyComponent.vue\"",[332,4633,4634],{"class":355},"),\n",[332,4636,4637,4640,4643],{"class":334,"line":226},[332,4638,4639],{"class":355},"  loadingComponent: myLoadingComponent ",[332,4641,4642],{"class":338},"\u002F* shows while loading *\u002F",[332,4644,555],{"class":355},[332,4646,4647,4650,4653],{"class":334,"line":395},[332,4648,4649],{"class":355},"  errorComponent: myErrorComponent ",[332,4651,4652],{"class":338},"\u002F* shows if there's an error *\u002F",[332,4654,555],{"class":355},[332,4656,4657,4660,4663,4666],{"class":334,"line":415},[332,4658,4659],{"class":355},"  delay: ",[332,4661,4662],{"class":364},"1000",[332,4664,4665],{"class":338}," \u002F* delay in ms before showing loading component *\u002F",[332,4667,555],{"class":355},[332,4669,4670,4673,4676,4679],{"class":334,"line":421},[332,4671,4672],{"class":355},"  timeout: ",[332,4674,4675],{"class":364},"3000",[332,4677,4678],{"class":338}," \u002F* timeout after this many ms *\u002F",[332,4680,555],{"class":355},[332,4682,4683],{"class":334,"line":434},[332,4684,2946],{"class":355},[972,4686,4687],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":217,"searchDepth":218,"depth":218,"links":4689},[4690,4691,4692,4693,4694,4695,4696],{"id":3719,"depth":218,"text":3720},{"id":3856,"depth":218,"text":3857},{"id":4117,"depth":218,"text":4118},{"id":4196,"depth":218,"text":4197},{"id":4305,"depth":218,"text":4306},{"id":4319,"depth":218,"text":4320},{"id":4517,"depth":218,"text":4518},"2022-04-02","Bliv en bedre og mere effektiv Vue-udvikler med disse tips og tricks til Vue 3.",{},"\u002Fblog\u002Fvue-3-tips-og-tricks",{"title":3705,"description":4698},"Bliv en bedre og mere effektiv Vue-udvikler med disse tips og tricks til Vue 3. Script setup, reactive CSS, v-memo, async components og mere.","Vue 3 Tips & Tricks - Bliv en bedre Vue-udvikler","vue-3-tips-og-tricks","blog\u002Fvue-3-tips-og-tricks",[997,3015,995],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*s2vCxDgTCjVt8AyAyFIDhw.png","_dC2H-En5B_LdlsX0Jq2eFIcQOEig7rC3OKPh9DtwKA",{"id":4710,"title":4711,"body":4712,"date":5529,"description":5530,"extension":236,"meta":5531,"navigation":238,"noindex":8,"path":5532,"seo":5533,"seoDescription":5534,"seoTitle":4711,"slug":5535,"stem":5536,"tags":5537,"thumbnail":5538,"updated":5529,"__hash__":5539},"blog\u002Fblog\u002Fforbedre-din-kode-med-javascript-features.md","Forbedre din kode: Prøv disse JavaScript features i dag",{"type":40,"value":4713,"toc":5521},[4714,4717,4720,4724,4727,4821,4866,4902,4927,4930,4934,4937,4997,5003,5009,5015,5022,5026,5029,5055,5059,5062,5065,5206,5213,5217,5220,5305,5308,5346,5392,5398,5405,5409,5412,5479,5506,5512,5518],[48,4715,4716],{},"At følge med i de seneste nyheder inden for frontend-verdenen kan være svært. Tingene udvikler sig hurtigt. Nye frameworks, nye biblioteker, nye features og meget mere.",[48,4718,4719],{},"Jeg vil prøve at lave en kort opsamling af nogle af de super fede nye features JavaScript har i ærmet til frontend-udviklere.",[43,4721,4723],{"id":4722},"optional-chaining","Optional Chaining",[48,4725,4726],{},"Optional chaining er en lille, men meget nyttig tilføjelse til sproget. Det gør den kode du skal skrive en smule kortere og renere. Det giver dig basalt set mulighed for at tjekke om værdier eksisterer i et objekt:",[280,4728,4730],{"className":2047,"code":4729,"language":1392,"meta":217,"style":217},"const someObject = {\n  profile: {\n   firstName: 'Nicky',\n    lastName: 'Christensen',\n    country: 'Denmark'\n  }\n}\n\u002F\u002F with optional chaining:\nif (someObject?.profile?.firstName){ \n console.log('Name is 1: ', someObject.profile.firstName)\n}\u002F\u002F navigate object graph safely\n",[287,4731,4732,4743,4748,4758,4768,4776,4780,4784,4789,4797,4813],{"__ignoreMap":217},[332,4733,4734,4736,4739,4741],{"class":334,"line":335},[332,4735,530],{"class":344},[332,4737,4738],{"class":364}," someObject",[332,4740,368],{"class":344},[332,4742,782],{"class":355},[332,4744,4745],{"class":334,"line":218},[332,4746,4747],{"class":355},"  profile: {\n",[332,4749,4750,4753,4756],{"class":334,"line":226},[332,4751,4752],{"class":355},"   firstName: ",[332,4754,4755],{"class":551},"'Nicky'",[332,4757,555],{"class":355},[332,4759,4760,4763,4766],{"class":334,"line":395},[332,4761,4762],{"class":355},"    lastName: ",[332,4764,4765],{"class":551},"'Christensen'",[332,4767,555],{"class":355},[332,4769,4770,4773],{"class":334,"line":415},[332,4771,4772],{"class":355},"    country: ",[332,4774,4775],{"class":551},"'Denmark'\n",[332,4777,4778],{"class":334,"line":421},[332,4779,479],{"class":355},[332,4781,4782],{"class":334,"line":434},[332,4783,499],{"class":355},[332,4785,4786],{"class":334,"line":446},[332,4787,4788],{"class":338},"\u002F\u002F with optional chaining:\n",[332,4790,4791,4794],{"class":334,"line":466},[332,4792,4793],{"class":344},"if",[332,4795,4796],{"class":355}," (someObject?.profile?.firstName){ \n",[332,4798,4799,4802,4805,4807,4810],{"class":334,"line":476},[332,4800,4801],{"class":355}," console.",[332,4803,4804],{"class":351},"log",[332,4806,407],{"class":355},[332,4808,4809],{"class":551},"'Name is 1: '",[332,4811,4812],{"class":355},", someObject.profile.firstName)\n",[332,4814,4815,4818],{"class":334,"line":482},[332,4816,4817],{"class":355},"}",[332,4819,4820],{"class":338},"\u002F\u002F navigate object graph safely\n",[280,4822,4824],{"className":2047,"code":4823,"language":1392,"meta":217,"style":217},"\u002F\u002F old style without optional chaining:\nif (someObject && someObject.profile && someObject.profile.firstName){ \n console.log('Name is 2: ', someObject.profile.firstName)\n}\n",[287,4825,4826,4831,4849,4862],{"__ignoreMap":217},[332,4827,4828],{"class":334,"line":335},[332,4829,4830],{"class":338},"\u002F\u002F old style without optional chaining:\n",[332,4832,4833,4835,4838,4841,4844,4846],{"class":334,"line":218},[332,4834,4793],{"class":344},[332,4836,4837],{"class":355}," (someObject ",[332,4839,4840],{"class":344},"&&",[332,4842,4843],{"class":355}," someObject.profile ",[332,4845,4840],{"class":344},[332,4847,4848],{"class":355}," someObject.profile.firstName){ \n",[332,4850,4851,4853,4855,4857,4860],{"class":334,"line":226},[332,4852,4801],{"class":355},[332,4854,4804],{"class":351},[332,4856,407],{"class":355},[332,4858,4859],{"class":551},"'Name is 2: '",[332,4861,4812],{"class":355},[332,4863,4864],{"class":334,"line":395},[332,4865,499],{"class":355},[280,4867,4869],{"className":2047,"code":4868,"language":1392,"meta":217,"style":217},"\u002F\u002F with optional chaining that fails as name doesnt exist:\nif (someObject?.profile?.name){ \n console.log('Name is 3: ', someObject.profile.firstName)\n}\u002F\u002F navigate object graph safely\n",[287,4870,4871,4876,4883,4896],{"__ignoreMap":217},[332,4872,4873],{"class":334,"line":335},[332,4874,4875],{"class":338},"\u002F\u002F with optional chaining that fails as name doesnt exist:\n",[332,4877,4878,4880],{"class":334,"line":218},[332,4879,4793],{"class":344},[332,4881,4882],{"class":355}," (someObject?.profile?.name){ \n",[332,4884,4885,4887,4889,4891,4894],{"class":334,"line":226},[332,4886,4801],{"class":355},[332,4888,4804],{"class":351},[332,4890,407],{"class":355},[332,4892,4893],{"class":551},"'Name is 3: '",[332,4895,4812],{"class":355},[332,4897,4898,4900],{"class":334,"line":395},[332,4899,4817],{"class":355},[332,4901,4820],{"class":338},[48,4903,4904,4905,1229,4910,4915,4916,4921,4922,1956],{},"Som du kan se, er de eneste to console.logs() der bliver printet ",[167,4906,4907],{},[67,4908,4909],{},"\"Name is 1\"",[167,4911,4912],{},[67,4913,4914],{},"\"Name is 2\"",". Den tredje bliver ikke printet, da ",[167,4917,4918],{},[67,4919,4920],{},"\"name\""," ikke eksisterer på ",[167,4923,4924],{},[67,4925,4926],{},"\"profile\"",[48,4928,4929],{},"Før optional chaining var vi nødt til at gøre som i eksempel 2, hvilket kan være noget besværligt og langt at skrive.",[43,4931,4933],{"id":4932},"nullish-coalescing","Nullish coalescing",[48,4935,4936],{},"I den seneste udgave af ECMAScript kom en ny logisk operator som returnerer sin højresides operand når dens venstresides operand er null eller undefined. Du kan bruge nullish coalescing \"??\" når du skal sætte standardværdier. Ofte når vi gør dette har vi brugt \"||\" operatoren, som du selvfølgelig stadig kan bruge. \"??\" har nogle andre fordele som kan gavne dig når du vil undgå sideeffekter.",[280,4938,4940],{"className":2047,"code":4939,"language":1392,"meta":217,"style":217},"const falsy = false;\nconst emptyString = '';\nconst nullish = null;\nconst uDefined = undefined;\n",[287,4941,4942,4956,4970,4983],{"__ignoreMap":217},[332,4943,4944,4946,4949,4951,4954],{"class":334,"line":335},[332,4945,530],{"class":344},[332,4947,4948],{"class":364}," falsy",[332,4950,368],{"class":344},[332,4952,4953],{"class":364}," false",[332,4955,2729],{"class":355},[332,4957,4958,4960,4963,4965,4968],{"class":334,"line":218},[332,4959,530],{"class":344},[332,4961,4962],{"class":364}," emptyString",[332,4964,368],{"class":344},[332,4966,4967],{"class":551}," ''",[332,4969,2729],{"class":355},[332,4971,4972,4974,4977,4979,4981],{"class":334,"line":226},[332,4973,530],{"class":344},[332,4975,4976],{"class":364}," nullish",[332,4978,368],{"class":344},[332,4980,383],{"class":364},[332,4982,2729],{"class":355},[332,4984,4985,4987,4990,4992,4995],{"class":334,"line":395},[332,4986,530],{"class":344},[332,4988,4989],{"class":364}," uDefined",[332,4991,368],{"class":344},[332,4993,4994],{"class":364}," undefined",[332,4996,2729],{"class":355},[280,4998,5001],{"className":4999,"code":5000,"language":285},[283],"console.log('1', falsy ?? 'Some string');\nconsole.log('2', emptyString ?? 'Default string') \u002F\u002F\"\" (as the empty string is not null or undefined)\nconsole.log('3', nullish ?? 'Default string')\nconsole.log('4', uDefined ?? 'Default string')\n",[287,5002,5000],{"__ignoreMap":217},[280,5004,5007],{"className":5005,"code":5006,"language":285},[283],"console.log('-------');\n",[287,5008,5006],{"__ignoreMap":217},[280,5010,5013],{"className":5011,"code":5012,"language":285},[283],"console.log('1.1', falsy || 'Some string');\nconsole.log('2.2', emptyString || 'Default string')\nconsole.log('3.3', nullish || 'Default string')\nconsole.log('4.4', uDefined || 'Default string')\n",[287,5014,5012],{"__ignoreMap":217},[48,5016,5017,5018],{},"Du kan prøve at lege med det i denne fiddle for at se forskellen mellem || og ?? operatoren: ",[966,5019,5020],{"href":5020,"rel":5021},"https:\u002F\u002Fjsfiddle.net\u002F96b4zw71\u002F",[4114],[43,5023,5025],{"id":5024},"dynamic-imports","Dynamic imports",[48,5027,5028],{},"Den seneste version af ECMAScript introducerer dynamic imports på moduler. Det gør det muligt at indlæse moduler asynkront. Dette er også kendt som code splitting, noget vi har gjort via build tools i årevis.",[280,5030,5032],{"className":2047,"code":5031,"language":1392,"meta":217,"style":217},"let someAsyncModule = await import('\u002Fmodules\u002Fmy-module.ts');\n",[287,5033,5034],{"__ignoreMap":217},[332,5035,5036,5039,5042,5044,5046,5048,5050,5053],{"class":334,"line":335},[332,5037,5038],{"class":344},"let",[332,5040,5041],{"class":355}," someAsyncModule ",[332,5043,440],{"class":344},[332,5045,454],{"class":344},[332,5047,569],{"class":344},[332,5049,407],{"class":355},[332,5051,5052],{"class":551},"'\u002Fmodules\u002Fmy-module.ts'",[332,5054,2825],{"class":355},[43,5056,5058],{"id":5057},"promiseallsettled","Promise.allSettled()",[48,5060,5061],{},"I årevis har vi brugt Promise.all() til at vente på at alle promises bliver resolved. Problemet med Promise.all() har været at vi ikke vidste hvilke promises der faktisk blev resolved og hvilke der fejlede.",[48,5063,5064],{},"Metoden Promise.allSettled() giver dig mulighed for at observere resultaterne af et sæt promises, uanset om de er fulfilled eller rejected, hvilket kan være rigtig nyttigt.",[280,5066,5068],{"className":2047,"code":5067,"language":1392,"meta":217,"style":217},"const promise1 = Promise.resolve(\"OK, I resolved\");\nconst promise2 = Promise.reject(\"OH no, I was rejected\");\nconst promise3 = Promise.resolve(\"After I was rejected\");\nPromise.allSettled([promise1, promise2, promise3])\n    .then((results) => console.log(results))\n    .catch((err) => console.log(\"error: \" + err));\n",[287,5069,5070,5094,5117,5139,5152,5177],{"__ignoreMap":217},[332,5071,5072,5074,5077,5079,5082,5084,5087,5089,5092],{"class":334,"line":335},[332,5073,530],{"class":344},[332,5075,5076],{"class":364}," promise1",[332,5078,368],{"class":344},[332,5080,5081],{"class":364}," Promise",[332,5083,1956],{"class":355},[332,5085,5086],{"class":351},"resolve",[332,5088,407],{"class":355},[332,5090,5091],{"class":551},"\"OK, I resolved\"",[332,5093,2825],{"class":355},[332,5095,5096,5098,5101,5103,5105,5107,5110,5112,5115],{"class":334,"line":218},[332,5097,530],{"class":344},[332,5099,5100],{"class":364}," promise2",[332,5102,368],{"class":344},[332,5104,5081],{"class":364},[332,5106,1956],{"class":355},[332,5108,5109],{"class":351},"reject",[332,5111,407],{"class":355},[332,5113,5114],{"class":551},"\"OH no, I was rejected\"",[332,5116,2825],{"class":355},[332,5118,5119,5121,5124,5126,5128,5130,5132,5134,5137],{"class":334,"line":226},[332,5120,530],{"class":344},[332,5122,5123],{"class":364}," promise3",[332,5125,368],{"class":344},[332,5127,5081],{"class":364},[332,5129,1956],{"class":355},[332,5131,5086],{"class":351},[332,5133,407],{"class":355},[332,5135,5136],{"class":551},"\"After I was rejected\"",[332,5138,2825],{"class":355},[332,5140,5141,5144,5146,5149],{"class":334,"line":395},[332,5142,5143],{"class":364},"Promise",[332,5145,1956],{"class":355},[332,5147,5148],{"class":351},"allSettled",[332,5150,5151],{"class":355},"([promise1, promise2, promise3])\n",[332,5153,5154,5157,5160,5163,5166,5168,5170,5172,5174],{"class":334,"line":415},[332,5155,5156],{"class":355},"    .",[332,5158,5159],{"class":351},"then",[332,5161,5162],{"class":355},"((",[332,5164,5165],{"class":787},"results",[332,5167,4055],{"class":355},[332,5169,566],{"class":344},[332,5171,4801],{"class":355},[332,5173,4804],{"class":351},[332,5175,5176],{"class":355},"(results))\n",[332,5178,5179,5181,5183,5185,5188,5190,5192,5194,5196,5198,5201,5203],{"class":334,"line":421},[332,5180,5156],{"class":355},[332,5182,2854],{"class":351},[332,5184,5162],{"class":355},[332,5186,5187],{"class":787},"err",[332,5189,4055],{"class":355},[332,5191,566],{"class":344},[332,5193,4801],{"class":355},[332,5195,4804],{"class":351},[332,5197,407],{"class":355},[332,5199,5200],{"class":551},"\"error: \"",[332,5202,2877],{"class":344},[332,5204,5205],{"class":355}," err));\n",[48,5207,5208,5209],{},"Tjek denne fiddle for at se hvordan det bruges: ",[966,5210,5211],{"href":5211,"rel":5212},"https:\u002F\u002Fjsfiddle.net\u002Fx2h01z7p\u002F1\u002F",[4114],[43,5214,5216],{"id":5215},"spread-operators","Spread operators",[48,5218,5219],{},"I nogen tid har vi haft adgang til spread operators. Det er særligt nyttigt når du for eksempel vil flette arrays eller objekter sammen. Før spread operators kunne vi bruge array.concat til at flette arrays, nu kan vi gøre det endnu nemmere:",[280,5221,5223],{"className":2047,"code":5222,"language":1392,"meta":217,"style":217},"const arr1 = [1,2,3];\nconst arr2 = [4,5,6];\nconst arr3 = [...arr1, ...arr2] \u002F\u002Farr3 ==> [1,2,3,4,5,6]\n",[287,5224,5225,5254,5280],{"__ignoreMap":217},[332,5226,5227,5229,5232,5234,5237,5240,5243,5246,5248,5251],{"class":334,"line":335},[332,5228,530],{"class":344},[332,5230,5231],{"class":364}," arr1",[332,5233,368],{"class":344},[332,5235,5236],{"class":355}," [",[332,5238,5239],{"class":364},"1",[332,5241,5242],{"class":355},",",[332,5244,5245],{"class":364},"2",[332,5247,5242],{"class":355},[332,5249,5250],{"class":364},"3",[332,5252,5253],{"class":355},"];\n",[332,5255,5256,5258,5261,5263,5265,5268,5270,5273,5275,5278],{"class":334,"line":218},[332,5257,530],{"class":344},[332,5259,5260],{"class":364}," arr2",[332,5262,368],{"class":344},[332,5264,5236],{"class":355},[332,5266,5267],{"class":364},"4",[332,5269,5242],{"class":355},[332,5271,5272],{"class":364},"5",[332,5274,5242],{"class":355},[332,5276,5277],{"class":364},"6",[332,5279,5253],{"class":355},[332,5281,5282,5284,5287,5289,5291,5294,5297,5299,5302],{"class":334,"line":226},[332,5283,530],{"class":344},[332,5285,5286],{"class":364}," arr3",[332,5288,368],{"class":344},[332,5290,5236],{"class":355},[332,5292,5293],{"class":344},"...",[332,5295,5296],{"class":355},"arr1, ",[332,5298,5293],{"class":344},[332,5300,5301],{"class":355},"arr2] ",[332,5303,5304],{"class":338},"\u002F\u002Farr3 ==> [1,2,3,4,5,6]\n",[48,5306,5307],{},"For objekter kan vi gøre:",[280,5309,5311],{"className":2047,"code":5310,"language":1392,"meta":217,"style":217},"const basePerson = {\n name: 'Nicky C',\n  country: 'DK'\n}\n",[287,5312,5313,5324,5334,5342],{"__ignoreMap":217},[332,5314,5315,5317,5320,5322],{"class":334,"line":335},[332,5316,530],{"class":344},[332,5318,5319],{"class":364}," basePerson",[332,5321,368],{"class":344},[332,5323,782],{"class":355},[332,5325,5326,5329,5332],{"class":334,"line":218},[332,5327,5328],{"class":355}," name: ",[332,5330,5331],{"class":551},"'Nicky C'",[332,5333,555],{"class":355},[332,5335,5336,5339],{"class":334,"line":226},[332,5337,5338],{"class":355},"  country: ",[332,5340,5341],{"class":551},"'DK'\n",[332,5343,5344],{"class":334,"line":395},[332,5345,499],{"class":355},[280,5347,5349],{"className":2047,"code":5348,"language":1392,"meta":217,"style":217},"const footballerPerson = {\n ...basePerson,\n  team: 'Man UTD',\n  shirtNumber: '11'\n}\n",[287,5350,5351,5362,5370,5380,5388],{"__ignoreMap":217},[332,5352,5353,5355,5358,5360],{"class":334,"line":335},[332,5354,530],{"class":344},[332,5356,5357],{"class":364}," footballerPerson",[332,5359,368],{"class":344},[332,5361,782],{"class":355},[332,5363,5364,5367],{"class":334,"line":218},[332,5365,5366],{"class":344}," ...",[332,5368,5369],{"class":355},"basePerson,\n",[332,5371,5372,5375,5378],{"class":334,"line":226},[332,5373,5374],{"class":355},"  team: ",[332,5376,5377],{"class":551},"'Man UTD'",[332,5379,555],{"class":355},[332,5381,5382,5385],{"class":334,"line":395},[332,5383,5384],{"class":355},"  shirtNumber: ",[332,5386,5387],{"class":551},"'11'\n",[332,5389,5390],{"class":334,"line":415},[332,5391,499],{"class":355},[280,5393,5396],{"className":5394,"code":5395,"language":285},[283],"console.log(footballerPerson) \u002F\u002FWill output a merge of the two objects\n",[287,5397,5395],{"__ignoreMap":217},[48,5399,5400,5401],{},"Prøv det her: ",[966,5402,5403],{"href":5403,"rel":5404},"https:\u002F\u002Fjsfiddle.net\u002Fs86knh72\u002F",[4114],[43,5406,5408],{"id":5407},"object-destructuring","Object Destructuring",[48,5410,5411],{},"Ved at bruge object destructuring kan du nemt udpakke værdier fra et objekt:",[280,5413,5415],{"className":2047,"code":5414,"language":1392,"meta":217,"style":217},"const basePerson = {\n name: 'Nicky C',\n  country: 'DK'\n}\nconst footballerPerson = {\n ...basePerson,\n  team: 'Man UTD',\n  shirtNumber: '11'\n}\n",[287,5416,5417,5427,5435,5441,5445,5455,5461,5469,5475],{"__ignoreMap":217},[332,5418,5419,5421,5423,5425],{"class":334,"line":335},[332,5420,530],{"class":344},[332,5422,5319],{"class":364},[332,5424,368],{"class":344},[332,5426,782],{"class":355},[332,5428,5429,5431,5433],{"class":334,"line":218},[332,5430,5328],{"class":355},[332,5432,5331],{"class":551},[332,5434,555],{"class":355},[332,5436,5437,5439],{"class":334,"line":226},[332,5438,5338],{"class":355},[332,5440,5341],{"class":551},[332,5442,5443],{"class":334,"line":395},[332,5444,499],{"class":355},[332,5446,5447,5449,5451,5453],{"class":334,"line":415},[332,5448,530],{"class":344},[332,5450,5357],{"class":364},[332,5452,368],{"class":344},[332,5454,782],{"class":355},[332,5456,5457,5459],{"class":334,"line":421},[332,5458,5366],{"class":344},[332,5460,5369],{"class":355},[332,5462,5463,5465,5467],{"class":334,"line":434},[332,5464,5374],{"class":355},[332,5466,5377],{"class":551},[332,5468,555],{"class":355},[332,5470,5471,5473],{"class":334,"line":446},[332,5472,5384],{"class":355},[332,5474,5387],{"class":551},[332,5476,5477],{"class":334,"line":466},[332,5478,499],{"class":355},[280,5480,5482],{"className":2047,"code":5481,"language":1392,"meta":217,"style":217},"const {team, shirtNumber} = footballerPerson;\n",[287,5483,5484],{"__ignoreMap":217},[332,5485,5486,5488,5491,5493,5495,5498,5501,5503],{"class":334,"line":335},[332,5487,530],{"class":344},[332,5489,5490],{"class":355}," {",[332,5492,169],{"class":364},[332,5494,687],{"class":355},[332,5496,5497],{"class":364},"shirtNumber",[332,5499,5500],{"class":355},"} ",[332,5502,440],{"class":344},[332,5504,5505],{"class":355}," footballerPerson;\n",[280,5507,5510],{"className":5508,"code":5509,"language":285},[283],"console.log(team, shirtNumber); \u002F\u002FManUtd, 11\n",[287,5511,5509],{"__ignoreMap":217},[48,5513,5400,5514],{},[966,5515,5516],{"href":5516,"rel":5517},"https:\u002F\u002Fjsfiddle.net\u002F2z3rp18v\u002F",[4114],[972,5519,5520],{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":217,"searchDepth":218,"depth":218,"links":5522},[5523,5524,5525,5526,5527,5528],{"id":4722,"depth":218,"text":4723},{"id":4932,"depth":218,"text":4933},{"id":5024,"depth":218,"text":5025},{"id":5057,"depth":218,"text":5058},{"id":5215,"depth":218,"text":5216},{"id":5407,"depth":218,"text":5408},"2022-02-21","Prøv disse fede nye features og gør din kode endnu bedre. Fra optional chaining til spread operators - her er et overblik over nyttige JavaScript features.",{},"\u002Fblog\u002Fforbedre-din-kode-med-javascript-features",{"title":4711,"description":5530},"Prøv disse fede nye JavaScript features og gør din kode endnu bedre. Optional chaining, nullish coalescing, spread operators og mere.","forbedre-din-kode-med-javascript-features","blog\u002Fforbedre-din-kode-med-javascript-features",[1392,3015,995],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*mmtXU2DtE3qMOuFqACJYEg.png","nKqYxevtIUUY7fxIcXLv4lTkeNP4nCKheWd07xdaMqA",{"id":5541,"title":5542,"body":5543,"date":5738,"description":5739,"extension":236,"meta":5740,"navigation":238,"noindex":8,"path":5741,"seo":5742,"seoDescription":5739,"seoTitle":5542,"slug":5743,"stem":5744,"tags":5745,"thumbnail":5746,"updated":5738,"__hash__":5747},"blog\u002Fblog\u002F7-vaner-for-effektive-udviklere.md","7 vaner for yderst effektive udviklere",{"type":40,"value":5544,"toc":5727},[5545,5554,5557,5560,5563,5566,5569,5573,5576,5580,5583,5591,5594,5597,5601,5604,5610,5613,5618,5624,5640,5646,5649,5652,5655,5658,5664,5667,5670,5679,5683,5686,5693,5697,5700,5703,5706,5709,5712,5718,5724],[48,5546,5547,5548,5553],{},"Har du hørt om bogen ",[966,5549,5552],{"href":5550,"rel":5551},"https:\u002F\u002Fwww.audible.co.uk\u002Fpd\u002FThe-7-Habits-of-Highly-Effective-People-Audiobook\u002F1797115073?source_code=M2M30DFT1Bk13108101801SY&gclid=Cj0KCQiA3rKQBhCNARIsACUEW_amILwPT0vIFPolwoHNfq67EEYMx6DE_T5wZmNHKW_Ocmplz_IslwcaAlk2EALw_wcB&gclsrc=aw.ds",[4114],"The 7 Habits of Highly Effective People","? Det er en bog skrevet af Stephen Covey som handler om produktivitet og selvudvikling. Du lærer mere om nogle vigtige kerneværdier og ideer som du kan udvikle for at løse personlige og professionelle problemer med en integreret og principbaseret tilgang. Hvis du ikke allerede har læst denne bog, opfordrer jeg dig kraftigt til at gøre det.",[48,5555,5556],{},"Jeg tror alle mennesker kan have gavn af positive vaner, men i dag vil jeg prøve at fokusere på hvorfor du som udvikler kan have gavn af positive vaner der gør dig mere effektiv som udvikler og som menneske.",[48,5558,5559],{},"Jeg har været i tech-branchen i omkring 15 år, og jeg ved der er mange meninger om hvad der gør en god udvikler.",[48,5561,5562],{},"Denne artikel handler ikke så meget om at være en god eller fantastisk udvikler, men mere om hvordan du bliver en effektiv udvikler, hvordan du får mest ud af dagen så du kan blive den bedste version af dig selv og få mere fra hånden!",[48,5564,5565],{},"Gennem mine år i branchen har jeg samlet et par ting op om hvad der gør dygtige udviklere yderst effektive.",[48,5567,5568],{},"Lad os se på vanerne.",[43,5570,5572],{"id":5571},"_1-lær-nye-ting","1. Lær nye ting",[48,5574,5575],{},"For at blive en dygtig og effektiv udvikler skal du have fokus på altid at udvikle dine egne færdigheder. Hvis du prokrastinerer, vil du aldrig blive effektiv, og heller ikke dygtig for den sags skyld. Effektive udviklere finder løsninger på problemer med viden. Viden kommer fra erfaring og fra at lære ting, derfor er det essentielt at holde dit sind åbent for læring af nye ting løbende.",[43,5577,5579],{"id":5578},"_2-hav-fokus-på-at-være-sund","2. Hav fokus på at være sund",[48,5581,5582],{},"Jeg er stor fan af denne vane. En god og sund livsstil giver dig et meget klarere sind og en masse mere energi i hverdagen.",[48,5584,5585,5586,1956],{},"Studier viser at en usund livsstil, hvor sund kost og motion IKKE er en del af livet, gør mennesker mere tilbøjelige til hjertesvigt, sårbare over for fedme, lider af træthed, har sværere ved at optage information og generelt er i ",[966,5587,5590],{"href":5588,"rel":5589},"https:\u002F\u002Fwww.ncbi.nlm.nih.gov\u002Fpmc\u002Farticles\u002FPMC4703222\u002F",[4114],"højere risiko for at blive syge",[48,5592,5593],{},"At passe godt på krop og sind med en sund livsstil vil gøre dig mere effektiv og produktiv, ikke kun som udvikler men som menneske generelt.",[48,5595,5596],{},"Tag på en løbetur, tag en svømmer, tag ned i fitnesscenteret, tænk over hvad du spiser. Hvis du ikke er vant til at dyrke motion, kan det være hårdt i begyndelsen, men på lang sigt vil du elske det.",[43,5598,5600],{"id":5599},"_3-har-fokus-på-værdi-ikke-problemer","3. Har fokus på værdi, ikke problemer",[48,5602,5603],{},"Effektive udviklere fokuserer på værdi frem for problemer. Der vil altid være bugs, problemer osv., men at have evnen til og vanen med at prøve at identificere de ting der bringer mest værdi for slutbrugeren vil hjælpe dig med at være mere effektiv. Du er måske ikke den mest effektive til at løse flest bugs, men de der bliver løst, er de bugs der bringer mest værdi for slutbrugeren, hvilket i sidste ende vil blive opfattet som mest effektivt.",[119,5605,5607],{"id":5606},"tag-dette-eksempel",[67,5608,5609],{},"Tag dette eksempel:",[48,5611,5612],{},"En kunde vil have en notifikation når batteriet er drænet. Hvorfor?",[48,5614,5615],{},[3592,5616],{"alt":217,"src":5617},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*RgPyFTiWSLupknGLx7Q1Og.png",[48,5619,5620,5623],{},[67,5621,5622],{},"Løsning",": Notifikationsservice der kan hjælpe med at forhindre at batteriet løber tørt",[48,5625,5626,5627,5630,5631,1229,5636,1956],{},"En god øvelse for at blive bedre til dette er at prøve at bruge ",[67,5628,5629],{},"5 whys"," og inkorporere det i din hverdag. Lær mere om 5 whys ",[966,5632,5635],{"href":5633,"rel":5634},"https:\u002F\u002Fwww.isixsigma.com\u002Ftools-templates\u002Fcause-effect\u002Fdetermine-root-cause-5-whys",[4114],"her",[966,5637,5635],{"href":5638,"rel":5639},"https:\u002F\u002Fkanbanize.com\u002Flean-management\u002Fimprovement\u002F5-whys-analysis-tool",[4114],[43,5641,5643],{"id":5642},"_4-lad-være-med-at-over-engineere",[67,5644,5645],{},"4. Lad være med at over-engineere",[48,5647,5648],{},"Effektive udviklere og mennesker ved hvornår de skal anvende hvilken metode på X problem. De prøver altid at forenkle tingene så de er så forståelige som muligt og ender ikke med at over-engineere en løsning.",[48,5650,5651],{},"Gode og effektive projekter er dem med forenklede implementeringer, nemme at vedligeholde, nemme at forstå.",[48,5653,5654],{},"Et komplekst design der er over-engineered vil med stor sandsynlighed føre til vanskeligheder med at implementere ny funktionalitet. Det gør vedligeholdelse til et mareridt og forvandler tilsyneladende simpel kode til et kaos af kompleksitet.",[48,5656,5657],{},"For at undgå dette, prøv at lade være med at skrive unødvendig kode og prøv altid at finde simple og elegante løsninger. Det vil gøre dig mere effektiv og produktiv.",[43,5659,5661],{"id":5660},"_5-omgiv-dig-med-kloge-mennesker",[67,5662,5663],{},"5. Omgiv dig med kloge mennesker",[48,5665,5666],{},"Denne vane er bestemt ikke kun begrænset til udviklere, men alle effektive mennesker generelt. Hvis du vil være effektiv og dygtig, er du nødt til at omgive dig med kloge mennesker. Se dig omkring i det rum du er i lige nu. Har du en mistanke om at du er den klogeste person i det? Hvis ja, så find et andet rum. Det vil ændre dit liv.",[48,5668,5669],{},"At omgive dig med kloge mennesker vil gøre dig klogere. De gør dig bedre. De vækker interesse og introducerer dig til nye koncepter, ideer, kultur, mennesker og meget mere. Kort sagt, de ved hvor de gode ting er, eller hvordan man finder dem.",[48,5671,5672,5673,5678],{},"Hvis du ikke ved hvor du skal starte med dette, anbefaler jeg at du læser ",[966,5674,5677],{"href":5675,"rel":5676},"https:\u002F\u002Fmedium.com\u002Fthe-mission\u002Fhow-do-i-surround-myself-with-people-who-are-smarter-than-me-d26f9f25d12d",[4114],"denne"," artikel af Leonard Kim.",[43,5680,5682],{"id":5681},"_6-vær-proaktiv","6. Vær proaktiv",[48,5684,5685],{},"Effektive udviklere prøver altid at være proaktive. En god ide er at prøve at blive bedre til at fokusere på det der er inden for din kontrol, frem for det du ikke kan kontrollere. Tag en proaktiv tilgang til tingene, og gør andre opmærksomme. Læg en indsats og brug den nødvendige energi på at blive bedre til dette.",[48,5687,5688,5689,5692],{},"Et eksempel på at være proaktiv kunne være følgende: ",[67,5690,5691],{},"Tag ansvar for gode krav"," — Giv ikke andre skylden for dårlige krav. Arbejd i stedet sammen med teamet om at analysere kravene grundigt for at sikre de er komplette, præcise og opfylder kundens behov. Tag det ansvar der kræves af dig, og hjælp andre. Hvis du gør dette, vil du og menneskerne omkring dig blive mere effektive.",[43,5694,5696],{"id":5695},"_7-prioriter-arbejdet","7. Prioriter arbejdet",[48,5698,5699],{},"At prioritere arbejde og arbejdsindsats er afgørende. Du skal prioritere det arbejde der giver høj forretningsværdi. Det er den ideelle situation, ikke? Effektive mennesker er gode til dette, at vide hvilke features der giver højest forretningsværdi, men kan gøres med lav\u002Fminimal indsats (Tid vs Forretningsværdi).",[48,5701,5702],{},"Du skal lægge din indsats i de vigtigste ting først, efterfulgt af mindre vigtige ting. For eksempel vil alle generelt være enige om at det er vigtigt at skabe genbrugelig og let vedligeholdelig kode. Men i et forsøg på at gøre dette har udviklere en tendens til at \"forgylde\u002Fover-engineere\". \"Forgylding eller over-engineering\" er når en udvikler tilføjer ekstra funktionalitet til en feature som ikke blev bedt om, og som nemt kan øge kompleksiteten og de estimerede timer der skal til for at levere arbejdet. Vær meget forsigtig med dette. Det tilføjer ikke den nødvendige værdi i forhold til den tid der bruges.",[48,5704,5705],{},"Var det en god investering at lave de ekstra ting? Sandsynligvis ikke. Du er nødt til at blive god til at prioritere arbejde, og også kende konceptet forretningsværdi vs brugt tid.",[48,5707,5708],{},"At have gode vaner i din hverdag kan være meget kraftfuldt. Det vil gavne ikke kun dig men alle omkring dig. Jeg tror virkelig på at det at inkorporere gode vaner vil gøre dig mere effektiv. Det vil hjælpe dig med at excellere som person og som udvikler.",[48,5710,5711],{},"Som Stephen Covey siger i sin bog:",[5713,5714,5715],"blockquote",{},[48,5716,5717],{},"\"Jeg er ikke et produkt af mine omstændigheder. Jeg er et produkt af mine beslutninger.\"",[48,5719,5720,5723],{},[67,5721,5722],{},"Start i dag. Prøv at udfordre dig selv fra i dag, begynd at praktisere disse vaner."," Det vil være hårdt, men det er det værd. Det er jeg sikker på. Kig tilbage om et år og se selv hvor meget du har udviklet dig som person.",[48,5725,5726],{},"Jeg ville elske at høre dine tanker, og om du har nogle værdifulde vaner der får dig til at føle dig som en effektiv udvikler? Del din kommentar herunder. Hvis du kan lide denne artikel, så del den gerne videre med dine venner og kollegaer.",{"title":217,"searchDepth":218,"depth":218,"links":5728},[5729,5730,5731,5734,5735,5736,5737],{"id":5571,"depth":218,"text":5572},{"id":5578,"depth":218,"text":5579},{"id":5599,"depth":218,"text":5600,"children":5732},[5733],{"id":5606,"depth":226,"text":5609},{"id":5642,"depth":218,"text":5645},{"id":5660,"depth":218,"text":5663},{"id":5681,"depth":218,"text":5682},{"id":5695,"depth":218,"text":5696},"2022-02-17","Praktiske råd til at blive en mere effektiv og produktiv udvikler. Lær de vaner der adskiller gode udviklere fra de bedste.",{},"\u002Fblog\u002F7-vaner-for-effektive-udviklere",{"title":5542,"description":5739},"7-vaner-for-effektive-udviklere","blog\u002F7-vaner-for-effektive-udviklere",[246,2441],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*jWjR55KRAh1glAAdeG9Uzg.jpeg","alf88JqeUjs3Zp0Z7yHcNAq9VcfspbfEr4HlzzwwVzw",{"id":5749,"title":5750,"body":5751,"date":8186,"description":8187,"extension":236,"meta":8188,"navigation":238,"noindex":8,"path":8189,"seo":8190,"seoDescription":8191,"seoTitle":8192,"slug":8193,"stem":8194,"tags":8195,"thumbnail":8197,"updated":234,"__hash__":8198},"blog\u002Fblog\u002Fvuejs-tips-and-best-practices.md","Vue 3 Tips & Best Practices i 2026",{"type":40,"value":5752,"toc":8164},[5753,5756,5760,5770,5926,5939,5943,5950,6039,6166,6169,6242,6246,6253,6370,6373,6377,6380,6473,6476,6480,6483,6667,6759,6762,6784,6788,6791,7048,7055,7059,7062,7335,7342,7346,7350,7357,7456,7460,7465,7598,7602,7605,7723,7727,7731,7734,7810,7817,7820,7883,7887,7897,8014,8018,8021,8140,8142,8152,8154,8161],[48,5754,5755],{},"Vue 3 har udviklet sig enormt siden de første releases. Med Vue 3.4 og 3.5 har vi fået en række nye features, der gør det nemmere og mere elegant at bygge moderne webapplikationer. I denne artikel deler jeg mine bedste tips og best practices baseret på 19+ års erfaring med frontend-udvikling.",[43,5757,5759],{"id":5758},"script-setup-er-standarden","Script Setup er standarden",[48,5761,5762,5763,5766,5767,5769],{},"Hvis du stadig bruger Options API eller den lange ",[287,5764,5765],{},"setup()"," funktion, er det tid til at skifte. ",[287,5768,3815],{}," er den anbefalede måde at skrive Vue 3 komponenter på. Det giver dig renere kode, bedre TypeScript-understøttelse og automatisk eksponering af variabler til din template.",[280,5771,5773],{"className":2460,"code":5772,"language":997,"meta":217,"style":217},"\u003Cscript setup lang=\"ts\">\nimport { ref, computed } from 'vue'\n\nconst count = ref(0)\nconst doubled = computed(() => count.value * 2)\n\nfunction increment() {\n  count.value++\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"increment\">\n    Count: {{ count }} (doubled: {{ doubled }})\n  \u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n",[287,5774,5775,5791,5801,5805,5821,5844,5848,5857,5864,5868,5876,5880,5888,5905,5910,5918],{"__ignoreMap":217},[332,5776,5777,5779,5781,5783,5785,5787,5789],{"class":334,"line":335},[332,5778,374],{"class":355},[332,5780,2127],{"class":2057},[332,5782,3838],{"class":351},[332,5784,2611],{"class":351},[332,5786,440],{"class":355},[332,5788,2616],{"class":551},[332,5790,2061],{"class":355},[332,5792,5793,5795,5797,5799],{"class":334,"line":218},[332,5794,3051],{"class":344},[332,5796,3054],{"class":355},[332,5798,3057],{"class":344},[332,5800,3060],{"class":551},[332,5802,5803],{"class":334,"line":226},[332,5804,418],{"emptyLinePlaceholder":238},[332,5806,5807,5809,5811,5813,5815,5817,5819],{"class":334,"line":395},[332,5808,530],{"class":344},[332,5810,3087],{"class":364},[332,5812,368],{"class":344},[332,5814,371],{"class":351},[332,5816,407],{"class":355},[332,5818,3096],{"class":364},[332,5820,392],{"class":355},[332,5822,5823,5825,5828,5830,5832,5834,5836,5838,5840,5842],{"class":334,"line":415},[332,5824,530],{"class":344},[332,5826,5827],{"class":364}," doubled",[332,5829,368],{"class":344},[332,5831,2702],{"class":351},[332,5833,2705],{"class":355},[332,5835,566],{"class":344},[332,5837,3116],{"class":355},[332,5839,3119],{"class":344},[332,5841,3122],{"class":364},[332,5843,392],{"class":355},[332,5845,5846],{"class":334,"line":421},[332,5847,418],{"emptyLinePlaceholder":238},[332,5849,5850,5853,5855],{"class":334,"line":434},[332,5851,5852],{"class":344},"function",[332,5854,3136],{"class":351},[332,5856,356],{"class":355},[332,5858,5859,5862],{"class":334,"line":446},[332,5860,5861],{"class":355},"  count.value",[332,5863,3146],{"class":344},[332,5865,5866],{"class":334,"line":466},[332,5867,499],{"class":355},[332,5869,5870,5872,5874],{"class":334,"line":476},[332,5871,2112],{"class":355},[332,5873,2127],{"class":2057},[332,5875,2061],{"class":355},[332,5877,5878],{"class":334,"line":482},[332,5879,418],{"emptyLinePlaceholder":238},[332,5881,5882,5884,5886],{"class":334,"line":487},[332,5883,374],{"class":355},[332,5885,2058],{"class":2057},[332,5887,2061],{"class":355},[332,5889,5890,5892,5895,5898,5900,5903],{"class":334,"line":496},[332,5891,2066],{"class":355},[332,5893,5894],{"class":2057},"button",[332,5896,5897],{"class":351}," @click",[332,5899,440],{"class":355},[332,5901,5902],{"class":551},"\"increment\"",[332,5904,2061],{"class":355},[332,5906,5907],{"class":334,"line":2156},[332,5908,5909],{"class":355},"    Count: {{ count }} (doubled: {{ doubled }})\n",[332,5911,5912,5914,5916],{"class":334,"line":2162},[332,5913,2103],{"class":355},[332,5915,5894],{"class":2057},[332,5917,2061],{"class":355},[332,5919,5920,5922,5924],{"class":334,"line":2173},[332,5921,2112],{"class":355},[332,5923,2058],{"class":2057},[332,5925,2061],{"class":355},[48,5927,5928,5929,5931,5932,5935,5936,5938],{},"Alt der er deklareret i ",[287,5930,3815],{}," er automatisk tilgængeligt i din template. Ingen ",[287,5933,5934],{},"return","-statement, ingen ",[287,5937,3726],{}," wrapper. Rent og enkelt.",[43,5940,5942],{"id":5941},"definemodel-to-vejs-binding-gjort-nemt-vue-34","defineModel - to-vejs binding gjort nemt (Vue 3.4+)",[48,5944,5945,5946,5949],{},"En af de bedste tilføjelser i Vue 3.4 er ",[287,5947,5948],{},"defineModel()",". Før skulle du manuelt håndtere props og emits for v-model bindings. Nu er det en one-liner:",[280,5951,5953],{"className":2460,"code":5952,"language":997,"meta":217,"style":217},"\u003C!-- ChildInput.vue -->\n\u003Cscript setup lang=\"ts\">\nconst modelValue = defineModel\u003Cstring>()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput v-model=\"modelValue\" \u002F>\n\u003C\u002Ftemplate>\n",[287,5954,5955,5960,5976,5995,6003,6007,6015,6031],{"__ignoreMap":217},[332,5956,5957],{"class":334,"line":335},[332,5958,5959],{"class":338},"\u003C!-- ChildInput.vue -->\n",[332,5961,5962,5964,5966,5968,5970,5972,5974],{"class":334,"line":218},[332,5963,374],{"class":355},[332,5965,2127],{"class":2057},[332,5967,3838],{"class":351},[332,5969,2611],{"class":351},[332,5971,440],{"class":355},[332,5973,2616],{"class":551},[332,5975,2061],{"class":355},[332,5977,5978,5980,5983,5985,5988,5990,5992],{"class":334,"line":226},[332,5979,530],{"class":344},[332,5981,5982],{"class":364}," modelValue",[332,5984,368],{"class":344},[332,5986,5987],{"class":351}," defineModel",[332,5989,374],{"class":355},[332,5991,866],{"class":364},[332,5993,5994],{"class":355},">()\n",[332,5996,5997,5999,6001],{"class":334,"line":395},[332,5998,2112],{"class":355},[332,6000,2127],{"class":2057},[332,6002,2061],{"class":355},[332,6004,6005],{"class":334,"line":415},[332,6006,418],{"emptyLinePlaceholder":238},[332,6008,6009,6011,6013],{"class":334,"line":421},[332,6010,374],{"class":355},[332,6012,2058],{"class":2057},[332,6014,2061],{"class":355},[332,6016,6017,6019,6021,6024,6026,6029],{"class":334,"line":434},[332,6018,2066],{"class":355},[332,6020,1894],{"class":2057},[332,6022,6023],{"class":351}," v-model",[332,6025,440],{"class":355},[332,6027,6028],{"class":551},"\"modelValue\"",[332,6030,4424],{"class":355},[332,6032,6033,6035,6037],{"class":334,"line":446},[332,6034,2112],{"class":355},[332,6036,2058],{"class":2057},[332,6038,2061],{"class":355},[280,6040,6042],{"className":2460,"code":6041,"language":997,"meta":217,"style":217},"\u003C!-- ParentForm.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { ref } from 'vue'\nimport ChildInput from '.\u002FChildInput.vue'\n\nconst name = ref('')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CChildInput v-model=\"name\" \u002F>\n  \u003Cp>Du skrev: {{ name }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n",[287,6043,6044,6049,6065,6076,6088,6092,6110,6118,6122,6130,6145,6158],{"__ignoreMap":217},[332,6045,6046],{"class":334,"line":335},[332,6047,6048],{"class":338},"\u003C!-- ParentForm.vue -->\n",[332,6050,6051,6053,6055,6057,6059,6061,6063],{"class":334,"line":218},[332,6052,374],{"class":355},[332,6054,2127],{"class":2057},[332,6056,3838],{"class":351},[332,6058,2611],{"class":351},[332,6060,440],{"class":355},[332,6062,2616],{"class":551},[332,6064,2061],{"class":355},[332,6066,6067,6069,6072,6074],{"class":334,"line":226},[332,6068,3051],{"class":344},[332,6070,6071],{"class":355}," { ref } ",[332,6073,3057],{"class":344},[332,6075,3060],{"class":551},[332,6077,6078,6080,6083,6085],{"class":334,"line":395},[332,6079,3051],{"class":344},[332,6081,6082],{"class":355}," ChildInput ",[332,6084,3057],{"class":344},[332,6086,6087],{"class":551}," '.\u002FChildInput.vue'\n",[332,6089,6090],{"class":334,"line":415},[332,6091,418],{"emptyLinePlaceholder":238},[332,6093,6094,6096,6099,6101,6103,6105,6108],{"class":334,"line":421},[332,6095,530],{"class":344},[332,6097,6098],{"class":364}," name",[332,6100,368],{"class":344},[332,6102,371],{"class":351},[332,6104,407],{"class":355},[332,6106,6107],{"class":551},"''",[332,6109,392],{"class":355},[332,6111,6112,6114,6116],{"class":334,"line":434},[332,6113,2112],{"class":355},[332,6115,2127],{"class":2057},[332,6117,2061],{"class":355},[332,6119,6120],{"class":334,"line":446},[332,6121,418],{"emptyLinePlaceholder":238},[332,6123,6124,6126,6128],{"class":334,"line":466},[332,6125,374],{"class":355},[332,6127,2058],{"class":2057},[332,6129,2061],{"class":355},[332,6131,6132,6134,6137,6139,6141,6143],{"class":334,"line":476},[332,6133,2066],{"class":355},[332,6135,6136],{"class":2057},"ChildInput",[332,6138,6023],{"class":351},[332,6140,440],{"class":355},[332,6142,4920],{"class":551},[332,6144,4424],{"class":355},[332,6146,6147,6149,6151,6154,6156],{"class":334,"line":482},[332,6148,2066],{"class":355},[332,6150,48],{"class":2057},[332,6152,6153],{"class":355},">Du skrev: {{ name }}\u003C\u002F",[332,6155,48],{"class":2057},[332,6157,2061],{"class":355},[332,6159,6160,6162,6164],{"class":334,"line":487},[332,6161,2112],{"class":355},[332,6163,2058],{"class":2057},[332,6165,2061],{"class":355},[48,6167,6168],{},"Du kan også bruge navngivne models og flere models på samme komponent:",[280,6170,6172],{"className":2460,"code":6171,"language":997,"meta":217,"style":217},"\u003Cscript setup lang=\"ts\">\nconst firstName = defineModel\u003Cstring>('firstName')\nconst lastName = defineModel\u003Cstring>('lastName')\n\u003C\u002Fscript>\n",[287,6173,6174,6190,6212,6234],{"__ignoreMap":217},[332,6175,6176,6178,6180,6182,6184,6186,6188],{"class":334,"line":335},[332,6177,374],{"class":355},[332,6179,2127],{"class":2057},[332,6181,3838],{"class":351},[332,6183,2611],{"class":351},[332,6185,440],{"class":355},[332,6187,2616],{"class":551},[332,6189,2061],{"class":355},[332,6191,6192,6194,6197,6199,6201,6203,6205,6207,6210],{"class":334,"line":218},[332,6193,530],{"class":344},[332,6195,6196],{"class":364}," firstName",[332,6198,368],{"class":344},[332,6200,5987],{"class":351},[332,6202,374],{"class":355},[332,6204,866],{"class":364},[332,6206,386],{"class":355},[332,6208,6209],{"class":551},"'firstName'",[332,6211,392],{"class":355},[332,6213,6214,6216,6219,6221,6223,6225,6227,6229,6232],{"class":334,"line":226},[332,6215,530],{"class":344},[332,6217,6218],{"class":364}," lastName",[332,6220,368],{"class":344},[332,6222,5987],{"class":351},[332,6224,374],{"class":355},[332,6226,866],{"class":364},[332,6228,386],{"class":355},[332,6230,6231],{"class":551},"'lastName'",[332,6233,392],{"class":355},[332,6235,6236,6238,6240],{"class":334,"line":395},[332,6237,2112],{"class":355},[332,6239,2127],{"class":2057},[332,6241,2061],{"class":355},[43,6243,6245],{"id":6244},"defineslots-typesikre-slots-vue-33","defineSlots - typesikre slots (Vue 3.3+)",[48,6247,6248,6249,6252],{},"Med ",[287,6250,6251],{},"defineSlots()"," kan du definere typer for dine slots, hvilket giver fuld TypeScript-understøttelse og autocompletion:",[280,6254,6256],{"className":2460,"code":6255,"language":997,"meta":217,"style":217},"\u003Cscript setup lang=\"ts\">\nconst slots = defineSlots\u003C{\n  default(props: { item: string; index: number }): any\n  header(props: { title: string }): any\n}>()\n\u003C\u002Fscript>\n",[287,6257,6258,6274,6289,6331,6357,6362],{"__ignoreMap":217},[332,6259,6260,6262,6264,6266,6268,6270,6272],{"class":334,"line":335},[332,6261,374],{"class":355},[332,6263,2127],{"class":2057},[332,6265,3838],{"class":351},[332,6267,2611],{"class":351},[332,6269,440],{"class":355},[332,6271,2616],{"class":551},[332,6273,2061],{"class":355},[332,6275,6276,6278,6281,6283,6286],{"class":334,"line":218},[332,6277,530],{"class":344},[332,6279,6280],{"class":364}," slots",[332,6282,368],{"class":344},[332,6284,6285],{"class":351}," defineSlots",[332,6287,6288],{"class":355},"\u003C{\n",[332,6290,6291,6294,6296,6299,6301,6304,6307,6309,6312,6315,6318,6320,6323,6326,6328],{"class":334,"line":226},[332,6292,6293],{"class":351},"  default",[332,6295,407],{"class":355},[332,6297,6298],{"class":787},"props",[332,6300,791],{"class":344},[332,6302,6303],{"class":355}," { ",[332,6305,6306],{"class":787},"item",[332,6308,791],{"class":344},[332,6310,6311],{"class":364}," string",[332,6313,6314],{"class":355},"; ",[332,6316,6317],{"class":787},"index",[332,6319,791],{"class":344},[332,6321,6322],{"class":364}," number",[332,6324,6325],{"class":355}," })",[332,6327,791],{"class":344},[332,6329,6330],{"class":364}," any\n",[332,6332,6333,6336,6338,6340,6342,6344,6347,6349,6351,6353,6355],{"class":334,"line":395},[332,6334,6335],{"class":351},"  header",[332,6337,407],{"class":355},[332,6339,6298],{"class":787},[332,6341,791],{"class":344},[332,6343,6303],{"class":355},[332,6345,6346],{"class":787},"title",[332,6348,791],{"class":344},[332,6350,6311],{"class":364},[332,6352,6325],{"class":355},[332,6354,791],{"class":344},[332,6356,6330],{"class":364},[332,6358,6359],{"class":334,"line":415},[332,6360,6361],{"class":355},"}>()\n",[332,6363,6364,6366,6368],{"class":334,"line":421},[332,6365,2112],{"class":355},[332,6367,2127],{"class":2057},[332,6369,2061],{"class":355},[48,6371,6372],{},"Det er særligt nyttigt når du bygger genbrugelige komponenter, hvor andre udviklere skal vide præcis hvilke slot props der er tilgængelige.",[43,6374,6376],{"id":6375},"reactive-destructuring-vue-35","Reactive Destructuring (Vue 3.5+)",[48,6378,6379],{},"Vue 3.5 introducerede reactive destructuring af props - en feature mange har ventet på. Før mistede du reaktiviteten, når du destructurede props. Nu virker det bare:",[280,6381,6383],{"className":2460,"code":6382,"language":997,"meta":217,"style":217},"\u003Cscript setup lang=\"ts\">\nconst { title, count = 0 } = defineProps\u003C{\n  title: string\n  count?: number\n}>()\n\n\u002F\u002F title og count er stadig reaktive!\n\u002F\u002F Du kan bruge dem direkte i computed, watch, etc.\n\u003C\u002Fscript>\n",[287,6384,6385,6401,6427,6436,6447,6451,6455,6460,6465],{"__ignoreMap":217},[332,6386,6387,6389,6391,6393,6395,6397,6399],{"class":334,"line":335},[332,6388,374],{"class":355},[332,6390,2127],{"class":2057},[332,6392,3838],{"class":351},[332,6394,2611],{"class":351},[332,6396,440],{"class":355},[332,6398,2616],{"class":551},[332,6400,2061],{"class":355},[332,6402,6403,6405,6407,6409,6411,6413,6415,6417,6420,6422,6425],{"class":334,"line":218},[332,6404,530],{"class":344},[332,6406,6303],{"class":355},[332,6408,6346],{"class":364},[332,6410,687],{"class":355},[332,6412,3199],{"class":364},[332,6414,368],{"class":344},[332,6416,2726],{"class":364},[332,6418,6419],{"class":355}," } ",[332,6421,440],{"class":344},[332,6423,6424],{"class":351}," defineProps",[332,6426,6288],{"class":355},[332,6428,6429,6432,6434],{"class":334,"line":226},[332,6430,6431],{"class":787},"  title",[332,6433,791],{"class":344},[332,6435,794],{"class":364},[332,6437,6438,6441,6444],{"class":334,"line":395},[332,6439,6440],{"class":787},"  count",[332,6442,6443],{"class":344},"?:",[332,6445,6446],{"class":364}," number\n",[332,6448,6449],{"class":334,"line":415},[332,6450,6361],{"class":355},[332,6452,6453],{"class":334,"line":421},[332,6454,418],{"emptyLinePlaceholder":238},[332,6456,6457],{"class":334,"line":434},[332,6458,6459],{"class":338},"\u002F\u002F title og count er stadig reaktive!\n",[332,6461,6462],{"class":334,"line":446},[332,6463,6464],{"class":338},"\u002F\u002F Du kan bruge dem direkte i computed, watch, etc.\n",[332,6466,6467,6469,6471],{"class":334,"line":466},[332,6468,2112],{"class":355},[332,6470,2127],{"class":2057},[332,6472,2061],{"class":355},[48,6474,6475],{},"Det gør koden mere læsbar og giver dig mulighed for at sætte default-værdier direkte i destructuring.",[43,6477,6479],{"id":6478},"composables-den-rigtige-måde-at-genbruge-logik","Composables - den rigtige måde at genbruge logik",[48,6481,6482],{},"Composables har fuldstændig erstattet mixins i Vue 3. De er nemmere at teste, har bedre TypeScript-support og undgår navnekollisioner. Her er et praktisk eksempel:",[280,6484,6486],{"className":326,"code":6485,"language":328,"meta":217,"style":217},"\u002F\u002F composables\u002FuseLocalStorage.ts\nimport { ref, watch } from 'vue'\n\nexport function useLocalStorage\u003CT>(key: string, defaultValue: T) {\n  const stored = localStorage.getItem(key)\n  const data = ref\u003CT>(stored ? JSON.parse(stored) : defaultValue)\n\n  watch(data, (newValue) => {\n    localStorage.setItem(key, JSON.stringify(newValue))\n  }, { deep: true })\n\n  return data\n}\n",[287,6487,6488,6493,6504,6508,6544,6562,6599,6603,6620,6642,6652,6656,6663],{"__ignoreMap":217},[332,6489,6490],{"class":334,"line":335},[332,6491,6492],{"class":338},"\u002F\u002F composables\u002FuseLocalStorage.ts\n",[332,6494,6495,6497,6500,6502],{"class":334,"line":218},[332,6496,3051],{"class":344},[332,6498,6499],{"class":355}," { ref, watch } ",[332,6501,3057],{"class":344},[332,6503,3060],{"class":551},[332,6505,6506],{"class":334,"line":226},[332,6507,418],{"emptyLinePlaceholder":238},[332,6509,6510,6512,6514,6517,6519,6522,6524,6527,6529,6531,6533,6536,6538,6541],{"class":334,"line":395},[332,6511,345],{"class":344},[332,6513,348],{"class":344},[332,6515,6516],{"class":351}," useLocalStorage",[332,6518,374],{"class":355},[332,6520,6521],{"class":351},"T",[332,6523,386],{"class":355},[332,6525,6526],{"class":787},"key",[332,6528,791],{"class":344},[332,6530,6311],{"class":364},[332,6532,687],{"class":355},[332,6534,6535],{"class":787},"defaultValue",[332,6537,791],{"class":344},[332,6539,6540],{"class":351}," T",[332,6542,6543],{"class":355},") {\n",[332,6545,6546,6548,6551,6553,6556,6559],{"class":334,"line":415},[332,6547,361],{"class":344},[332,6549,6550],{"class":364}," stored",[332,6552,368],{"class":344},[332,6554,6555],{"class":355}," localStorage.",[332,6557,6558],{"class":351},"getItem",[332,6560,6561],{"class":355},"(key)\n",[332,6563,6564,6566,6569,6571,6573,6575,6577,6580,6583,6586,6588,6591,6594,6596],{"class":334,"line":421},[332,6565,361],{"class":344},[332,6567,6568],{"class":364}," data",[332,6570,368],{"class":344},[332,6572,371],{"class":351},[332,6574,374],{"class":355},[332,6576,6521],{"class":351},[332,6578,6579],{"class":355},">(stored ",[332,6581,6582],{"class":344},"?",[332,6584,6585],{"class":364}," JSON",[332,6587,1956],{"class":355},[332,6589,6590],{"class":351},"parse",[332,6592,6593],{"class":355},"(stored) ",[332,6595,791],{"class":344},[332,6597,6598],{"class":355}," defaultValue)\n",[332,6600,6601],{"class":334,"line":434},[332,6602,418],{"emptyLinePlaceholder":238},[332,6604,6605,6608,6611,6614,6616,6618],{"class":334,"line":446},[332,6606,6607],{"class":351},"  watch",[332,6609,6610],{"class":355},"(data, (",[332,6612,6613],{"class":787},"newValue",[332,6615,4055],{"class":355},[332,6617,566],{"class":344},[332,6619,782],{"class":355},[332,6621,6622,6625,6628,6631,6634,6636,6639],{"class":334,"line":466},[332,6623,6624],{"class":355},"    localStorage.",[332,6626,6627],{"class":351},"setItem",[332,6629,6630],{"class":355},"(key, ",[332,6632,6633],{"class":364},"JSON",[332,6635,1956],{"class":355},[332,6637,6638],{"class":351},"stringify",[332,6640,6641],{"class":355},"(newValue))\n",[332,6643,6644,6647,6649],{"class":334,"line":476},[332,6645,6646],{"class":355},"  }, { deep: ",[332,6648,2168],{"class":364},[332,6650,6651],{"class":355}," })\n",[332,6653,6654],{"class":334,"line":482},[332,6655,418],{"emptyLinePlaceholder":238},[332,6657,6658,6660],{"class":334,"line":487},[332,6659,490],{"class":344},[332,6661,6662],{"class":355}," data\n",[332,6664,6665],{"class":334,"line":496},[332,6666,499],{"class":355},[280,6668,6670],{"className":2460,"code":6669,"language":997,"meta":217,"style":217},"\u003Cscript setup lang=\"ts\">\nimport { useLocalStorage } from '@\u002Fcomposables\u002FuseLocalStorage'\n\nconst theme = useLocalStorage('theme', 'light')\nconst favorites = useLocalStorage\u003Cstring[]>('favorites', [])\n\u003C\u002Fscript>\n",[287,6671,6672,6688,6700,6704,6727,6751],{"__ignoreMap":217},[332,6673,6674,6676,6678,6680,6682,6684,6686],{"class":334,"line":335},[332,6675,374],{"class":355},[332,6677,2127],{"class":2057},[332,6679,3838],{"class":351},[332,6681,2611],{"class":351},[332,6683,440],{"class":355},[332,6685,2616],{"class":551},[332,6687,2061],{"class":355},[332,6689,6690,6692,6695,6697],{"class":334,"line":218},[332,6691,3051],{"class":344},[332,6693,6694],{"class":355}," { useLocalStorage } ",[332,6696,3057],{"class":344},[332,6698,6699],{"class":551}," '@\u002Fcomposables\u002FuseLocalStorage'\n",[332,6701,6702],{"class":334,"line":226},[332,6703,418],{"emptyLinePlaceholder":238},[332,6705,6706,6708,6711,6713,6715,6717,6720,6722,6725],{"class":334,"line":395},[332,6707,530],{"class":344},[332,6709,6710],{"class":364}," theme",[332,6712,368],{"class":344},[332,6714,6516],{"class":351},[332,6716,407],{"class":355},[332,6718,6719],{"class":551},"'theme'",[332,6721,687],{"class":355},[332,6723,6724],{"class":551},"'light'",[332,6726,392],{"class":355},[332,6728,6729,6731,6734,6736,6738,6740,6742,6745,6748],{"class":334,"line":415},[332,6730,530],{"class":344},[332,6732,6733],{"class":364}," favorites",[332,6735,368],{"class":344},[332,6737,6516],{"class":351},[332,6739,374],{"class":355},[332,6741,866],{"class":364},[332,6743,6744],{"class":355},"[]>(",[332,6746,6747],{"class":551},"'favorites'",[332,6749,6750],{"class":355},", [])\n",[332,6752,6753,6755,6757],{"class":334,"line":421},[332,6754,2112],{"class":355},[332,6756,2127],{"class":2057},[332,6758,2061],{"class":355},[48,6760,6761],{},"Gode composable-principper:",[625,6763,6764,6771,6774,6777],{},[628,6765,6766,6767,6770],{},"Navngiv dem altid med ",[287,6768,6769],{},"use","-prefix",[628,6772,6773],{},"Return refs eller reactive objekter så forbrugeren kan destructure",[628,6775,6776],{},"Hold dem fokuserede på én ting",[628,6778,6779,6780,6783],{},"Håndter cleanup i ",[287,6781,6782],{},"onUnmounted"," hvis nødvendigt",[43,6785,6787],{"id":6786},"pinia-fremfor-vuex","Pinia fremfor Vuex",[48,6789,6790],{},"Vuex er officielt deprecated. Pinia er den anbefalede state management-løsning for Vue 3. Den er lettere, har bedre TypeScript-support og bruger Composition API:",[280,6792,6794],{"className":326,"code":6793,"language":328,"meta":217,"style":217},"\u002F\u002F stores\u002FuseUserStore.ts\nimport { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\n\nexport const useUserStore = defineStore('user', () => {\n  const user = ref\u003CUser | null>(null)\n  const isLoggedIn = computed(() => user.value !== null)\n\n  async function login(email: string, password: string) {\n    const response = await fetch('\u002Fapi\u002Flogin', {\n      method: 'POST',\n      body: JSON.stringify({ email, password })\n    })\n    user.value = await response.json()\n  }\n\n  function logout() {\n    user.value = null\n  }\n\n  return { user, isLoggedIn, login, logout }\n})\n",[287,6795,6796,6801,6813,6823,6827,6854,6878,6903,6907,6936,6958,6968,6982,6986,7002,7006,7010,7020,7029,7033,7037,7044],{"__ignoreMap":217},[332,6797,6798],{"class":334,"line":335},[332,6799,6800],{"class":338},"\u002F\u002F stores\u002FuseUserStore.ts\n",[332,6802,6803,6805,6808,6810],{"class":334,"line":218},[332,6804,3051],{"class":344},[332,6806,6807],{"class":355}," { defineStore } ",[332,6809,3057],{"class":344},[332,6811,6812],{"class":551}," 'pinia'\n",[332,6814,6815,6817,6819,6821],{"class":334,"line":226},[332,6816,3051],{"class":344},[332,6818,3054],{"class":355},[332,6820,3057],{"class":344},[332,6822,3060],{"class":551},[332,6824,6825],{"class":334,"line":395},[332,6826,418],{"emptyLinePlaceholder":238},[332,6828,6829,6831,6834,6837,6839,6842,6844,6847,6850,6852],{"class":334,"line":415},[332,6830,345],{"class":344},[332,6832,6833],{"class":344}," const",[332,6835,6836],{"class":364}," useUserStore",[332,6838,368],{"class":344},[332,6840,6841],{"class":351}," defineStore",[332,6843,407],{"class":355},[332,6845,6846],{"class":551},"'user'",[332,6848,6849],{"class":355},", () ",[332,6851,566],{"class":344},[332,6853,782],{"class":355},[332,6855,6856,6858,6860,6862,6864,6866,6868,6870,6872,6874,6876],{"class":334,"line":421},[332,6857,361],{"class":344},[332,6859,365],{"class":364},[332,6861,368],{"class":344},[332,6863,371],{"class":351},[332,6865,374],{"class":355},[332,6867,377],{"class":351},[332,6869,380],{"class":344},[332,6871,383],{"class":364},[332,6873,386],{"class":355},[332,6875,389],{"class":364},[332,6877,392],{"class":355},[332,6879,6880,6882,6885,6887,6889,6891,6893,6896,6899,6901],{"class":334,"line":434},[332,6881,361],{"class":344},[332,6883,6884],{"class":364}," isLoggedIn",[332,6886,368],{"class":344},[332,6888,2702],{"class":351},[332,6890,2705],{"class":355},[332,6892,566],{"class":344},[332,6894,6895],{"class":355}," user.value ",[332,6897,6898],{"class":344},"!==",[332,6900,383],{"class":364},[332,6902,392],{"class":355},[332,6904,6905],{"class":334,"line":446},[332,6906,418],{"emptyLinePlaceholder":238},[332,6908,6909,6911,6913,6916,6918,6921,6923,6925,6927,6930,6932,6934],{"class":334,"line":466},[332,6910,424],{"class":344},[332,6912,348],{"class":344},[332,6914,6915],{"class":351}," login",[332,6917,407],{"class":355},[332,6919,6920],{"class":787},"email",[332,6922,791],{"class":344},[332,6924,6311],{"class":364},[332,6926,687],{"class":355},[332,6928,6929],{"class":787},"password",[332,6931,791],{"class":344},[332,6933,6311],{"class":364},[332,6935,6543],{"class":355},[332,6937,6938,6940,6943,6945,6947,6950,6952,6955],{"class":334,"line":476},[332,6939,3084],{"class":344},[332,6941,6942],{"class":364}," response",[332,6944,368],{"class":344},[332,6946,454],{"class":344},[332,6948,6949],{"class":351}," fetch",[332,6951,407],{"class":355},[332,6953,6954],{"class":551},"'\u002Fapi\u002Flogin'",[332,6956,6957],{"class":355},", {\n",[332,6959,6960,6963,6966],{"class":334,"line":482},[332,6961,6962],{"class":355},"      method: ",[332,6964,6965],{"class":551},"'POST'",[332,6967,555],{"class":355},[332,6969,6970,6973,6975,6977,6979],{"class":334,"line":487},[332,6971,6972],{"class":355},"      body: ",[332,6974,6633],{"class":364},[332,6976,1956],{"class":355},[332,6978,6638],{"class":351},[332,6980,6981],{"class":355},"({ email, password })\n",[332,6983,6984],{"class":334,"line":496},[332,6985,4073],{"class":355},[332,6987,6988,6990,6992,6994,6997,7000],{"class":334,"line":2156},[332,6989,449],{"class":355},[332,6991,440],{"class":344},[332,6993,454],{"class":344},[332,6995,6996],{"class":355}," response.",[332,6998,6999],{"class":351},"json",[332,7001,463],{"class":355},[332,7003,7004],{"class":334,"line":2162},[332,7005,479],{"class":355},[332,7007,7008],{"class":334,"line":2173},[332,7009,418],{"emptyLinePlaceholder":238},[332,7011,7012,7015,7018],{"class":334,"line":2179},[332,7013,7014],{"class":344},"  function",[332,7016,7017],{"class":351}," logout",[332,7019,356],{"class":355},[332,7021,7022,7024,7026],{"class":334,"line":2184},[332,7023,449],{"class":355},[332,7025,440],{"class":344},[332,7027,7028],{"class":364}," null\n",[332,7030,7031],{"class":334,"line":2193},[332,7032,479],{"class":355},[332,7034,7035],{"class":334,"line":2204},[332,7036,418],{"emptyLinePlaceholder":238},[332,7038,7039,7041],{"class":334,"line":2210},[332,7040,490],{"class":344},[332,7042,7043],{"class":355}," { user, isLoggedIn, login, logout }\n",[332,7045,7046],{"class":334,"line":2215},[332,7047,3790],{"class":355},[48,7049,7050,7051,7054],{},"Brug altid ",[287,7052,7053],{},"setup store"," syntaksen (som ovenfor) fremfor options syntaksen. Den er mere fleksibel og mapper direkte til Composition API patterns, du allerede kender.",[43,7056,7058],{"id":7057},"typescript-med-vue-3","TypeScript med Vue 3",[48,7060,7061],{},"Vue 3 er bygget med TypeScript, og understøttelsen er førsteklasses. Her er de vigtigste patterns:",[280,7063,7065],{"className":2460,"code":7064,"language":997,"meta":217,"style":217},"\u003Cscript setup lang=\"ts\">\n\u002F\u002F Typer dine props med generics\nconst props = defineProps\u003C{\n  title: string\n  items: BlogPost[]\n  variant?: 'primary' | 'secondary'\n}>()\n\n\u002F\u002F Typer dine emits\nconst emit = defineEmits\u003C{\n  submit: [value: string]\n  update: [id: number, data: Partial\u003CBlogPost>]\n}>()\n\n\u002F\u002F Typer dine refs\nconst inputRef = ref\u003CHTMLInputElement | null>(null)\nconst posts = ref\u003CBlogPost[]>([])\n\n\u002F\u002F Brug interfaces til komplekse typer\ninterface BlogPost {\n  id: number\n  title: string\n  content: string\n  publishedAt: Date\n}\n\u003C\u002Fscript>\n",[287,7066,7067,7083,7088,7101,7109,7120,7135,7139,7143,7148,7162,7181,7215,7219,7223,7228,7254,7272,7276,7281,7289,7297,7305,7314,7323,7327],{"__ignoreMap":217},[332,7068,7069,7071,7073,7075,7077,7079,7081],{"class":334,"line":335},[332,7070,374],{"class":355},[332,7072,2127],{"class":2057},[332,7074,3838],{"class":351},[332,7076,2611],{"class":351},[332,7078,440],{"class":355},[332,7080,2616],{"class":551},[332,7082,2061],{"class":355},[332,7084,7085],{"class":334,"line":218},[332,7086,7087],{"class":338},"\u002F\u002F Typer dine props med generics\n",[332,7089,7090,7092,7095,7097,7099],{"class":334,"line":226},[332,7091,530],{"class":344},[332,7093,7094],{"class":364}," props",[332,7096,368],{"class":344},[332,7098,6424],{"class":351},[332,7100,6288],{"class":355},[332,7102,7103,7105,7107],{"class":334,"line":395},[332,7104,6431],{"class":787},[332,7106,791],{"class":344},[332,7108,794],{"class":364},[332,7110,7111,7113,7115,7118],{"class":334,"line":415},[332,7112,824],{"class":787},[332,7114,791],{"class":344},[332,7116,7117],{"class":351}," BlogPost",[332,7119,832],{"class":355},[332,7121,7122,7125,7127,7130,7132],{"class":334,"line":421},[332,7123,7124],{"class":787},"  variant",[332,7126,6443],{"class":344},[332,7128,7129],{"class":551}," 'primary'",[332,7131,380],{"class":344},[332,7133,7134],{"class":551}," 'secondary'\n",[332,7136,7137],{"class":334,"line":434},[332,7138,6361],{"class":355},[332,7140,7141],{"class":334,"line":446},[332,7142,418],{"emptyLinePlaceholder":238},[332,7144,7145],{"class":334,"line":466},[332,7146,7147],{"class":338},"\u002F\u002F Typer dine emits\n",[332,7149,7150,7152,7155,7157,7160],{"class":334,"line":476},[332,7151,530],{"class":344},[332,7153,7154],{"class":364}," emit",[332,7156,368],{"class":344},[332,7158,7159],{"class":351}," defineEmits",[332,7161,6288],{"class":355},[332,7163,7164,7167,7169,7171,7174,7177,7179],{"class":334,"line":482},[332,7165,7166],{"class":787},"  submit",[332,7168,791],{"class":344},[332,7170,5236],{"class":355},[332,7172,7173],{"class":351},"value",[332,7175,7176],{"class":355},": ",[332,7178,866],{"class":364},[332,7180,620],{"class":355},[332,7182,7183,7186,7188,7190,7193,7195,7198,7200,7202,7204,7207,7209,7212],{"class":334,"line":487},[332,7184,7185],{"class":787},"  update",[332,7187,791],{"class":344},[332,7189,5236],{"class":355},[332,7191,7192],{"class":351},"id",[332,7194,7176],{"class":355},[332,7196,7197],{"class":364},"number",[332,7199,687],{"class":355},[332,7201,3501],{"class":351},[332,7203,7176],{"class":355},[332,7205,7206],{"class":351},"Partial",[332,7208,374],{"class":355},[332,7210,7211],{"class":351},"BlogPost",[332,7213,7214],{"class":355},">]\n",[332,7216,7217],{"class":334,"line":496},[332,7218,6361],{"class":355},[332,7220,7221],{"class":334,"line":2156},[332,7222,418],{"emptyLinePlaceholder":238},[332,7224,7225],{"class":334,"line":2162},[332,7226,7227],{"class":338},"\u002F\u002F Typer dine refs\n",[332,7229,7230,7232,7235,7237,7239,7241,7244,7246,7248,7250,7252],{"class":334,"line":2173},[332,7231,530],{"class":344},[332,7233,7234],{"class":364}," inputRef",[332,7236,368],{"class":344},[332,7238,371],{"class":351},[332,7240,374],{"class":355},[332,7242,7243],{"class":351},"HTMLInputElement",[332,7245,380],{"class":344},[332,7247,383],{"class":364},[332,7249,386],{"class":355},[332,7251,389],{"class":364},[332,7253,392],{"class":355},[332,7255,7256,7258,7261,7263,7265,7267,7269],{"class":334,"line":2179},[332,7257,530],{"class":344},[332,7259,7260],{"class":364}," posts",[332,7262,368],{"class":344},[332,7264,371],{"class":351},[332,7266,374],{"class":355},[332,7268,7211],{"class":351},[332,7270,7271],{"class":355},"[]>([])\n",[332,7273,7274],{"class":334,"line":2184},[332,7275,418],{"emptyLinePlaceholder":238},[332,7277,7278],{"class":334,"line":2193},[332,7279,7280],{"class":338},"\u002F\u002F Brug interfaces til komplekse typer\n",[332,7282,7283,7285,7287],{"class":334,"line":2204},[332,7284,776],{"class":344},[332,7286,7117],{"class":351},[332,7288,782],{"class":355},[332,7290,7291,7293,7295],{"class":334,"line":2210},[332,7292,788],{"class":787},[332,7294,791],{"class":344},[332,7296,6446],{"class":364},[332,7298,7299,7301,7303],{"class":334,"line":2215},[332,7300,6431],{"class":787},[332,7302,791],{"class":344},[332,7304,794],{"class":364},[332,7306,7307,7310,7312],{"class":334,"line":2221},[332,7308,7309],{"class":787},"  content",[332,7311,791],{"class":344},[332,7313,794],{"class":364},[332,7315,7316,7319,7321],{"class":334,"line":2801},[332,7317,7318],{"class":787},"  publishedAt",[332,7320,791],{"class":344},[332,7322,852],{"class":351},[332,7324,7325],{"class":334,"line":2828},[332,7326,499],{"class":355},[332,7328,7329,7331,7333],{"class":334,"line":2848},[332,7330,2112],{"class":355},[332,7332,2127],{"class":2057},[332,7334,2061],{"class":355},[48,7336,7337,7338,7341],{},"Et godt tip: Definer dine typer i separate filer under en ",[287,7339,7340],{},"types\u002F"," mappe, så de kan genbruges på tværs af komponenter og composables.",[43,7343,7345],{"id":7344},"performance-tips","Performance Tips",[119,7347,7349],{"id":7348},"brug-shallowref-til-store-objekter","Brug shallowRef til store objekter",[48,7351,7352,7353,7356],{},"Hvis du har store objekter eller arrays, der ikke har brug for dyb reaktivitet, kan ",[287,7354,7355],{},"shallowRef"," spare dig for betydelig overhead:",[280,7358,7360],{"className":326,"code":7359,"language":328,"meta":217,"style":217},"import { shallowRef, triggerRef } from 'vue'\n\n\u002F\u002F Kun top-level .value ændringer trigger opdateringer\nconst largeList = shallowRef\u003CDataItem[]>([])\n\n\u002F\u002F Når du opdaterer nested data, trigger manuelt\nlargeList.value[0].name = 'Updated'\ntriggerRef(largeList)\n\n\u002F\u002F Eller erstat hele værdien\nlargeList.value = [...largeList.value]\n",[287,7361,7362,7373,7377,7382,7401,7405,7410,7425,7433,7437,7442],{"__ignoreMap":217},[332,7363,7364,7366,7369,7371],{"class":334,"line":335},[332,7365,3051],{"class":344},[332,7367,7368],{"class":355}," { shallowRef, triggerRef } ",[332,7370,3057],{"class":344},[332,7372,3060],{"class":551},[332,7374,7375],{"class":334,"line":218},[332,7376,418],{"emptyLinePlaceholder":238},[332,7378,7379],{"class":334,"line":226},[332,7380,7381],{"class":338},"\u002F\u002F Kun top-level .value ændringer trigger opdateringer\n",[332,7383,7384,7386,7389,7391,7394,7396,7399],{"class":334,"line":395},[332,7385,530],{"class":344},[332,7387,7388],{"class":364}," largeList",[332,7390,368],{"class":344},[332,7392,7393],{"class":351}," shallowRef",[332,7395,374],{"class":355},[332,7397,7398],{"class":351},"DataItem",[332,7400,7271],{"class":355},[332,7402,7403],{"class":334,"line":415},[332,7404,418],{"emptyLinePlaceholder":238},[332,7406,7407],{"class":334,"line":421},[332,7408,7409],{"class":338},"\u002F\u002F Når du opdaterer nested data, trigger manuelt\n",[332,7411,7412,7415,7417,7420,7422],{"class":334,"line":434},[332,7413,7414],{"class":355},"largeList.value[",[332,7416,3096],{"class":364},[332,7418,7419],{"class":355},"].name ",[332,7421,440],{"class":344},[332,7423,7424],{"class":551}," 'Updated'\n",[332,7426,7427,7430],{"class":334,"line":446},[332,7428,7429],{"class":351},"triggerRef",[332,7431,7432],{"class":355},"(largeList)\n",[332,7434,7435],{"class":334,"line":466},[332,7436,418],{"emptyLinePlaceholder":238},[332,7438,7439],{"class":334,"line":476},[332,7440,7441],{"class":338},"\u002F\u002F Eller erstat hele værdien\n",[332,7443,7444,7447,7449,7451,7453],{"class":334,"line":482},[332,7445,7446],{"class":355},"largeList.value ",[332,7448,440],{"class":344},[332,7450,5236],{"class":355},[332,7452,5293],{"class":344},[332,7454,7455],{"class":355},"largeList.value]\n",[119,7457,7459],{"id":7458},"computed-vs-methods","Computed vs methods",[48,7461,7462,7464],{},[287,7463,3203],{}," caches resultatet og genberegner kun når afhængigheder ændres. Brug det altid til afledte værdier:",[280,7466,7468],{"className":326,"code":7467,"language":328,"meta":217,"style":217},"\u002F\u002F GODT - caches resultatet\nconst expensiveResult = computed(() => {\n  return items.value.filter(i => i.active).sort((a, b) => b.score - a.score)\n})\n\n\u002F\u002F SKIDT - kører ved hver re-render\nfunction getExpensiveResult() {\n  return items.value.filter(i => i.active).sort((a, b) => b.score - a.score)\n}\n",[287,7469,7470,7475,7492,7536,7540,7544,7549,7558,7594],{"__ignoreMap":217},[332,7471,7472],{"class":334,"line":335},[332,7473,7474],{"class":338},"\u002F\u002F GODT - caches resultatet\n",[332,7476,7477,7479,7482,7484,7486,7488,7490],{"class":334,"line":218},[332,7478,530],{"class":344},[332,7480,7481],{"class":364}," expensiveResult",[332,7483,368],{"class":344},[332,7485,2702],{"class":351},[332,7487,2705],{"class":355},[332,7489,566],{"class":344},[332,7491,782],{"class":355},[332,7493,7494,7496,7498,7501,7503,7506,7509,7512,7515,7517,7519,7521,7524,7526,7528,7531,7533],{"class":334,"line":226},[332,7495,490],{"class":344},[332,7497,2717],{"class":355},[332,7499,7500],{"class":351},"filter",[332,7502,407],{"class":355},[332,7504,7505],{"class":787},"i",[332,7507,7508],{"class":344}," =>",[332,7510,7511],{"class":355}," i.active).",[332,7513,7514],{"class":351},"sort",[332,7516,5162],{"class":355},[332,7518,966],{"class":787},[332,7520,687],{"class":355},[332,7522,7523],{"class":787},"b",[332,7525,4055],{"class":355},[332,7527,566],{"class":344},[332,7529,7530],{"class":355}," b.score ",[332,7532,4175],{"class":344},[332,7534,7535],{"class":355}," a.score)\n",[332,7537,7538],{"class":334,"line":395},[332,7539,3790],{"class":355},[332,7541,7542],{"class":334,"line":415},[332,7543,418],{"emptyLinePlaceholder":238},[332,7545,7546],{"class":334,"line":421},[332,7547,7548],{"class":338},"\u002F\u002F SKIDT - kører ved hver re-render\n",[332,7550,7551,7553,7556],{"class":334,"line":434},[332,7552,5852],{"class":344},[332,7554,7555],{"class":351}," getExpensiveResult",[332,7557,356],{"class":355},[332,7559,7560,7562,7564,7566,7568,7570,7572,7574,7576,7578,7580,7582,7584,7586,7588,7590,7592],{"class":334,"line":446},[332,7561,490],{"class":344},[332,7563,2717],{"class":355},[332,7565,7500],{"class":351},[332,7567,407],{"class":355},[332,7569,7505],{"class":787},[332,7571,7508],{"class":344},[332,7573,7511],{"class":355},[332,7575,7514],{"class":351},[332,7577,5162],{"class":355},[332,7579,966],{"class":787},[332,7581,687],{"class":355},[332,7583,7523],{"class":787},[332,7585,4055],{"class":355},[332,7587,566],{"class":344},[332,7589,7530],{"class":355},[332,7591,4175],{"class":344},[332,7593,7535],{"class":355},[332,7595,7596],{"class":334,"line":466},[332,7597,499],{"class":355},[119,7599,7601],{"id":7600},"lazy-loading-med-defineasynccomponent","Lazy loading med defineAsyncComponent",[48,7603,7604],{},"Split din bundle ved at lazy-loade tunge komponenter:",[280,7606,7608],{"className":326,"code":7607,"language":328,"meta":217,"style":217},"import { defineAsyncComponent } from 'vue'\n\nconst HeavyChart = defineAsyncComponent(() =>\n  import('.\u002Fcomponents\u002FHeavyChart.vue')\n)\n\n\u002F\u002F Med loading og error states\nconst HeavyEditor = defineAsyncComponent({\n  loader: () => import('.\u002Fcomponents\u002FHeavyEditor.vue'),\n  loadingComponent: LoadingSpinner,\n  errorComponent: ErrorDisplay,\n  delay: 200,\n  timeout: 10000\n})\n",[287,7609,7610,7620,7624,7639,7650,7654,7658,7663,7676,7693,7698,7703,7712,7719],{"__ignoreMap":217},[332,7611,7612,7614,7616,7618],{"class":334,"line":335},[332,7613,3051],{"class":344},[332,7615,4542],{"class":355},[332,7617,3057],{"class":344},[332,7619,3060],{"class":551},[332,7621,7622],{"class":334,"line":218},[332,7623,418],{"emptyLinePlaceholder":238},[332,7625,7626,7628,7631,7633,7635,7637],{"class":334,"line":226},[332,7627,530],{"class":344},[332,7629,7630],{"class":364}," HeavyChart",[332,7632,368],{"class":344},[332,7634,4570],{"class":351},[332,7636,2705],{"class":355},[332,7638,4575],{"class":344},[332,7640,7641,7643,7645,7648],{"class":334,"line":395},[332,7642,4580],{"class":344},[332,7644,407],{"class":355},[332,7646,7647],{"class":551},"'.\u002Fcomponents\u002FHeavyChart.vue'",[332,7649,392],{"class":355},[332,7651,7652],{"class":334,"line":415},[332,7653,392],{"class":355},[332,7655,7656],{"class":334,"line":421},[332,7657,418],{"emptyLinePlaceholder":238},[332,7659,7660],{"class":334,"line":434},[332,7661,7662],{"class":338},"\u002F\u002F Med loading og error states\n",[332,7664,7665,7667,7670,7672,7674],{"class":334,"line":446},[332,7666,530],{"class":344},[332,7668,7669],{"class":364}," HeavyEditor",[332,7671,368],{"class":344},[332,7673,4570],{"class":351},[332,7675,3920],{"class":355},[332,7677,7678,7680,7682,7684,7686,7688,7691],{"class":334,"line":466},[332,7679,4620],{"class":351},[332,7681,563],{"class":355},[332,7683,566],{"class":344},[332,7685,569],{"class":344},[332,7687,407],{"class":355},[332,7689,7690],{"class":551},"'.\u002Fcomponents\u002FHeavyEditor.vue'",[332,7692,4634],{"class":355},[332,7694,7695],{"class":334,"line":476},[332,7696,7697],{"class":355},"  loadingComponent: LoadingSpinner,\n",[332,7699,7700],{"class":334,"line":482},[332,7701,7702],{"class":355},"  errorComponent: ErrorDisplay,\n",[332,7704,7705,7707,7710],{"class":334,"line":487},[332,7706,4659],{"class":355},[332,7708,7709],{"class":364},"200",[332,7711,555],{"class":355},[332,7713,7714,7716],{"class":334,"line":496},[332,7715,4672],{"class":355},[332,7717,7718],{"class":364},"10000\n",[332,7720,7721],{"class":334,"line":2156},[332,7722,3790],{"class":355},[43,7724,7726],{"id":7725},"almindelige-fejl-du-bør-undgå","Almindelige fejl du bør undgå",[119,7728,7730],{"id":7729},"_1-muter-ikke-props","1. Muter ikke props",[48,7732,7733],{},"Vue advarer dig, men det er værd at gentage. Klon altid data fra props før du ændrer den:",[280,7735,7737],{"className":326,"code":7736,"language":328,"meta":217,"style":217},"const props = defineProps\u003C{ user: User }>()\n\n\u002F\u002F FORKERT\nprops.user.name = 'New name'\n\n\u002F\u002F RIGTIGT\nconst localUser = ref({ ...props.user })\n",[287,7738,7739,7763,7767,7772,7782,7786,7791],{"__ignoreMap":217},[332,7740,7741,7743,7745,7747,7749,7752,7755,7757,7760],{"class":334,"line":335},[332,7742,530],{"class":344},[332,7744,7094],{"class":364},[332,7746,368],{"class":344},[332,7748,6424],{"class":351},[332,7750,7751],{"class":355},"\u003C{ ",[332,7753,7754],{"class":787},"user",[332,7756,791],{"class":344},[332,7758,7759],{"class":351}," User",[332,7761,7762],{"class":355}," }>()\n",[332,7764,7765],{"class":334,"line":218},[332,7766,418],{"emptyLinePlaceholder":238},[332,7768,7769],{"class":334,"line":226},[332,7770,7771],{"class":338},"\u002F\u002F FORKERT\n",[332,7773,7774,7777,7779],{"class":334,"line":395},[332,7775,7776],{"class":355},"props.user.name ",[332,7778,440],{"class":344},[332,7780,7781],{"class":551}," 'New name'\n",[332,7783,7784],{"class":334,"line":415},[332,7785,418],{"emptyLinePlaceholder":238},[332,7787,7788],{"class":334,"line":421},[332,7789,7790],{"class":338},"\u002F\u002F RIGTIGT\n",[332,7792,7793,7795,7798,7800,7802,7805,7807],{"class":334,"line":434},[332,7794,530],{"class":344},[332,7796,7797],{"class":364}," localUser",[332,7799,368],{"class":344},[332,7801,371],{"class":351},[332,7803,7804],{"class":355},"({ ",[332,7806,5293],{"class":344},[332,7808,7809],{"class":355},"props.user })\n",[119,7811,7813,7814,7816],{"id":7812},"_2-glem-ikke-at-bruge-i-v-for","2. Glem ikke at bruge ",[6526,7815],{}," i v-for",[48,7818,7819],{},"Unikke keys hjælper Vue med effektivt at opdatere DOM:",[280,7821,7823],{"className":2460,"code":7822,"language":997,"meta":217,"style":217},"\u003C!-- Brug altid en unik identifier, aldrig index -->\n\u003Cdiv v-for=\"item in items\" :key=\"item.id\">\n  {{ item.name }}\n\u003C\u002Fdiv>\n",[287,7824,7825,7830,7870,7875],{"__ignoreMap":217},[332,7826,7827],{"class":334,"line":335},[332,7828,7829],{"class":338},"\u003C!-- Brug altid en unik identifier, aldrig index -->\n",[332,7831,7832,7834,7836,7838,7840,7843,7846,7849,7852,7854,7857,7859,7861,7863,7866,7868],{"class":334,"line":218},[332,7833,374],{"class":355},[332,7835,2069],{"class":2057},[332,7837,2530],{"class":344},[332,7839,440],{"class":355},[332,7841,7842],{"class":551},"\"",[332,7844,7845],{"class":355},"item ",[332,7847,7848],{"class":344},"in",[332,7850,7851],{"class":355}," items",[332,7853,7842],{"class":551},[332,7855,7856],{"class":355}," :",[332,7858,6526],{"class":351},[332,7860,440],{"class":355},[332,7862,7842],{"class":551},[332,7864,7865],{"class":355},"item.id",[332,7867,7842],{"class":551},[332,7869,2061],{"class":355},[332,7871,7872],{"class":334,"line":226},[332,7873,7874],{"class":355},"  {{ item.name }}\n",[332,7876,7877,7879,7881],{"class":334,"line":395},[332,7878,2112],{"class":355},[332,7880,2069],{"class":2057},[332,7882,2061],{"class":355},[119,7884,7886],{"id":7885},"_3-undgå-watch-når-computed-er-nok","3. Undgå watch når computed er nok",[48,7888,7889,7890,7893,7894,7896],{},"Mange udviklere bruger ",[287,7891,7892],{},"watch"," hvor en ",[287,7895,3203],{}," ville være bedre:",[280,7898,7900],{"className":326,"code":7899,"language":328,"meta":217,"style":217},"\u002F\u002F OVERKOMPLICERET\nconst fullName = ref('')\nwatch([firstName, lastName], ([first, last]) => {\n  fullName.value = `${first} ${last}`\n})\n\n\u002F\u002F BEDRE\nconst fullName = computed(() => `${firstName.value} ${lastName.value}`)\n",[287,7901,7902,7907,7924,7946,7966,7970,7974,7979],{"__ignoreMap":217},[332,7903,7904],{"class":334,"line":335},[332,7905,7906],{"class":338},"\u002F\u002F OVERKOMPLICERET\n",[332,7908,7909,7911,7914,7916,7918,7920,7922],{"class":334,"line":218},[332,7910,530],{"class":344},[332,7912,7913],{"class":364}," fullName",[332,7915,368],{"class":344},[332,7917,371],{"class":351},[332,7919,407],{"class":355},[332,7921,6107],{"class":551},[332,7923,392],{"class":355},[332,7925,7926,7928,7931,7934,7936,7939,7942,7944],{"class":334,"line":226},[332,7927,7892],{"class":351},[332,7929,7930],{"class":355},"([firstName, lastName], ([",[332,7932,7933],{"class":787},"first",[332,7935,687],{"class":355},[332,7937,7938],{"class":787},"last",[332,7940,7941],{"class":355},"]) ",[332,7943,566],{"class":344},[332,7945,782],{"class":355},[332,7947,7948,7951,7953,7956,7958,7961,7963],{"class":334,"line":395},[332,7949,7950],{"class":355},"  fullName.value ",[332,7952,440],{"class":344},[332,7954,7955],{"class":551}," `${",[332,7957,7933],{"class":355},[332,7959,7960],{"class":551},"} ${",[332,7962,7938],{"class":355},[332,7964,7965],{"class":551},"}`\n",[332,7967,7968],{"class":334,"line":415},[332,7969,3790],{"class":355},[332,7971,7972],{"class":334,"line":421},[332,7973,418],{"emptyLinePlaceholder":238},[332,7975,7976],{"class":334,"line":434},[332,7977,7978],{"class":338},"\u002F\u002F BEDRE\n",[332,7980,7981,7983,7985,7987,7989,7991,7993,7995,7997,7999,8001,8003,8005,8007,8009,8012],{"class":334,"line":446},[332,7982,530],{"class":344},[332,7984,7913],{"class":364},[332,7986,368],{"class":344},[332,7988,2702],{"class":351},[332,7990,2705],{"class":355},[332,7992,566],{"class":344},[332,7994,7955],{"class":551},[332,7996,2240],{"class":355},[332,7998,1956],{"class":551},[332,8000,7173],{"class":355},[332,8002,7960],{"class":551},[332,8004,2244],{"class":355},[332,8006,1956],{"class":551},[332,8008,7173],{"class":355},[332,8010,8011],{"class":551},"}`",[332,8013,392],{"class":355},[119,8015,8017],{"id":8016},"_4-håndter-cleanup-i-composables","4. Håndter cleanup i composables",[48,8019,8020],{},"Hvis din composable opretter event listeners eller timers, ryd altid op:",[280,8022,8024],{"className":326,"code":8023,"language":328,"meta":217,"style":217},"export function useWindowResize() {\n  const width = ref(window.innerWidth)\n\n  function onResize() {\n    width.value = window.innerWidth\n  }\n\n  onMounted(() => window.addEventListener('resize', onResize))\n  onUnmounted(() => window.removeEventListener('resize', onResize))\n\n  return { width }\n}\n",[287,8025,8026,8037,8051,8055,8064,8074,8078,8082,8105,8125,8129,8136],{"__ignoreMap":217},[332,8027,8028,8030,8032,8035],{"class":334,"line":335},[332,8029,345],{"class":344},[332,8031,348],{"class":344},[332,8033,8034],{"class":351}," useWindowResize",[332,8036,356],{"class":355},[332,8038,8039,8041,8044,8046,8048],{"class":334,"line":218},[332,8040,361],{"class":344},[332,8042,8043],{"class":364}," width",[332,8045,368],{"class":344},[332,8047,371],{"class":351},[332,8049,8050],{"class":355},"(window.innerWidth)\n",[332,8052,8053],{"class":334,"line":226},[332,8054,418],{"emptyLinePlaceholder":238},[332,8056,8057,8059,8062],{"class":334,"line":395},[332,8058,7014],{"class":344},[332,8060,8061],{"class":351}," onResize",[332,8063,356],{"class":355},[332,8065,8066,8069,8071],{"class":334,"line":415},[332,8067,8068],{"class":355},"    width.value ",[332,8070,440],{"class":344},[332,8072,8073],{"class":355}," window.innerWidth\n",[332,8075,8076],{"class":334,"line":421},[332,8077,479],{"class":355},[332,8079,8080],{"class":334,"line":434},[332,8081,418],{"emptyLinePlaceholder":238},[332,8083,8084,8087,8089,8091,8094,8097,8099,8102],{"class":334,"line":446},[332,8085,8086],{"class":351},"  onMounted",[332,8088,2705],{"class":355},[332,8090,566],{"class":344},[332,8092,8093],{"class":355}," window.",[332,8095,8096],{"class":351},"addEventListener",[332,8098,407],{"class":355},[332,8100,8101],{"class":551},"'resize'",[332,8103,8104],{"class":355},", onResize))\n",[332,8106,8107,8110,8112,8114,8116,8119,8121,8123],{"class":334,"line":466},[332,8108,8109],{"class":351},"  onUnmounted",[332,8111,2705],{"class":355},[332,8113,566],{"class":344},[332,8115,8093],{"class":355},[332,8117,8118],{"class":351},"removeEventListener",[332,8120,407],{"class":355},[332,8122,8101],{"class":551},[332,8124,8104],{"class":355},[332,8126,8127],{"class":334,"line":476},[332,8128,418],{"emptyLinePlaceholder":238},[332,8130,8131,8133],{"class":334,"line":482},[332,8132,490],{"class":344},[332,8134,8135],{"class":355}," { width }\n",[332,8137,8138],{"class":334,"line":487},[332,8139,499],{"class":355},[43,8141,3529],{"id":3528},[48,8143,8144,8145,8148,8149,8151],{},"Vue 3 i 2026 er et modent og kraftfuldt framework. De nyeste features som ",[287,8146,8147],{},"defineModel",", reactive destructuring og forbedret TypeScript-support gør det til en fornøjelse at arbejde med. Fokuser på at bruge ",[287,8150,3815],{},", skriv composables i stedet for mixins, vælg Pinia til state management og brug TypeScript overalt.",[960,8153],{},[48,8155,8156,8157,8160],{},"Har du brug for hjælp med din Vue 3 applikation, eller overvejer du at modernisere din eksisterende frontend? ",[966,8158,8159],{"href":968},"Tag kontakt med mig"," - jeg hjælper gerne med alt fra arkitektur og code reviews til fuld implementering.",[972,8162,8163],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":217,"searchDepth":218,"depth":218,"links":8165},[8166,8167,8168,8169,8170,8171,8172,8173,8178,8185],{"id":5758,"depth":218,"text":5759},{"id":5941,"depth":218,"text":5942},{"id":6244,"depth":218,"text":6245},{"id":6375,"depth":218,"text":6376},{"id":6478,"depth":218,"text":6479},{"id":6786,"depth":218,"text":6787},{"id":7057,"depth":218,"text":7058},{"id":7344,"depth":218,"text":7345,"children":8174},[8175,8176,8177],{"id":7348,"depth":226,"text":7349},{"id":7458,"depth":226,"text":7459},{"id":7600,"depth":226,"text":7601},{"id":7725,"depth":218,"text":7726,"children":8179},[8180,8181,8183,8184],{"id":7729,"depth":226,"text":7730},{"id":7812,"depth":226,"text":8182},"2. Glem ikke at bruge  i v-for",{"id":7885,"depth":226,"text":7886},{"id":8016,"depth":226,"text":8017},{"id":3528,"depth":218,"text":3529},"2022-02-06","Opdaterede tips og best practices til Vue 3.4+ og 3.5+ - fra Composition API og script setup til defineModel, reactive destructuring, composables og TypeScript.",{},"\u002Fblog\u002Fvuejs-tips-and-best-practices",{"title":5750,"description":8187},"Opdaterede Vue 3 tips og best practices for 2026. Script setup, defineModel, composables, Pinia, TypeScript og performance optimering.","Vue 3 Tips & Best Practices i 2026 - Moderne Vue udvikling","vuejs-tips-and-best-practices","blog\u002Fvuejs-tips-and-best-practices",[997,8196,328,995,3015],"vue3","\u002Fimages\u002Fcontentful\u002FVueJS.jpg","BfKxaLnLHmxHs_jWBYcBYVvpl21JX9dUXzJy2xS4tiY",{"id":8200,"title":8201,"body":8202,"date":8554,"description":8555,"extension":236,"meta":8556,"navigation":238,"noindex":8,"path":8557,"seo":8558,"seoDescription":8559,"seoTitle":8201,"slug":8560,"stem":8561,"tags":8562,"thumbnail":8563,"updated":8554,"__hash__":8564},"blog\u002Fblog\u002Fvue-3-google-recaptcha.md","Vue 3 - Google reCaptcha implementeret på bare 2 minutter",{"type":40,"value":8203,"toc":8552},[8204,8207,8210,8217,8220,8223,8239,8242,8245,8248,8251,8265,8268,8528,8531,8538,8541,8546,8549],[48,8205,8206],{},"Når vi bygger webapplikationer, har vi ofte brug for at beskytte vores applikationer mod bots og spam. Spammy bots, hackere og ondsindet injektionssoftware kan lave et rigtig grimt rod i vores applikationer, hvis vi ikke har den rette beskyttelse!",[48,8208,8209],{},"Hvordan forhindrer vi det? Ja... reCaptcha til undsætning!",[48,8211,8212,8213,8216],{},"Kort sagt er reCAPTCHA ",[67,8214,8215],{},"en gratis tjeneste fra Google, der hjælper med at beskytte webapplikationer mod spam og misbrug",". Den kan hjælpe med at skelne mennesker fra bots, hvilket gør applikationer mere sikre. Det er en gratis tjeneste, som du kan tilmelde dig på få simple trin.",[48,8218,8219],{},"For at holde denne artikel kort og præcis, vil jeg ikke gå i dybden med hele tilmeldingsprocessen hos Google. Googles dokumentation vil hjælpe dig rigeligt med det.",[48,8221,8222],{},"Forudsætninger:",[625,8224,8225,8228,8236],{},[628,8226,8227],{},"Du skal have en Google-konto for at bruge reCaptcha",[628,8229,8230,8231,8235],{},"API-nøgle - Du kan tilmelde dig her (",[966,8232,8233],{"href":8233,"rel":8234},"https:\u002F\u002Fdevelopers.google.com\u002Frecaptcha\u002Fintro",[4114],")",[628,8237,8238],{},"En kørende Vue 3-applikation",[48,8240,8241],{},"Når du har tilmeldt dig og fået en API-nøgle, skal du muligvis tilføje dit domæne for at bruge den! Du kan tilføje dit domæne i admin-konsollen hos Google.",[48,8243,8244],{},"Vue 3 reCaptcha",[48,8246,8247],{},"Som artiklens titel antyder, kan vi nemt implementere dette i vores Vue 3-applikation. I dette eksempel bruger vi en pakke, der kan gøre arbejdet for os. Med den kan vi implementere reCaptcha-funktionaliteten på blot et par linjer kode.",[48,8249,8250],{},"I din terminal, kør følgende kommando:",[48,8252,8253,8254,8259,8260],{},"Med Yarn: ",[167,8255,8256],{},[67,8257,8258],{},"yarn add vue-recaptcha","\nMed NPM: ",[167,8261,8262],{},[67,8263,8264],{},"npm i vue-recaptcha",[48,8266,8267],{},"Når pakken er installeret, gå ind i dit IDE og Vue-projekt og opret en ny komponent. Med koden herunder har du et fungerende eksempel på en reCaptcha-komponent. Du skal bare tilføje din egen siteKey og selv håndtere, hvad der skal ske, når der opstår en fejl, og når captchaen er gyldig.",[280,8269,8271],{"className":2047,"code":8270,"language":1392,"meta":217,"style":217},"\u003Ctemplate>\n  \u003CVueRecaptcha\n    :sitekey=\"siteKey\"\n    :load-recaptcha-script=\"true\"\n    @verify=\"handleSuccess\"\n    @error=\"handleError\"\n  >\u003C\u002FVueRecaptcha>\n\u003C\u002Ftemplate>\n\n\u003Cscript lang=\"ts\">\nimport { computed, defineComponent } from 'vue';\nimport { VueRecaptcha } from 'vue-recaptcha';\n\nexport default defineComponent({\n  name: 'ReCaptcha',\n  components: {\n    VueRecaptcha\n  },\n  setup() {\n    const siteKey = computed(() => {\n      return 'yourSiteAPIKey';\n    });\n\n    const handleError = () => {\n      \u002F\u002F Do some validation\n    };\n\n    const handleSuccess = (response: string) => {\n     \u002F\u002F Do some validation\n    };\n\n    return {\n      handleSuccess,\n      handleError,\n      siteKey,\n    };\n  }\n});\n\u003C\u002Fscript>\n",[287,8272,8273,8281,8288,8294,8299,8304,8309,8319,8327,8331,8345,8349,8354,8358,8362,8371,8376,8381,8385,8391,8406,8415,8419,8423,8438,8443,8447,8451,8476,8481,8485,8489,8493,8498,8503,8508,8512,8516,8520],{"__ignoreMap":217},[332,8274,8275,8277,8279],{"class":334,"line":335},[332,8276,374],{"class":355},[332,8278,2058],{"class":2057},[332,8280,2061],{"class":355},[332,8282,8283,8285],{"class":334,"line":218},[332,8284,2066],{"class":355},[332,8286,8287],{"class":364},"VueRecaptcha\n",[332,8289,8290],{"class":334,"line":226},[332,8291,8293],{"class":8292},"s6RL2","    :sitekey=\"siteKey\"\n",[332,8295,8296],{"class":334,"line":395},[332,8297,8298],{"class":8292},"    :load-recaptcha-script=\"true\"\n",[332,8300,8301],{"class":334,"line":415},[332,8302,8303],{"class":8292},"    @verify=\"handleSuccess\"\n",[332,8305,8306],{"class":334,"line":421},[332,8307,8308],{"class":8292},"    @error=\"handleError\"\n",[332,8310,8311,8314,8317],{"class":334,"line":434},[332,8312,8313],{"class":355},"  >\u003C\u002F",[332,8315,8316],{"class":364},"VueRecaptcha",[332,8318,2061],{"class":355},[332,8320,8321,8323,8325],{"class":334,"line":446},[332,8322,2112],{"class":355},[332,8324,2058],{"class":2057},[332,8326,2061],{"class":355},[332,8328,8329],{"class":334,"line":466},[332,8330,418],{"emptyLinePlaceholder":238},[332,8332,8333,8335,8337,8339,8341,8343],{"class":334,"line":476},[332,8334,374],{"class":355},[332,8336,2127],{"class":2057},[332,8338,2611],{"class":351},[332,8340,440],{"class":344},[332,8342,2616],{"class":551},[332,8344,2061],{"class":355},[332,8346,8347],{"class":334,"line":482},[332,8348,2623],{"class":355},[332,8350,8351],{"class":334,"line":487},[332,8352,8353],{"class":355},"import { VueRecaptcha } from 'vue-recaptcha';\n",[332,8355,8356],{"class":334,"line":496},[332,8357,418],{"emptyLinePlaceholder":238},[332,8359,8360],{"class":334,"line":2156},[332,8361,2655],{"class":355},[332,8363,8364,8366,8369],{"class":334,"line":2162},[332,8365,2660],{"class":355},[332,8367,8368],{"class":551},"'ReCaptcha'",[332,8370,555],{"class":355},[332,8372,8373],{"class":334,"line":2173},[332,8374,8375],{"class":355},"  components: {\n",[332,8377,8378],{"class":334,"line":2179},[332,8379,8380],{"class":355},"    VueRecaptcha\n",[332,8382,8383],{"class":334,"line":2184},[332,8384,581],{"class":355},[332,8386,8387,8389],{"class":334,"line":2193},[332,8388,2187],{"class":351},[332,8390,356],{"class":355},[332,8392,8393,8396,8398,8400,8402,8404],{"class":334,"line":2204},[332,8394,8395],{"class":355},"    const siteKey ",[332,8397,440],{"class":344},[332,8399,2702],{"class":351},[332,8401,2705],{"class":355},[332,8403,566],{"class":344},[332,8405,782],{"class":355},[332,8407,8408,8410,8413],{"class":334,"line":2210},[332,8409,2714],{"class":344},[332,8411,8412],{"class":551}," 'yourSiteAPIKey'",[332,8414,2729],{"class":355},[332,8416,8417],{"class":334,"line":2215},[332,8418,2734],{"class":355},[332,8420,8421],{"class":334,"line":2221},[332,8422,418],{"emptyLinePlaceholder":238},[332,8424,8425,8427,8430,8432,8434,8436],{"class":334,"line":2801},[332,8426,2776],{"class":355},[332,8428,8429],{"class":351},"handleError",[332,8431,368],{"class":344},[332,8433,2787],{"class":355},[332,8435,566],{"class":344},[332,8437,782],{"class":355},[332,8439,8440],{"class":334,"line":2828},[332,8441,8442],{"class":338},"      \u002F\u002F Do some validation\n",[332,8444,8445],{"class":334,"line":2848},[332,8446,2892],{"class":355},[332,8448,8449],{"class":334,"line":2860},[332,8450,418],{"emptyLinePlaceholder":238},[332,8452,8453,8455,8458,8460,8463,8466,8468,8470,8472,8474],{"class":334,"line":2883},[332,8454,2776],{"class":355},[332,8456,8457],{"class":351},"handleSuccess",[332,8459,368],{"class":344},[332,8461,8462],{"class":355}," (",[332,8464,8465],{"class":787},"response",[332,8467,791],{"class":344},[332,8469,6311],{"class":364},[332,8471,4055],{"class":355},[332,8473,566],{"class":344},[332,8475,782],{"class":355},[332,8477,8478],{"class":334,"line":2889},[332,8479,8480],{"class":338},"     \u002F\u002F Do some validation\n",[332,8482,8483],{"class":334,"line":2895},[332,8484,2892],{"class":355},[332,8486,8487],{"class":334,"line":2900},[332,8488,418],{"emptyLinePlaceholder":238},[332,8490,8491],{"class":334,"line":2909},[332,8492,2918],{"class":355},[332,8494,8495],{"class":334,"line":2915},[332,8496,8497],{"class":355},"      handleSuccess,\n",[332,8499,8500],{"class":334,"line":2921},[332,8501,8502],{"class":355},"      handleError,\n",[332,8504,8505],{"class":334,"line":2927},[332,8506,8507],{"class":355},"      siteKey,\n",[332,8509,8510],{"class":334,"line":2933},[332,8511,2892],{"class":355},[332,8513,8514],{"class":334,"line":2938},[332,8515,479],{"class":355},[332,8517,8518],{"class":334,"line":2943},[332,8519,2946],{"class":355},[332,8521,8522,8524,8526],{"class":334,"line":2949},[332,8523,2112],{"class":355},[332,8525,2127],{"class":2057},[332,8527,2061],{"class":355},[48,8529,8530],{},"Der har du det - på blot et par linjer kode og ved at bruge den fantastiske pakke, kan du tilføje Google reCaptcha til din egen komponent. Dette er et meget basalt fungerende eksempel, men hvis du ønsker at ændre størrelse og stil, kommer den med nogle props, du kan sende til komponenten.",[48,8532,8533,8534],{},"Gå over til dokumentationen for at lære mere om de props og metoder, du har til rådighed: ",[966,8535,8536],{"href":8536,"rel":8537},"https:\u002F\u002Fgithub.com\u002FDanSnow\u002Fvue-recaptcha#readme",[4114],[48,8539,8540],{},"Det var alt for nu!",[48,8542,8543],{},[3592,8544],{"alt":217,"src":8545},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*GmtGvbap0r7toziy-rV9rw.gif",[48,8547,8548],{},"Tak fordi du læste med, og jeg håber du kunne lide artiklen.",[972,8550,8551],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s6RL2, html code.shiki .s6RL2{--shiki-default:#FDAEB7;--shiki-default-font-style:italic}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":217,"searchDepth":218,"depth":218,"links":8553},[],"2022-02-02","Lær hvordan du nemt implementerer Google reCaptcha i din Vue 3-applikation. Det tager kun 2 minutter!",{},"\u002Fblog\u002Fvue-3-google-recaptcha",{"title":8201,"description":8555},"Lær hvordan du nemt implementerer Google reCaptcha i din Vue 3-applikation på bare 2 minutter. Komplet guide med kodeeksempler og opsætning.","vue-3-google-recaptcha","blog\u002Fvue-3-google-recaptcha",[997,2005,995],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*uG97FFS0QE3RSIl-m-3jRw.png","J4vNgJP1f7o_JDzXKh_e3-4s4jg6IH-ZyDn8ofA4lJU",{"id":8566,"title":8567,"body":8568,"date":8782,"description":8783,"extension":236,"meta":8784,"navigation":238,"noindex":8,"path":8785,"seo":8786,"seoDescription":8787,"seoTitle":8567,"slug":8788,"stem":8789,"tags":8790,"thumbnail":8791,"updated":8782,"__hash__":8792},"blog\u002Fblog\u002F10-raad-til-mit-yngre-jeg-som-udvikler.md","10 råd jeg ville give mit yngre jeg som udvikler",{"type":40,"value":8569,"toc":8768},[8570,8573,8577,8587,8596,8599,8602,8605,8608,8611,8614,8617,8620,8623,8627,8630,8633,8636,8639,8642,8646,8649,8652,8655,8659,8662,8665,8668,8672,8675,8678,8681,8684,8688,8691,8694,8697,8701,8704,8712,8716,8719,8722,8725,8729,8732,8735,8738,8742,8745,8749,8752,8755,8759,8762,8765],[48,8571,8572],{},"Før vi går ind i de ting jeg ville fortælle mit yngre jeg, vil jeg gerne give dig lidt baggrund og kontekst om mig og min rejse.",[43,8574,8576],{"id":8575},"min-baggrundshistorie","Min baggrundshistorie",[48,8578,8579],{},[966,8580,8582],{"href":8581},"#a48f",[167,8583,8584],{},[67,8585,8586],{},"Spring baggrundshistorien over og tag mig til rådene",[48,8588,8589,8590,8595],{},"I øjeblikket arbejder jeg som Team Lead & Frontend Tech Lead hos en virksomhed der hedder ",[966,8591,8594],{"href":8592,"rel":8593},"https:\u002F\u002Fleadfamly.com",[4114],"Leadfamly",". Det sidste års tid er gået med at omskrive omkring 500.000 linjer kode fra et gammelt AngularJS-projekt til en ny platform baseret på Vue.js\u002FTypeScript.",[48,8597,8598],{},"Tidligere i min karriere har jeg vundet priser for det jeg laver, sammen med fantastiske teams jeg har arbejdet med. Nu er mine ansvarsområder ikke kun begrænset til kodning, de inkluderer også at lede et team af udviklere, implementere processer, coaching\u002Fmentoring, prioritering af arbejdet osv.",[48,8600,8601],{},"Men det har ikke altid været sådan, det har været en lang rejse, og jeg ville ønske jeg havde gjort en masse ting anderledes gennem min karriere. I mange tilfælde ville jeg ønske jeg kunne gå tilbage til mit yngre jeg og give mig selv lidt gode råd.",[48,8603,8604],{},"Det ville vi vel alle?",[48,8606,8607],{},"Så jeg har været i tech-branchen i en del år nu. Jeg blev færdiguddannet i 2007, og et par måneder senere fik jeg mit første job som udvikler. På den skole jeg gik på lærte jeg HTML\u002FCSS og noget PHP, og selvfølgelig en masse andre ting. Det var en bredere uddannelse, så jeg kom også omkring ting som 3D (Studio Max), Flash, ASP, C++ og grafisk design. Kort efter jeg blev færdig, landede jeg et job som udvikler\u002Fdesigner, hvor jeg lavede mange forskellige typer opgaver, både programmering og design.",[48,8609,8610],{},"Dengang arbejdede jeg primært med hjemmesider og e-commerce sider, men indimellem var der også nogle bannerannoncer der skulle laves, hvilket blev gjort i Flash\u002FActionScript. De hjemmesider der blev bygget dengang var ikke nær så JavaScript-tunge som mange hjemmesider\u002Fwebshops er i dag, så siderne vi byggede var meget \"statiske\" og hovedsageligt opbygget med HTML\u002FCSS med et CMS-system bagved.",[48,8612,8613],{},"SaaS-platforme eksisterede i praksis ikke, og hvis de gjorde, var det normalt ret små systemer. Ting som NoSQL-databaser og JavaScript frameworks var stort set ikke-eksisterende!",[48,8615,8616],{},"Et par år senere fik jeg et nyt job, også som udvikler. Jobbet mindede meget om det første, nemlig at bygge hjemmesider. Den største forskel var at hjemmesiderne var baseret på nogle større CMS-systemer, som Dynamicweb og Synkron VIA (eksisterer ikke længere). Måden man implementerede hjemmesider på var ved hjælp af XSLT. Systemerne returnerede XML, og du transformerede det med XSLT og outputtede selvfølgelig HTML. Efter et par år i jobbet begyndte jeg udelukkende at fokusere på frontend-udvikling og droppede backend-udvikling helt, da min primære interesse var den visuelle side af tingene. Jeg har arbejdet med frontend lige siden.",[48,8618,8619],{},"De sider vi byggede begyndte at blive lidt mere dynamiske og interaktive. Det var også på det tidspunkt jQuery begyndte at dukke op. Et fantastisk værktøj\u002Fbibliotek dengang. Siden da er der sket rigtig meget inden for udvikling, særligt frontend-udvikling. Vi har nu fantastiske JS-biblioteker\u002Fframeworks som Vue, React, Svelte, vi har NPM hvor vi nemt kan hente pakker til vores projekter, og vi har module bundlers til at gøre alle mulige fede ting, som vi dengang måtte gøre manuelt. Alt i alt er der sket rigtig meget, og det sker stadig. Tingene bevæger sig hurtigere end nogensinde!",[48,8621,8622],{},"Nu tænker du måske, hvad er din pointe?! Jo, i løbet af den tid har jeg lært en masse, og vejen til hvor jeg er i dag har været en ujævn vej. Når jeg kigger tilbage, er der så mange ting jeg ville have gjort anderledes.",[43,8624,8626],{"id":8625},"råd-1-lær-det-grundlæggende","Råd 1: Lær det grundlæggende",[48,8628,8629],{},"En KÆMPE fejl jeg lavede var ikke at lære det basale først. Selvfølgelig lærte jeg HTML\u002FCSS, men når det kommer til JavaScript, startede jeg helt forkert.",[48,8631,8632],{},"Som du måske har bemærket, nævnte jeg fremkomsten af jQuery, og det var der jeg startede med JavaScript. Jeg lærte nogle år senere at det var et dumt træk. Jeg tog mig ikke tid til rent faktisk at lære JavaScript i sin rene form, altså Vanilla JS. Da vi begyndte at bevæge os væk fra jQuery, kæmpede jeg virkelig, fordi jeg ikke havde lært det grundlæggende i JavaScript.",[48,8634,8635],{},"Jeg tænkte slet ikke over at gøre det på grund af den magi jQuery leverede dengang.",[48,8637,8638],{},"Hvorfor skulle jeg? jQuery var fantastisk.",[48,8640,8641],{},"Uden at kende Vanilla JavaScript vidste jeg reelt ikke hvad der foregik bag kulisserne i jQuery, og jeg havde heller ikke en ordentlig forståelse af selve JS-sproget, da jeg ikke tog mig tid til at lære det. Så et råd jeg ville give mit yngre jeg er helt klart: Lær ALTID det grundlæggende først! Byg derefter dine færdigheder videre derfra.",[43,8643,8645],{"id":8644},"råd-2-fokuser-ikke-kun-på-det-visuelle","Råd 2: Fokuser ikke kun på det visuelle",[48,8647,8648],{},"Jeg har altid elsket at bygge smukke og flotte sider og applikationer der virkelig så godt ud. Jeg gik ikke rigtig op i forretningslogikken der måtte ligge bag. Jeg ville bare fokusere på det visuelle! Sjovt nok er det i dag omvendt... næsten!",[48,8650,8651],{},"Jeg elsker stadig at ting ser godt ud, men nu nyder jeg også virkelig den mere \"komplekse\" side af tingene.",[48,8653,8654],{},"Med det sagt er jeg sikker på at jeg ville være blevet en god udvikler endnu hurtigere, hvis jeg havde kunnet begge dele tidligere i min karriere. Det er ikke det samme som at sige at du ikke er en god udvikler, hvis du kun kan HTML\u002FCSS eller omvendt. Personligt mener jeg bare at du har brug for begge sider for at overleve i frontend-verdenen i dag.",[43,8656,8658],{"id":8657},"råd-3-vær-omkring-kloge-mennesker","Råd 3: Vær omkring kloge mennesker",[48,8660,8661],{},"Lad os se det i øjnene, mange udviklere er introverte og mange er ikke så åbne over for at danne nye relationer med andre. I mine tidlige dage som udvikler prøvede jeg altid at finde ud af tingene selv, uden at ville spørge eller lære fra andre.",[48,8663,8664],{},"Heldigvis har det ændret sig meget med årene! Jeg er ikke introvert, faktisk meget det modsatte. Jeg kan godt lide at være omkring mennesker, jeg kan godt lide at snakke, være social osv. Det har også hjulpet mig meget med at lære. Selv den dag i dag finder jeg ofte de klogeste mennesker i rummet og suger al den viden jeg kan fra dem!",[48,8666,8667],{},"Jeg tror på at man aldrig er færdig med at lære, og at omgive dig med kloge mennesker vil kun gavne dig på lang sigt.",[43,8669,8671],{"id":8670},"råd-4-omfavn-pair-programming","Råd 4: Omfavn pair-programming",[48,8673,8674],{},"Da jeg var yngre, frygtede jeg ofte pair-programming, og jeg tror mange gør det, indtil de lærer at sætte pris på det. For mig var det fordi jeg var bange! Er jeg god nok? Hvad får jeg ud af det? Hvad nu hvis den person jeg sidder med synes jeg gør et dårligt stykke arbejde og så fortæller min chef det? Ville jeg blive fyret?",[48,8676,8677],{},"En masse forskellige spørgsmål fløj altid rundt. Men med årene er pair-programming virkelig noget jeg synes er super værdifuldt, og man kan lære så meget af det.",[48,8679,8680],{},"Selv hvis du er sat sammen med en udvikler der ikke er lige så dygtig som dig selv, får du mulighed for at uddanne og gøre den anden person bedre. Jeg synes det at gøre folk bedre til deres job og se dem få succes er utrolig givende.",[48,8682,8683],{},"Alle de frygtscenarier der fyldte mit yngre jegs sind blev gjort til skamme, da jeg begyndte at give det en fair chance. Jeg lærte en masse af de mennesker jeg var sat sammen med, og ved at blive bedre kunne jeg give den viden videre til andre.",[43,8685,8687],{"id":8686},"råd-5-der-er-intet-jeg-i-team","Råd 5: Der er intet 'jeg' i 'team'",[48,8689,8690],{},"Som ung person vil man ofte bevise sit værd, nogle gange endda på andres bekostning, i hvert fald gjorde jeg. Det er ikke noget jeg er stolt af overhovedet.",[48,8692,8693],{},"I dag kunne jeg ikke drømme om at gøre det på nogen måde, men mit yngre jeg er en anden historie. Jeg arbejdede for mig selv og mine egne mål. Det jeg ikke forstod dengang var, at for at jeg kunne nå mine egne mål, må teamet også lykkes med at nå deres mål. Hvis teamet fejler, fejler du også! Selv hvis du er den dygtigste udvikler, er du stadig en del af et team, og hvis teamet fejler, fejler du! Så enkelt er det.",[48,8695,8696],{},"Når man er en del af et team, er det så vigtigt at ingen arbejder for sig selv og deres egen vindings skyld! Det vil i sidste ende skade teamet, samarbejdet og dynamikken i teamet! Hvis det sker, vil de opgaver og mål teamet har sat sig, sandsynligvis ikke blive nået. Jeg tror på, at for at få succes som individ, har du brug for at teamet og menneskerne omkring dig også får succes.",[43,8698,8700],{"id":8699},"råd-6-lær-forskellige-programmeringsparadigmer-og-design-patterns","Råd 6: Lær forskellige programmeringsparadigmer og design patterns",[48,8702,8703],{},"For mig, da jeg satte mig det mål virkelig at forstå hvordan JavaScript fungerer, hjalp det enormt at lære forskellige programmeringsparadigmer og design patterns. I begyndelsen lærte jeg bare ved at gøre tingene uden rigtig at få fat i den underliggende essens af det hele. Hvad var forskellen mellem OOP vs funktionel programmering? Funktionel vs event-drevet osv... Hvad var de forskellige design patterns?",[48,8705,8706,8707],{},"Når man dykker ned i dem, er der mange, og det kan virke overvældende. Lær dem ikke alle, men lær i det mindste nogle og få en grundlæggende forståelse af dem. Personligt ville jeg ønske jeg var dykket ned i disse emner endnu tidligere, da det hjalp rigtig meget. Hvis du er interesseret i design patterns kan jeg anbefale bogen af ",[966,8708,8711],{"href":8709,"rel":8710},"https:\u002F\u002Fwww.amazon.com\u002FLearning-JavaScript-Design-Patterns-Developers\u002Fdp\u002F1449331815?asin=1449331815&revisionId=&format=4&depth=1",[4114],"Addy Osmani: JavaScript Design Patterns",[43,8713,8715],{"id":8714},"råd-7-invester-altid-i-dig-selv","Råd 7: Invester altid i dig selv",[48,8717,8718],{},"Det er hårdt at være udvikler! Tingene bevæger sig altid hurtigt, og der er altid nye ting at lære. Du er nødt til at investere i dig selv og din egen vækst for at udvikle dig og blive dygtigere som udvikler og som menneske.",[48,8720,8721],{},"Det betyder ikke at du skal gå ud og købe dyre kurser, bøger osv. Jeg taler om at investere din egen tid i at lære!",[48,8723,8724],{},"Uanset om det er at lære ved at gøre, lære fra et kursus, en bog eller andre mennesker. Du er nødt til at gøre det! Der findes ingen genveje til at blive god til noget. Du må investere tid og lægge arbejdet i det!",[43,8726,8728],{"id":8727},"råd-8-pas-på-dig-selv-og-dit-helbred","Råd 8: Pas på dig selv og dit helbred",[48,8730,8731],{},"Da jeg var yngre, levede jeg for weekenderne. Jeg elskede at feste, ligesom de fleste unge gør. Men det er nok ikke den mest sunde livsstil, og det vil efterlade dig træt og udmattet i hvert fald den første del af ugen. Du vil højst sandsynligt ikke have energien til at lære nye ting eller virkelig blive en bedre version af dig selv. Jeg siger ikke at du ALDRIG skal feste, men hver weekend er måske lidt for meget.",[48,8733,8734],{},"Efterhånden som jeg er blevet ældre, har jeg ikke det samme behov for at gå i byen hver weekend. Misforstå mig ikke, jeg nyder stadig en god fest, men nu nyder jeg også en masse andre ting som at bruge tid med min forlovede og venner, træne, gå en tur\u002Fløbe, lave mad osv.",[48,8736,8737],{},"Generelt prøver jeg at leve et sundt liv, spise rigtigt, dyrke regelmæssig motion, da jeg virkelig føler mig mere energisk når jeg lever sundt. Det hjælper mig med at være mere produktiv og have et mindset der er bedre egnet til at lære.",[43,8739,8741],{"id":8740},"råd-9-anerkend-det-der-er-lige-foran-dig","Råd 9: Anerkend det der er lige foran dig",[48,8743,8744],{},"Internettet har ændret verden siden det så dagens lys. Tidligere var viden låst inde på biblioteket, hos brancheeksperter og undervisere. I dag er det nemmere end nogensinde at lære nye færdigheder og forbinde sig med andre mennesker. Jeg synes det er essentielt at udnytte dette til at blive den bedste version af dig selv.",[43,8746,8748],{"id":8747},"råd-10-fejr-dine-sejre","Råd 10: Fejr dine sejre",[48,8750,8751],{},"Da jeg var i starten af min karriere, gjorde jeg aldrig rigtig dette. Jeg tvivlede altid på mig selv og på om jeg kunne have gjort det endnu bedre. Det førte til at jeg aldrig rigtig fejrede mine sejre, når jeg faktisk nåede en milepæl. Det fortryder jeg dybt.",[48,8753,8754],{},"I dag tror jeg det er super vigtigt at fejre dine sejre, både små og store. Det vil opbygge din selvtillid og tro på dig selv, og hvis det er muligt, så fejr sejrene med dit team, hvis du er en del af et!",[43,8756,8758],{"id":8757},"ekstra-råd-giv-det-videre","Ekstra råd: Giv det videre",[48,8760,8761],{},"Hjælp andre mennesker med at blive den bedste version af sig selv. Ved at gøre det holder du dig selv motiveret på din egen vej, og du vil opdage at de varige forbindelser du opbygger ved at hjælpe andre vil gavne dig enormt fremover. Derudover er det bare meget tilfredsstillende at hjælpe andre!",[48,8763,8764],{},"Der er så mange flere tips og råd jeg ville give mit yngre jeg, dette er bare et lille udvalg af de mest essentielle.",[48,8766,8767],{},"Jeg håber du nød artiklen og fandt den nyttig. Hvilke råd ville du give dit yngre jeg?",{"title":217,"searchDepth":218,"depth":218,"links":8769},[8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781],{"id":8575,"depth":218,"text":8576},{"id":8625,"depth":218,"text":8626},{"id":8644,"depth":218,"text":8645},{"id":8657,"depth":218,"text":8658},{"id":8670,"depth":218,"text":8671},{"id":8686,"depth":218,"text":8687},{"id":8699,"depth":218,"text":8700},{"id":8714,"depth":218,"text":8715},{"id":8727,"depth":218,"text":8728},{"id":8740,"depth":218,"text":8741},{"id":8747,"depth":218,"text":8748},{"id":8757,"depth":218,"text":8758},"2022-01-23","10 ting jeg ville have fortalt mig selv som frontend-udvikler og som menneske! Lær af mine fejl og få et forspring i din karriere.",{},"\u002Fblog\u002F10-raad-til-mit-yngre-jeg-som-udvikler",{"title":8567,"description":8783},"10 ting jeg ville have fortalt mig selv som frontend-udvikler og som menneske. Lær af mine fejl og få et forspring i din karriere.","10-raad-til-mit-yngre-jeg-som-udvikler","blog\u002F10-raad-til-mit-yngre-jeg-som-udvikler",[246,2441],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*Hw6m0PrRJbytXTt41U_oPA.png","D7A2MgtCigVvmjsz1yVAsxHJASescVt0UhI8Ej1i10s",{"id":8794,"title":8795,"body":8796,"date":9030,"description":9031,"extension":236,"meta":9032,"navigation":238,"noindex":8,"path":9033,"seo":9034,"seoDescription":9035,"seoTitle":9036,"slug":9037,"stem":9038,"tags":9039,"thumbnail":1000,"updated":234,"__hash__":9041},"blog\u002Fblog\u002Ftypescript-er-det-virkelig-sa-godt.md","TypeScript i 2026 — Fra kontroversielt til uundværligt",{"type":40,"value":8797,"toc":9013},[8798,8802,8805,8808,8812,8815,8840,8853,8857,8861,8864,8890,8894,8901,8904,8908,8914,8918,8922,8928,8938,8942,8947,8952,8956,8962,8966,8969,8989,8992,8996,8999,9002,9005,9007,9010],[43,8799,8801],{"id":8800},"opdatering-2026-meget-har-ændret-sig","Opdatering 2026: Meget har ændret sig",[48,8803,8804],{},"I 2021 skrev jeg den originale version af denne artikel, hvor jeg stillede spørgsmålet: \"Er TypeScript virkelig så godt?\" Dengang var mit svar nuanceret — ja, det har fordele, men det øger kompleksiteten og er ikke altid det rigtige valg.",[48,8806,8807],{},"I 2026 er billedet et helt andet. TypeScript er gået fra at være et kontroversielt valg til at være den ubestridte standard for professionel JavaScript-udvikling. Lad mig forklare hvad der har ændret sig.",[43,8809,8811],{"id":8810},"typescript-er-nu-industristandard","TypeScript er nu industristandard",[48,8813,8814],{},"Tallene taler for sig selv. Stort set alle større frameworks og biblioteker er skrevet i TypeScript eller har førsteklasses TypeScript-support:",[625,8816,8817,8823,8829,8834],{},[628,8818,8819,8822],{},[67,8820,8821],{},"Vue 3"," — Skrevet i TypeScript fra bunden",[628,8824,8825,8828],{},[67,8826,8827],{},"Next.js og Nuxt 3"," — TypeScript som default",[628,8830,8831,8833],{},[67,8832,1320],{}," — Har altid krævet TypeScript",[628,8835,8836,8839],{},[67,8837,8838],{},"Alle store UI-biblioteker"," — Har TypeScript-definitioner som standard",[48,8841,8842,8843,687,8846,871,8849,8852],{},"Når du opretter et nyt projekt med ",[287,8844,8845],{},"create-next-app",[287,8847,8848],{},"nuxi init",[287,8850,8851],{},"ng new",", får du TypeScript som standard. Det er ikke længere et tilvalg — det er udgangspunktet.",[43,8854,8856],{"id":8855},"hvad-har-ændret-sig-siden-2021","Hvad har ændret sig siden 2021?",[119,8858,8860],{"id":8859},"kompleksiteten-er-blevet-lavere","Kompleksiteten er blevet lavere",[48,8862,8863],{},"I 2021 skrev jeg at TypeScript øger kompleksiteten. Det var sandt dengang. Men flere ting har gjort det markant nemmere:",[625,8865,8866,8872,8878,8884],{},[628,8867,8868,8871],{},[67,8869,8870],{},"Bedre type inference"," — TypeScript er blevet langt bedre til at udlede typer automatisk, så du sjældent skal skrive eksplicitte typer",[628,8873,8874,8877],{},[67,8875,8876],{},"Framework-integration"," — Vue 3, Nuxt 3 og andre frameworks har dyb TypeScript-integration der \"bare virker\"",[628,8879,8880,8883],{},[67,8881,8882],{},"IDE-support"," — VS Code og andre editorer giver dig auto-complete, fejlmarkering og refactoring der gør dig hurtigere, ikke langsommere",[628,8885,8886,8889],{},[67,8887,8888],{},"Simplere konfiguration"," — Moderne frameworks klarer TypeScript-opsætningen for dig. Du behøver ikke rode med tsconfig eller build-pipelines",[119,8891,8893],{"id":8892},"alle-kan-typescript-nu","Alle kan TypeScript nu",[48,8895,8896,8897,8900],{},"I 2021 nævnte jeg at mange dygtige JavaScript-udviklere ikke kunne TypeScript. I 2026 er det svært at finde en professionel frontend-udvikler der ",[167,8898,8899],{},"ikke"," kender TypeScript. Det er blevet en grundlæggende kompetence på linje med at kende HTML og CSS.",[48,8902,8903],{},"Jobopslag der kræver \"JavaScript\" kræver nu næsten altid også TypeScript. Det er ikke længere et nicheværktøj — det er pensum.",[119,8905,8907],{"id":8906},"ai-værktøjer-elsker-typescript","AI-værktøjer elsker TypeScript",[48,8909,8910,8911,8913],{},"En af de mest overraskende fordele ved TypeScript i 2026 er hvordan det spiller sammen med AI-assisterede udviklingsværktøjer. Typer giver AI-værktøjer kontekst til at generere mere præcis og korrekt kode. Når en AI kan se at en funktion forventer et ",[287,8912,377],{},"-objekt med specifikke felter, bliver forslagene markant bedre.",[43,8915,8917],{"id":8916},"de-oprindelige-argumenter-holder-de-stadig","De oprindelige argumenter — holder de stadig?",[119,8919,8921],{"id":8920},"typescript-øger-kompleksiteten","\"TypeScript øger kompleksiteten\"",[48,8923,8924,8927],{},[67,8925,8926],{},"2021:"," Ja, det tilføjer et ekstra lag man skal lære og forholde sig til.",[48,8929,8930,8933,8934,8937],{},[67,8931,8932],{},"2026:"," TypeScript ",[167,8935,8936],{},"reducerer"," kompleksitet i praksis. Når din kodebase vokser, er typer det der holder den håndterbar. Uden TypeScript ender man med at bruge tid på at læse kode for at forstå hvad en funktion forventer — med TypeScript er det eksplicit og verificeret.",[119,8939,8941],{"id":8940},"typescript-gør-projektet-dyrere","\"TypeScript gør projektet dyrere\"",[48,8943,8944,8946],{},[67,8945,8926],{}," Mere kode = mere tid = højere pris.",[48,8948,8949,8951],{},[67,8950,8932],{}," TypeScript sparer tid og penge. Fejl fanges før de når produktion. Refactoring er sikrere og hurtigere. Onboarding af nye udviklere går hurtigere fordi koden er selvdokumenterende. På større projekter er det en investering der betaler sig mange gange.",[119,8953,8955],{"id":8954},"typescript-minimerer-ikke-testing","\"TypeScript minimerer ikke testing\"",[48,8957,8958,8961],{},[67,8959,8960],{},"2021 og 2026:"," Dette holder stadig. TypeScript fanger type-fejl, men du har stadig brug for tests til forretningslogik, integrations-flows og edge cases. TypeScript og tests komplementerer hinanden — de erstatter ikke hinanden.",[43,8963,8965],{"id":8964},"hvornår-giver-typescript-ikke-mening","Hvornår giver TypeScript ikke mening?",[48,8967,8968],{},"Selvom TypeScript er blevet standarden, er der stadig scenarier hvor det kan være overkill:",[625,8970,8971,8977,8983],{},[628,8972,8973,8976],{},[67,8974,8975],{},"Hurtige prototyper og proof-of-concepts"," — Når hastighed er vigtigere end korrekthed",[628,8978,8979,8982],{},[67,8980,8981],{},"Meget simple scripts"," — Et lille build-script eller en engangs-utility behøver ikke typer",[628,8984,8985,8988],{},[67,8986,8987],{},"Eksisterende JavaScript-kodebase"," — Migration til TypeScript er en investering. Det skal være en bevidst beslutning, ikke noget man gør halvhjertet",[48,8990,8991],{},"Men for alle nye professionelle projekter? TypeScript er det oplagte valg.",[43,8993,8995],{"id":8994},"min-egen-rejse-med-typescript","Min egen rejse med TypeScript",[48,8997,8998],{},"Jeg har brugt TypeScript dagligt i mange år nu — fra SaaS-platforme hos Playable til enterprise-løsninger hos Harness. Min holdning har ændret sig fra \"det er ok, men kig på ulemperne\" til \"jeg ville ikke starte et projekt uden det.\"",[48,9000,9001],{},"Det er ikke fordi ulemperne er væk. Det er fordi fordelene er blevet så store, og værktøjerne så modne, at regnestykket er helt anderledes end i 2021.",[48,9003,9004],{},"TypeScript i 2026 er ikke det samme værktøj som i 2021. Det er hurtigere, smartere og nemmere at bruge. Og det er kommet for at blive.",[43,9006,1348],{"id":1347},[48,9008,9009],{},"Hvis du stadig overvejer om TypeScript er det rigtige for dit næste projekt: ja, det er det. Økosystemet, værktøjerne og branchen har gjort valget for dig. TypeScript er ikke længere et tilvalg — det er fundamentet for moderne webudvikling.",[48,9011,9012],{},"Har du spørgsmål om TypeScript eller brug for hjælp med at komme i gang? Skriv til mig — jeg deler gerne mine erfaringer.",{"title":217,"searchDepth":218,"depth":218,"links":9014},[9015,9016,9017,9022,9027,9028,9029],{"id":8800,"depth":218,"text":8801},{"id":8810,"depth":218,"text":8811},{"id":8855,"depth":218,"text":8856,"children":9018},[9019,9020,9021],{"id":8859,"depth":226,"text":8860},{"id":8892,"depth":226,"text":8893},{"id":8906,"depth":226,"text":8907},{"id":8916,"depth":218,"text":8917,"children":9023},[9024,9025,9026],{"id":8920,"depth":226,"text":8921},{"id":8940,"depth":226,"text":8941},{"id":8954,"depth":226,"text":8955},{"id":8964,"depth":218,"text":8965},{"id":8994,"depth":218,"text":8995},{"id":1347,"depth":218,"text":1348},"2021-02-05","I 2021 skrev jeg om hvorvidt TypeScript var det værd. I 2026 er svaret klart. Her er hvad der har ændret sig, og hvad du skal vide om TypeScript i dag.",{},"\u002Fblog\u002Ftypescript-er-det-virkelig-sa-godt",{"title":8795,"description":9031},"Fra kontroversielt til uundværligt: TypeScript er blevet standarden i professionel webudvikling. Lær hvorfor, og hvad du skal vide om TypeScript i 2026.","TypeScript i 2026 — Derfor er det blevet industristandard","typescript-er-det-virkelig-sa-godt","blog\u002Ftypescript-er-det-virkelig-sa-godt",[328,1392,9040,995],"udvikling","qAAxG8aErZMrfe3b7TB9PJsbA0iT8ERZ3eaD0IBTwzE",{"id":9043,"title":9044,"body":9045,"date":9469,"description":9470,"extension":236,"meta":9471,"navigation":238,"noindex":8,"path":9472,"seo":9473,"seoDescription":9474,"seoTitle":9475,"slug":9476,"stem":9477,"tags":9478,"thumbnail":9481,"updated":234,"__hash__":9482},"blog\u002Fblog\u002Fhvad-koster-en-hjemmeside.md","Hvad koster en hjemmeside i 2026?",{"type":40,"value":9046,"toc":9447},[9047,9051,9054,9057,9060,9064,9068,9073,9090,9093,9097,9102,9122,9125,9129,9134,9154,9157,9161,9166,9186,9189,9193,9196,9200,9211,9215,9226,9230,9241,9245,9256,9260,9263,9283,9287,9290,9293,9313,9317,9360,9364,9367,9370,9384,9387,9401,9404,9408,9440,9444],[43,9048,9050],{"id":9049},"det-korte-svar-det-kommer-an-på","Det korte svar: Det kommer an på",[48,9052,9053],{},"Jeg har fået dette spørgsmål hundredvis af gange i løbet af mine 19+ år som webudvikler, og svaret er altid det samme: det afhænger af dine behov, ambitioner og krav.",[48,9055,9056],{},"Man kan sammenligne det med at spørge \"hvad koster en bil?\" — er det en VW Up eller en Porsche? Selv indenfor samme mærke varierer prisen enormt alt efter udstyr og specifikationer.",[48,9058,9059],{},"Det samme gælder for hjemmesider. Men lad mig give dig et realistisk overblik over prislejer i 2026.",[43,9061,9063],{"id":9062},"prisoverslag-for-hjemmesider-i-2026","Prisoverslag for hjemmesider i 2026",[119,9065,9067],{"id":9066},"simpel-hjemmeside-wordpresstemplate","Simpel hjemmeside (WordPress\u002Ftemplate)",[48,9069,9070],{},[67,9071,9072],{},"Pris: 10.000 - 30.000 DKK",[625,9074,9075,9078,9081,9084,9087],{},[628,9076,9077],{},"Template-baseret design (fx WordPress med et købt tema)",[628,9079,9080],{},"5-10 undersider",[628,9082,9083],{},"Kontaktformular",[628,9085,9086],{},"Basalt responsivt design",[628,9088,9089],{},"Minimal tilpasning",[48,9091,9092],{},"Pas på: I denne prisklasse får du oftest en standardløsning med begrænset kvalitet. Mange udbydere installerer blot et tema og tilpasser farver og indhold. Det kan være fint til en helt simpel tilstedeværelse, men forvent ikke høj hastighed, god SEO eller unikt design.",[119,9094,9096],{"id":9095},"professionel-hjemmeside-skræddersyet","Professionel hjemmeside (skræddersyet)",[48,9098,9099],{},[67,9100,9101],{},"Pris: 40.000 - 120.000 DKK",[625,9103,9104,9107,9110,9113,9116,9119],{},[628,9105,9106],{},"Skræddersyet design tilpasset din virksomhed",[628,9108,9109],{},"Responsivt og optimeret til alle devices",[628,9111,9112],{},"SEO-optimeret struktur og indhold",[628,9114,9115],{},"CMS-integration (så du selv kan redigere indhold)",[628,9117,9118],{},"Performance-optimering",[628,9120,9121],{},"Basalt analytics-setup",[48,9123,9124],{},"Her får du en hjemmeside der er bygget specifikt til din virksomhed og dine brugere. Designet er unikt, koden er skrevet fra bunden, og der er taget højde for hastighed, SEO og brugeroplevelse.",[119,9126,9128],{"id":9127},"webshop","Webshop",[48,9130,9131],{},[67,9132,9133],{},"Pris: 50.000 - 200.000+ DKK",[625,9135,9136,9139,9142,9145,9148,9151],{},[628,9137,9138],{},"Alt fra den professionelle hjemmeside",[628,9140,9141],{},"Produktkatalog og kategoristyring",[628,9143,9144],{},"Betalingsløsning (Stripe, Nets, MobilePay)",[628,9146,9147],{},"Ordrestyring og lagerstyring",[628,9149,9150],{},"Fragtberegning og forsendelse",[628,9152,9153],{},"Integration til regnskabssystem",[48,9155,9156],{},"Prisen afhænger i høj grad af antal produkter, kompleksitet i produktvarianter, og hvilke integrationer der er behov for. En webshop med 50 produkter er en helt anden opgave end en med 10.000+ produkter.",[119,9158,9160],{"id":9159},"web-applikation-saas-platform","Web-applikation \u002F SaaS-platform",[48,9162,9163],{},[67,9164,9165],{},"Pris: 150.000 - 500.000+ DKK",[625,9167,9168,9171,9174,9177,9180,9183],{},[628,9169,9170],{},"Brugertilmelding og login-system",[628,9172,9173],{},"Kompleks funktionalitet og forretningslogik",[628,9175,9176],{},"API-integrationer",[628,9178,9179],{},"Skalerbar arkitektur",[628,9181,9182],{},"Sikkerhed og databeskyttelse",[628,9184,9185],{},"Løbende videreudvikling",[48,9187,9188],{},"Denne type projekt er software-udvikling, ikke \"bare\" en hjemmeside. Her taler vi om digitale produkter der kører en forretning.",[43,9190,9192],{"id":9191},"hvad-påvirker-prisen","Hvad påvirker prisen?",[48,9194,9195],{},"Der er en lang række faktorer der påvirker prisen på en hjemmeside. Her er de vigtigste:",[119,9197,9199],{"id":9198},"design-og-kompleksitet","Design og kompleksitet",[625,9201,9202,9205,9208],{},[628,9203,9204],{},"Skal det være et unikt, skræddersyet design, eller er et template tilstrækkeligt?",[628,9206,9207],{},"Hvor mange undersider er der behov for?",[628,9209,9210],{},"Er der behov for animationer, interaktive elementer eller avanceret layout?",[119,9212,9214],{"id":9213},"funktionalitet","Funktionalitet",[625,9216,9217,9220,9223],{},[628,9218,9219],{},"Skal der være integrationer til tredjeparts-systemer (CRM, ERP, betalingsgateway)?",[628,9221,9222],{},"Er der behov for brugerlogin, booking, prisberegner eller andre specialfunktioner?",[628,9224,9225],{},"Skal du selv kunne opdatere indhold via et CMS?",[119,9227,9229],{"id":9228},"seo-og-performance","SEO og performance",[625,9231,9232,9235,9238],{},[628,9233,9234],{},"Skal hjemmesiden optimeres til søgemaskiner?",[628,9236,9237],{},"Er hastighed en prioritet? (Hint: det bør det altid være)",[628,9239,9240],{},"Skal der være struktureret data og schema markup?",[119,9242,9244],{"id":9243},"vedligeholdelse-og-support","Vedligeholdelse og support",[625,9246,9247,9250,9253],{},[628,9248,9249],{},"Hvem tager sig af opdateringer og sikkerhed efter lancering?",[628,9251,9252],{},"Er der behov for løbende support og videreudvikling?",[628,9254,9255],{},"Skal der være en serviceaftale?",[119,9257,9259],{"id":9258},"ai-påvirkning-på-priser-i-2026","AI-påvirkning på priser i 2026",[48,9261,9262],{},"AI-værktøjer har ændret landskabet for webudvikling. Nogle enkle opgaver kan nu laves hurtigere, men det har også øget forventningerne til kvalitet. Her er hvad du skal vide:",[625,9264,9265,9271,9277],{},[628,9266,9267,9270],{},[67,9268,9269],{},"AI kan hjælpe med prototyping og kode"," — Men det kræver en erfaren udvikler at bruge AI-værktøjer effektivt og sikre kvaliteten",[628,9272,9273,9276],{},[67,9274,9275],{},"Template-markedet er blevet større"," — Der er flere billige løsninger end nogensinde, men kvalitetsforskellen er også blevet større",[628,9278,9279,9282],{},[67,9280,9281],{},"Kompleksiteten er steget"," — Forventninger til hastighed, SEO, tilgængelighed og brugeroplevelse er højere end nogensinde",[43,9284,9286],{"id":9285},"kravspecifikation-dit-vigtigste-værktøj","Kravspecifikation: Dit vigtigste værktøj",[48,9288,9289],{},"Inden du indhenter tilbud, bør du udarbejde en kravspecifikation. Det er en beskrivelse af hvad din hjemmeside skal kunne, hvordan den skal se ud, og hvem den henvender sig til.",[48,9291,9292],{},"En god kravspecifikation hjælper dig med at:",[625,9294,9295,9301,9307],{},[628,9296,9297,9300],{},[67,9298,9299],{},"Få sammenlignelige tilbud"," — Uden en kravspec sammenligner du æbler og pærer",[628,9302,9303,9306],{},[67,9304,9305],{},"Undgå scope creep"," — Klare rammer forebygger at projektet vokser ukontrolleret",[628,9308,9309,9312],{},[67,9310,9311],{},"Sætte realistiske forventninger"," — Både for dig og for udvikleren",[119,9314,9316],{"id":9315},"hvad-skal-en-kravspecifikation-indeholde","Hvad skal en kravspecifikation indeholde?",[625,9318,9319,9325,9331,9337,9342,9348,9354],{},[628,9320,9321,9324],{},[67,9322,9323],{},"Formål"," — Hvad skal hjemmesiden opnå for din forretning?",[628,9326,9327,9330],{},[67,9328,9329],{},"Målgruppe"," — Hvem er dine brugere?",[628,9332,9333,9336],{},[67,9334,9335],{},"Sider og indhold"," — Hvilke sider er der behov for, og hvad skal de indeholde?",[628,9338,9339,9341],{},[67,9340,9214],{}," — Kontaktformular, booking, webshop, login, integrationer?",[628,9343,9344,9347],{},[67,9345,9346],{},"Design"," — Har du et eksisterende brand\u002Fdesignguide, eller skal der laves nyt design?",[628,9349,9350,9353],{},[67,9351,9352],{},"Tekniske krav"," — Hastighed, SEO, browsersupport, tilgængelighed?",[628,9355,9356,9359],{},[67,9357,9358],{},"Budget og tidsplan"," — Hvad er dit budget, og hvornår skal løsningen være klar?",[43,9361,9363],{"id":9362},"pris-og-kvalitet-hænger-sammen","Pris og kvalitet hænger sammen",[48,9365,9366],{},"Det er fristende at vælge den billigste løsning, men i webudvikling får du næsten altid hvad du betaler for.",[48,9368,9369],{},"En hjemmeside til 10.000 DKK er formentlig:",[625,9371,9372,9375,9378,9381],{},[628,9373,9374],{},"Et standardiseret WordPress-tema med minimal tilpasning",[628,9376,9377],{},"Langsom og dårligt optimeret",[628,9379,9380],{},"Uden SEO-strategi",[628,9382,9383],{},"Svær at vedligeholde og videreudvikle",[48,9385,9386],{},"En hjemmeside til 60.000+ DKK bør give dig:",[625,9388,9389,9392,9395,9398],{},[628,9390,9391],{},"Et unikt design tilpasset din virksomhed",[628,9393,9394],{},"Hurtig load-tid og god performance",[628,9396,9397],{},"SEO-optimeret struktur",[628,9399,9400],{},"En løsning der kan vokse med din forretning",[48,9402,9403],{},"Tænk på din hjemmeside som en investering, ikke en udgift. For de fleste virksomheder er hjemmesiden omdrejningspunktet for al digital kommunikation. Den skal stå skarpt.",[43,9405,9407],{"id":9406},"gode-råd-inden-du-køber","Gode råd inden du køber",[660,9409,9410,9416,9422,9428,9434],{},[628,9411,9412,9415],{},[67,9413,9414],{},"Lav en kravspecifikation"," — Selv en simpel. Det sparer dig tid og penge",[628,9417,9418,9421],{},[67,9419,9420],{},"Indhent 2-3 tilbud"," — Sammenlign ikke bare pris, men også erfaring, referencer og proces",[628,9423,9424,9427],{},[67,9425,9426],{},"Spørg ind til teknologi"," — Hvad bliver det bygget i, og kan det vedligeholdes af andre?",[628,9429,9430,9433],{},[67,9431,9432],{},"Tænk langsigtet"," — En billig løsning nu kan blive dyr på sigt, hvis den skal bygges om",[628,9435,9436,9439],{},[67,9437,9438],{},"Prioriter hastighed og SEO"," — Det er ikke nice-to-have, det er afgørende for din synlighed",[43,9441,9443],{"id":9442},"har-du-brug-for-et-tilbud","Har du brug for et tilbud?",[48,9445,9446],{},"Har du et projekt du gerne vil have et prisoverslag på? Tag kontakt, så tager vi en uforpligtende snak om dine behov og muligheder.",{"title":217,"searchDepth":218,"depth":218,"links":9448},[9449,9450,9456,9463,9466,9467,9468],{"id":9049,"depth":218,"text":9050},{"id":9062,"depth":218,"text":9063,"children":9451},[9452,9453,9454,9455],{"id":9066,"depth":226,"text":9067},{"id":9095,"depth":226,"text":9096},{"id":9127,"depth":226,"text":9128},{"id":9159,"depth":226,"text":9160},{"id":9191,"depth":218,"text":9192,"children":9457},[9458,9459,9460,9461,9462],{"id":9198,"depth":226,"text":9199},{"id":9213,"depth":226,"text":9214},{"id":9228,"depth":226,"text":9229},{"id":9243,"depth":226,"text":9244},{"id":9258,"depth":226,"text":9259},{"id":9285,"depth":218,"text":9286,"children":9464},[9465],{"id":9315,"depth":226,"text":9316},{"id":9362,"depth":218,"text":9363},{"id":9406,"depth":218,"text":9407},{"id":9442,"depth":218,"text":9443},"2021-02-02","Hvad koster det at få lavet en hjemmeside? Priserne varierer enormt, og der er mange faktorer der spiller ind. Her får du et realistisk overblik over priser og hvad der påvirker dem.",{},"\u002Fblog\u002Fhvad-koster-en-hjemmeside",{"title":9044,"description":9470},"Hvad koster en hjemmeside i 2026? Fra simple WordPress-sider til skræddersyede løsninger. Få et realistisk overblik over priser, faktorer der påvirker prisen, og råd til at finde den rigtige løsning.","Hvad koster en hjemmeside i 2026? Priser og prisoverslag","hvad-koster-en-hjemmeside","blog\u002Fhvad-koster-en-hjemmeside",[9479,2004,2005,9480],"pris","hjemmeside","\u002Fimages\u002Fcontentful\u002Fblog-pris-hjemmeside.png","-FI28IRldFkjAtLVTjSPWOWnJcBSNOFGxNj8tYBI_u4",{"id":9484,"title":9485,"body":9486,"date":9569,"description":9490,"extension":236,"meta":9570,"navigation":238,"noindex":8,"path":9571,"seo":9572,"seoDescription":9490,"seoTitle":9485,"slug":9573,"stem":9574,"tags":9575,"thumbnail":9578,"updated":9569,"__hash__":9579},"blog\u002Fblog\u002Fjeg-har-skrevet-en-wordpress-bog.md","Jeg har skrevet en WordPress bog!",{"type":40,"value":9487,"toc":9567},[9488,9491,9505,9508,9511,9514,9517,9520,9525,9528,9531,9534,9537,9540,9554,9557,9564],[48,9489,9490],{},"Ja, den er god nok. Jeg har skrevet en bog.",[48,9492,9493,9494,9499,9500,1956],{},"Det er en bog om WordPress og den kan kobes direkte pa ",[966,9495,9498],{"href":9496,"rel":9497},"https:\u002F\u002Fwww.saxo.com\u002Fdk\u002Fwordpress-guiden_pdf_9788740459036",[4114],"Saxo",", eller pa ",[966,9501,9504],{"href":9502,"rel":9503},"https:\u002F\u002Fwordpress-guiden.dk",[4114],"WordPress Guiden",[48,9506,9507],{},"I bogen laerer man at lave en simpel hjemmeside eller webshop, uden at have behov for at kunne udvikle\u002Fkode selv.",[48,9509,9510],{},"Bogen hedder \"WordPress Guiden - Laer at lav din egen profesionelle hjemmeside eller webshop\", og henvender sig til folk som gerne vil prove at kaste sig ud i selv at lave egen hjemmeside eller webshop med WordPress og WooCommerce.",[48,9512,9513],{},"Bogen er egentlig skrevet en smule i protest, da jeg ser rigtigt mange sma virksomheder kalde sig selv WordPress eksperter og som lover dig den absolute bedste hjemmeside, og som tager sig rigtig godt betalt for simpelt arbejde som de fleste faktisk selv kunne klare med lidt hjaelp og vejledning.",[48,9515,9516],{},"Ser du, WordPress er nemlig et CMS system hvortil der findes noget som hedder temaer, og ved nogle fa klik og installering af et tema kan man altsa have en hjemmeside up-and-running ret hurtigt, ogsa har man faktisk en hjemmeside. Der findes et hav af steder man kan tilkobe temaer, som fx themeforest.net",[48,9518,9519],{},"Derfra har man sa stadig ikke en saerlig god hjemmeside, da temaer i WordPress oftest er fyldt op med alt muligt ubrugeligt som blandt andet slover hjemmesiden gevaldigt.",[48,9521,9522],{},[67,9523,9524],{},"Man laerer naturligvis ikke at bygge hjemmeside eller webshop som jeg selv, da det kraever mange ars laering og erfaring, og kraever at du selv kan kode\u002Fprogrammere.",[48,9526,9527],{},"Kort fortalt henvender bogen sig til: ikke teknisk kyndige personer, men som gerne vil prove at give sig i kast med selv at lave en simpel hjemmeside.\nSom naevnt, er grunden til at jeg skrev bogen, var at jeg gerne vil hjaelpe folk som selv onsker at prove at kaste sig ud i at lave en simpel hjemmeside, som ikke har eller behover at have de tekniske evner. Samt onsker jeg at give folk muligheden for at spare penge ved IKKE at skulle ud og betale nogle \"sakaldte wordpress eksperter\" for at gore noget som man relativt nemt selv kan klare.",[48,9529,9530],{},"Naturligvis far man ikke en professionel hjemmeside som man ville fa som hvis man gik til en professionel udvikler eller bureau, men bogen laerer dig hvordan du bruger WordPress, samt hvordan du far bygget en flot, men simpel hjemmeside. Den laerer dig endda ogsa hvordan du laver en webshop som kan tage imod kortbetaling med WooCommerce.",[48,9532,9533],{},"I bogen laerer man mere eller mindre alt om Wordpress og dets administration, herunder installering og brug af temaer og plugins, shortcodes, hastighedsoptimering og mange andre brugbare ting.",[48,9535,9536],{},"Bogen kan erhverves for kun 129,- DKK.",[48,9538,9539],{},"Jeg vil personligt selv sige at bogen er ideel til:",[625,9541,9542,9545,9548,9551],{},[628,9543,9544],{},"Influencers\u002Fbloggere\u002Fprivate personer",[628,9546,9547],{},"Den lille virksomhed som har behov for et simpelt website",[628,9549,9550],{},"Personen som gerne vil laere mere om WordPress og hvordan det virker.",[628,9552,9553],{},"Personer der har behov for en lille og simpel webshop",[48,9555,9556],{},"Bogen er omkring 214 sider, og tager man sig tiden til at laese, forsta og laere, kan man vaere i stand til at selv lave en simpel hjemmeside eller webshop nar man er faerdig med nogen.",[48,9558,9559,9560],{},"Det er naturligvis ogsa muligt at fa en light udgave helt gratis.\n",[966,9561,9563],{"href":9502,"rel":9562},[4114],"Laes meget mere om hele bogen pa WordPress Guiden",[48,9565,9566],{},"Bemaerk, onsker du en professionel hjemmeside der bade er hurtig, SEO venlig, skraeddersyet mv, sa er det ikke denne bog du skal kobe. Jeg vil til enhver tid anbefale dig at bruge professionelle kraefter hvis du onsker en professionel hjemmeside eller webshop.",{"title":217,"searchDepth":218,"depth":218,"links":9568},[],"2021-01-23",{},"\u002Fblog\u002Fjeg-har-skrevet-en-wordpress-bog",{"title":9485,"description":9490},"jeg-har-skrevet-en-wordpress-bog","blog\u002Fjeg-har-skrevet-en-wordpress-bog",[9576,9577],"wordpress","bog","\u002Fimages\u002Fcontentful\u002Fblog-bog.jpg","PS2Kg7l6SWR1PJJqwVdAUi_NXizGdyovlCJPflqD-1o",{"id":9581,"title":9582,"body":9583,"date":9805,"description":9806,"extension":236,"meta":9807,"navigation":238,"noindex":238,"path":9808,"seo":9809,"seoDescription":9806,"seoTitle":9582,"slug":9810,"stem":9811,"tags":9812,"thumbnail":9814,"updated":9805,"__hash__":9815},"blog\u002Fblog\u002Fupload-filer-til-cooudinary-med-vue-and-vuetify.md","Upload filer til Cloudinary med Vue & Vuetify",{"type":40,"value":9584,"toc":9803},[9585,9588,9591,9594,9597,9600,9606,9613,9619,9632,9638,9647,9650,9656,9663,9666,9672,9675,9681,9684,9687,9693,9704,9707,9714,9720,9726,9729,9735,9741,9747,9750,9756,9763,9766,9772,9775,9778,9784,9787,9795],[48,9586,9587],{},"For noget tid siden arbejdede jeg pa en SaaS platform hvor man blandt andet nemt skulle kunne uploade filer til en server. Valget faldt pa Cloudinary, og kravet var at selve upload delen skulle ske via klienten (browseren). Dette betod der var 2 mader at handtere det pa, enten ved at benytte Cloudinarys egen upload widget eller ved at bygge det selv. Jeg valgte at bygge det selv, da upload widgetten fra Cloudinary er stor i filstorrelse, har ringe performance, og ikke har mange muligheder for styling.",[48,9589,9590],{},"Nar projektet er blevet oprettet skal Vuetify tilfojes til projektet, ogsa via terminalen \"vue add vuetify\" - Vaelg \"default\" setup, og du er korende.",[48,9592,9593],{},"Super, nu hvor der er et projekt, kan vi komme igang med lidt udvikling.",[48,9595,9596],{},"Start med at abn dit favorit IDE, personligt selv benytter jeg WebStorm.",[48,9598,9599],{},"Rediger filen App.vue, da vi lige have fjernet lidt boilerplate kode herfra. Din fil ma gerne ligne dette:",[280,9601,9604],{"className":9602,"code":9603,"language":285},[283],"\u003Ctemplate>\n  \u003Cv-app>\n    \u003Cv-app-bar\n            app\n            color=\"primary\"\n            dark>\n    \u003C\u002Fv-app-bar>\n    \u003Cv-content>\n        \u003C!-- Upload file here -->\n    \u003C\u002Fv-content>\n  \u003C\u002Fv-app>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  export default {\n    name: 'App',\n    data: () => ({\n    \u002F\u002F\n    }),\n  };\n\u003C\u002Fscript>\n",[287,9605,9603],{"__ignoreMap":217},[48,9607,9608,9609],{},"Nu hvor vores App.vue fil er helt ren for boilerplate kode kan vi starte.\nFor at kunne uploade filer til Cloudinary skal vi bruge et input element af typen \"file\". I dette tilfaelde er Vuetify installeret i vores losning, hvorfor vi kan bruge komponenten ",[9610,9611,9612],"v-file-input",{}," (Se dokumentation her pa komponenten)",[48,9614,9615,9616],{},"Denne komponent tilfojer vi til ",[167,9617,9618],{},"v-content",[48,9620,9621,9622,9624,9625,9628,9629,1956],{},"Komponenten skal vaere bundet op pa et @change event. Dette er fordi vi gerne vil fange de filer som komponenten returnere nar vi har valgt nogle filer fra filsystemet.\nTilføj en funktion til ",[167,9623,3507],{},". Jeg navngiver funktionen ",[67,9626,9627],{},"onAddFiles()"," - Herefter skal den bindes til komponenten via ",[167,9630,9631],{},"@change",[280,9633,9636],{"className":9634,"code":9635,"language":285},[283],"\u003Cv-content>\n  \u003Ch1>\n    Upload file to Cloudinary\n  \u003C\u002Fh1>\n  \u003Cv-file-input multiple label=\"Add your files\" chips @change=\"onAddFiles\" \u002F>\n\u003C\u002Fv-content>\n",[287,9637,9635],{"__ignoreMap":217},[48,9639,9640,9641,9643,9644],{},"I ",[67,9642,9627],{}," funktionen skal der tilfojes et parameter. Dette parameter vil i sidste ende indeholde de filer som bliver valgt fra filsystemet. Filerne bliver sendt komponenten ",[9610,9645,9646],{}," og returnere et array af File Objects til selve funktionen.",[48,9648,9649],{},"Som du kan se i koden, skriver vi til console.log, hvilket gor vi i vores browser kan se hvad der bliver returneret til konsollen. Prov det af og se hvad der sker i dit tilfaelde.",[280,9651,9654],{"className":9652,"code":9653,"language":285},[283],"\u003Ctemplate>\n  \u003Cv-app>\n    \u003Cv-app-bar\n    app\n    color=\"primary\"\n    dark>\n  \u003C\u002Fv-app-bar>\n  \u003Cv-content>\n\u003Ch1>\nUpload file to Cloudinary\n\u003C\u002Fh1>\n\u003Cv-file-input multiple label=\"Add your files\" chips @change=\"onAddFiles\" \u002F>\n\u003C\u002Fv-content>\n\u003C\u002Fv-app>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  export default {\n    name: 'App',\n    data: () => ({\n    }),\n    methods: {\n      onAddFiles(files) {\n        window.console.log(files);\n      }\n    }\n  };\n\u003C\u002Fscript>\n",[287,9655,9653],{"__ignoreMap":217},[48,9657,9658,9659,9662],{},"Du skulle gerne fa et ",[167,9660,9661],{},"array"," af filer vist i konsollen. Dette betyder nemlig at det virker indtil videre, og at vi har noget data at arbejde med. Naeste skridt er at vi skal tage hver fil vi tilfojer og uploade filen til Cloudinary.",[48,9664,9665],{},"Hvis ikke du allerede har en konto hos Cloudinary, sa opret den nu. Det er gratis.\nNar du har oprettet din konto er der et par ting vi skal bruge herfra.\nGa til Settings -> upload, og klik pa \"Enable unsigned uploads\"",[48,9667,9668],{},[3592,9669],{"alt":9670,"src":9671},"cloudinary-1","\u002Fimages\u002Fcontentful\u002Fcloudinary-1.png",[48,9673,9674],{},"Det skaber et upload preset som vi skal bruge for at kunne fa lov at uploade filer. Dette skal senere hen tilfojes til koden sammen med vores \"API base url\". URL hertil kan du finde under \"Dashboard -> Account Details\"",[48,9676,9677],{},[3592,9678],{"alt":9679,"src":9680},"cloudinary-2","\u002Fimages\u002Fcontentful\u002Fcloudinary-2.png",[48,9682,9683],{},"Nu hvor vi har de 2 vaerdier, kan vi ga tilbage til vores kode.",[48,9685,9686],{},"Cloudinary understotter desvaerre ikke at man kan sende et array af filer til deres API, hvorfor det er nodvendigt at loope igennem alle filer, og tilføje hver enkelt.",[280,9688,9691],{"className":9689,"code":9690,"language":285},[283],"onAddFiles(files) {\n  if(files.length > 0) {\n    files.forEach((file) => {\n      window.console.log(file);\n    });\n }\n}\n",[287,9692,9690],{"__ignoreMap":217},[48,9694,9695,9696,9699,9700,9703],{},"Som du kan se, looper vi over ",[167,9697,9698],{},"files"," og dermed kan fange hver ",[167,9701,9702],{},"file",". Det naeste der skal klares er at vi skal have lavet en funktion der kan tage hver fil og uploade den til Cloudinary.",[48,9705,9706],{},"I den funktion har vi behov for 2 vigtige ting, nemlig vores upload preset og vores API base url. Base URL skal udvides med \u002Fupload\u002F for at det vil virke.",[48,9708,9709,9710,9713],{},"Tilføj en ny funktion, jeg navngiver den: ",[67,9711,9712],{},"uploadFileToCloudinary()"," og tilføj følgende kode:",[280,9715,9718],{"className":9716,"code":9717,"language":285},[283],"uploadFileToCloudinary(file) {\n  return new Promise(function (resolve, reject) {\nconst CLOUDINARY_URL = 'https:\u002F\u002Fapi.cloudinary.com\u002Fv1_1\u002FCLOUDNAME\u002Fupload';\nconst CLOUDINARY_UPLOAD_PRESET = 'YOURUPLOADPRESET';\n\nlet formData = new FormData();\nformData.append('upload_preset', CLOUDINARY_UPLOAD_PRESET);\nformData.append('folder', 'cloudinary-demo');\nformData.append('file', file);\n\nlet request = new XMLHttpRequest();\nrequest.open('POST', CLOUDINARY_URL, true);\nrequest.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\nrequest.onreadystatechange = () => {\n    if (request.readyState === 4 && request.status === 200) {\n        let response = JSON.parse(request.responseText);\n        resolve(response);\n    }\n    if (request.status !== 200) {\n        let response = JSON.parse(request.responseText);\n        let error = response.error.message;\n        alert('error, status code not 200 ' + error);\n        reject(error);\n    }\n};\n\nrequest.onerror = (err) => {\n    alert('error: ' + err);\n    reject(err);\n};\n\nrequest.send(formData);\n});\n}\n",[287,9719,9717],{"__ignoreMap":217},[48,9721,9722,9723,9725],{},"Inden vi gar videre skal vi lige have sat nogle vaerdier i ",[67,9724,3501],{}," som vi far behov for senere.",[48,9727,9728],{},"Tilføj dette til data:",[280,9730,9733],{"className":9731,"code":9732,"language":285},[283],"data: () => ({\n  files: [],\n  isError: false,\n  errorText: null\n})\n",[287,9734,9732],{"__ignoreMap":217},[48,9736,9737,9738,9740],{},"Rediger funktionen ",[67,9739,9627],{},", og kald upload funktionen for hver fil. Nar vi far svar fra vores metode, pusher vi svaret til vores files array som vi har sat i data.",[280,9742,9745],{"className":9743,"code":9744,"language":285},[283],"onAddFiles(files) {\nif (files.length > 0) {\n  files.forEach((file) => {\n    window.console.log(file);\n    this.uploadFileToCloudinary(file).then((fileResponse) => {\n        this.files.push(fileResponse);\n    });\n  });\n}\n}\n",[287,9746,9744],{"__ignoreMap":217},[48,9748,9749],{},"Lad os ogsa rette vores template til sa vi kan se hver fil der bliver uploadet, og lad os ligeledes vise en fejl hvis det gar galt.",[280,9751,9754],{"className":9752,"code":9753,"language":285},[283],"\u003Ctemplate>\n\u003Cv-app>\n\u003Cv-app-bar\n        app\n        color=\"primary\"\n        dark>\n\u003C\u002Fv-app-bar>\n\u003Cv-content style=\"padding:50px; margin-top:30px;\">\n    \u003Ch1>\n        Upload file to Cloudinary\n    \u003C\u002Fh1>\n    \u003Cv-file-input multiple label=\"Add your files\" chips @change=\"onAddFiles\" \u002F>\n\n    \u003Cv-card v-if=\"files.length > 0\">\n        \u003Cv-card-text>\n            \u003Cv-alert type=\"success\" v-for=\"file in files\" :key=\"file.public_id\">\n                File uploaded: {{file.original_filename}} at {{file.url}}\n            \u003C\u002Fv-alert>\n        \u003C\u002Fv-card-text>\n    \u003C\u002Fv-card>\n\n    \u003Cv-alert v-if=\"isError\">\n        {{errorText}}\n    \u003C\u002Fv-alert>\n\n\u003C\u002Fv-content>\n\u003C\u002Fv-app>\n\u003C\u002Ftemplate>\n",[287,9755,9753],{"__ignoreMap":217},[48,9757,9758,9759,9762],{},"Sa er vi snart ved at vaere i mal vi mangler blot et par ting endnu.\nLige nu laver vi en \"alert\" nar der sker en fejl i funktionen ",[67,9760,9761],{},"uploadFileToCloudinary",".\nDette skal vi have tilrettet for at vi kan se det i vores applikation.",[48,9764,9765],{},"Erstat alle \"alert\" med folgende kode:",[280,9767,9770],{"className":9768,"code":9769,"language":285},[283],"this.errorText = 'error uploading files ' + error;\nthis.isError = true;\n",[287,9771,9769],{"__ignoreMap":217},[48,9773,9774],{},"Du er nu i mal. Du har nu en fuld funktionel applikation der kan upload filer til Cloudinary.",[48,9776,9777],{},"Dit slutresultat skulle gerne minde lidt om dette.",[48,9779,9780],{},[3592,9781],{"alt":9782,"src":9783},"cloudinary-3","\u002Fimages\u002Fcontentful\u002Fcloudinary-3.png",[48,9785,9786],{},"For at opsummere. Dette er en simpel, men effektiv og brugbar bade at uploade filer til Cloudinary pa. Som applikationen er pt er den meget simpel, men kan nemt udvides til at vaere meget mere avanceret og fleksibel.",[48,9788,9789,9790],{},"Denne artikel skrev jeg oprindeligt pa Medium, hvilket du kan finde her: ",[966,9791,9794],{"href":9792,"rel":9793},"https:\u002F\u002Fmedium.com\u002Fp\u002Fdd45472c4fd6\u002F",[4114],"Upload files to Cloudinary using Vue & Vuetify",[48,9796,9797,9798],{},"Hele koden til ovenstaende kan findes pa ",[966,9799,9802],{"href":9800,"rel":9801},"https:\u002F\u002Fgithub.com\u002Fnickycdk\u002Fvue-cloudinary-demo",[4114],"GIT",{"title":217,"searchDepth":218,"depth":218,"links":9804},[],"2020-01-24","For noget tid siden arbejdede jeg pa en SaaS platform hvor man blandt andet nemt skulle kunne uploade filer til en server. Valget faldt pa Cloudinary, og kravet var at selve upload delen skulle ske vi",{},"\u002Fblog\u002Fupload-filer-til-cooudinary-med-vue-and-vuetify",{"title":9582,"description":9806},"upload-filer-til-cooudinary-med-vue-and-vuetify","blog\u002Fupload-filer-til-cooudinary-med-vue-and-vuetify",[997,1392,9813],"cloudinary","\u002Fimages\u002Fcontentful\u002Fupload-filer-blogpost.png","XwFoOzeLh4aTN_C6ye7sC7nRnlqUvvXJm0bXVALh83Y",{"id":9817,"title":9818,"body":9819,"date":10193,"description":10194,"extension":236,"meta":10195,"navigation":238,"noindex":8,"path":10196,"seo":10197,"seoDescription":10198,"seoTitle":10199,"slug":10200,"stem":10201,"tags":10202,"thumbnail":10207,"updated":234,"__hash__":10208},"blog\u002Fblog\u002Fstatiske-websites.md","Statiske websites i 2026 — Hvorfor det stadig er vejen frem",{"type":40,"value":9820,"toc":10179},[9821,9825,9828,9831,9834,9838,9841,9847,9853,9859,9863,9867,9870,9873,9893,9896,9900,9903,9906,9926,9929,9933,9936,9962,9965,9969,9972,9997,10000,10014,10017,10021,10024,10050,10054,10057,10060,10098,10101,10105,10108,10134,10137,10141,10144,10147,10173,10176],[43,9822,9824],{"id":9823},"fra-trend-til-standard","Fra trend til standard",[48,9826,9827],{},"Da jeg skrev den originale version af denne artikel i 2020, var statiske websites stadig noget mange betragtede som en trend. I 2026 er det ikke længere en trend — det er standarden for moderne webudvikling.",[48,9829,9830],{},"Mit eget website, som du læser dette på lige nu, er et statisk website bygget med Nuxt 3. Det er lynhurtigt, sikkert og koster næsten ingenting at hoste. Og det er ikke et specialtilfælde — de fleste professionelle websites i dag er bygget på denne måde.",[48,9832,9833],{},"Lad mig forklare hvorfor, og hvad der har ændret sig siden 2020.",[43,9835,9837],{"id":9836},"hvad-er-et-statisk-website","Hvad er et statisk website?",[48,9839,9840],{},"Et statisk website består af pre-genererede HTML-, CSS- og JavaScript-filer der serveres direkte fra en server eller et CDN. I modsætning til dynamiske websites, hvor serveren genererer indhold for hvert request, er alt allerede bygget på forhånd.",[48,9842,9843,9844,9846],{},"Det betyder ",[67,9845,8899],{}," at indholdet er statisk. Dit website kan stadig have dynamisk indhold, personalisering og interaktivitet. Forskellen er at den initiale side er pre-renderet, hvilket giver markant hurtigere load-tider.",[48,9848,9849,9852],{},[67,9850,9851],{},"Dynamisk:"," Bruger besøger side → Server genererer HTML → Sender til browser",[48,9854,9855,9858],{},[67,9856,9857],{},"Statisk:"," Bruger besøger side → Server sender pre-genereret HTML → Browseren viser det med det samme",[43,9860,9862],{"id":9861},"_5-grunde-til-at-vælge-statisk-generering","5 grunde til at vælge statisk generering",[119,9864,9866],{"id":9865},"_1-hastighed-der-slår-alt","1. Hastighed der slår alt",[48,9868,9869],{},"Statiske websites er de hurtigste websites du kan bygge. Når browseren anmoder om en side, får den et færdigt HTML-dokument med det samme — ingen databaseforespørgsler, ingen server-side rendering, ingen ventetid.",[48,9871,9872],{},"Det giver:",[625,9874,9875,9881,9887],{},[628,9876,9877,9880],{},[67,9878,9879],{},"Bedre Core Web Vitals"," — LCP (Largest Contentful Paint) er typisk under 1 sekund",[628,9882,9883,9886],{},[67,9884,9885],{},"Højere Google-rangering"," — Hastighed er en direkte rankeringsfaktor",[628,9888,9889,9892],{},[67,9890,9891],{},"Bedre brugeroplevelse"," — Sider loader øjeblikkeligt, også på langsomme mobilforbindelser",[48,9894,9895],{},"Med et CDN (Content Delivery Network) bliver dine filer desuden serveret fra det datacenter der er tættest på brugeren. Besøger nogen dit site fra USA, får de filerne fra et amerikansk datacenter — ikke fra en server i Danmark.",[119,9897,9899],{"id":9898},"_2-sikkerhed-uden-bekymringer","2. Sikkerhed uden bekymringer",[48,9901,9902],{},"Et statisk website har en drastisk reduceret angrebsflade. Der er ingen server-side kode der kan udnyttes, ingen database der kan hackes, og ingen CMS-administration der kan kompromitteres.",[48,9904,9905],{},"Det betyder:",[625,9907,9908,9914,9920],{},[628,9909,9910,9913],{},[67,9911,9912],{},"Ingen sikkerhedsopdateringer"," — Der er ingen server-software at patche",[628,9915,9916,9919],{},[67,9917,9918],{},"Ingen SQL-injection"," — Der er ingen database at angribe",[628,9921,9922,9925],{},[67,9923,9924],{},"Ingen brute force angreb"," — Der er ingen login-side at gå efter",[48,9927,9928],{},"For virksomheder der håndterer følsomme data eller bare vil sove trygt om natten, er dette en kæmpe fordel.",[119,9930,9932],{"id":9931},"_3-hosting-er-næsten-gratis","3. Hosting er næsten gratis",[48,9934,9935],{},"Statiske filer er de billigste filer at hoste. Moderne platforme tilbyder gratis eller næsten-gratis hosting til statiske websites:",[625,9937,9938,9944,9950,9956],{},[628,9939,9940,9943],{},[67,9941,9942],{},"Netlify"," — Gratis tier med automatisk deployment fra Git",[628,9945,9946,9949],{},[67,9947,9948],{},"Vercel"," — Gratis for personlige projekter, optimeret til Next.js og Nuxt",[628,9951,9952,9955],{},[67,9953,9954],{},"Cloudflare Pages"," — Gratis hosting med global CDN",[628,9957,9958,9961],{},[67,9959,9960],{},"GitHub Pages"," — Gratis hosting direkte fra dit Git-repository",[48,9963,9964],{},"Sammenlign det med en traditionel server-løsning der kan koste hundreder eller tusinder af kroner om måneden. Med statisk hosting betaler du typisk ingenting for et standard website.",[119,9966,9968],{"id":9967},"_4-udvikleroplevelsen-er-fantastisk","4. Udvikleroplevelsen er fantastisk",[48,9970,9971],{},"Moderne frameworks har gjort det utrolig nemt at bygge statiske websites:",[625,9973,9974,9980,9985,9991],{},[628,9975,9976,9979],{},[67,9977,9978],{},"Nuxt 3"," — Vue-baseret framework med førsteklasses statisk generering. Det er det jeg selv bruger",[628,9981,9982,9984],{},[67,9983,1133],{}," — React-baseret framework med static export og ISR (Incremental Static Regeneration)",[628,9986,9987,9990],{},[67,9988,9989],{},"Astro"," — Nyere framework designet specifikt til content-sites. Sender næsten ingen JavaScript til browseren",[628,9992,9993,9996],{},[67,9994,9995],{},"SvelteKit"," — Svelte-baseret med fleksibel rendering",[48,9998,9999],{},"En typisk arbejdsgang ser sådan ud:",[660,10001,10002,10005,10008,10011],{},[628,10003,10004],{},"Skriv kode og test lokalt med hot-reload",[628,10006,10007],{},"Push til Git",[628,10009,10010],{},"Hosting-platformen bygger automatisk de statiske filer",[628,10012,10013],{},"Websitet er opdateret inden for sekunder",[48,10015,10016],{},"Ingen servere at konfigurere, ingen deployment-scripts at vedligeholde, ingen nedetid under opdateringer.",[119,10018,10020],{"id":10019},"_5-seo-er-built-in","5. SEO er built-in",[48,10022,10023],{},"Statiske websites er drømmen for SEO:",[625,10025,10026,10032,10038,10044],{},[628,10027,10028,10031],{},[67,10029,10030],{},"Fuldt renderet HTML"," — Søgemaskiner får komplet indhold med det samme, ingen JavaScript-rendering nødvendig",[628,10033,10034,10037],{},[67,10035,10036],{},"Hurtige load-tider"," — Google belønner hurtige sider med højere rangering",[628,10039,10040,10043],{},[67,10041,10042],{},"Nem struktur"," — Statisk generering tvinger dig til at tænke i klare URL-strukturer og sidearkitektur",[628,10045,10046,10049],{},[67,10047,10048],{},"Automatisk sitemap"," — De fleste frameworks genererer sitemap automatisk",[43,10051,10053],{"id":10052},"hvad-med-dynamisk-funktionalitet","Hvad med dynamisk funktionalitet?",[48,10055,10056],{},"Den største bekymring folk har ved statiske websites er: \"Hvad med formularer, login og andet dynamisk indhold?\"",[48,10058,10059],{},"I 2026 er dette næsten ikke længere et problem:",[625,10061,10062,10068,10074,10080,10086,10092],{},[628,10063,10064,10067],{},[67,10065,10066],{},"Formularer"," — Netlify Forms, Formspree eller din egen API-route håndterer det",[628,10069,10070,10073],{},[67,10071,10072],{},"E-commerce"," — Snipcart, Shopify Storefront API eller WooCommerce headless",[628,10075,10076,10079],{},[67,10077,10078],{},"CMS"," — Contentful, Sanity, Storyblok, eller endda Markdown-filer (som denne blog bruger)",[628,10081,10082,10085],{},[67,10083,10084],{},"Autentificering"," — Auth0, Clerk, Supabase Auth",[628,10087,10088,10091],{},[67,10089,10090],{},"Søgning"," — Algolia, Meilisearch, eller klient-side søgning",[628,10093,10094,10097],{},[67,10095,10096],{},"Kommentarer"," — Disqus, Giscus, eller custom API",[48,10099,10100],{},"Disse services taler med dit statiske website via API'er, og brugeren mærker ingen forskel.",[43,10102,10104],{"id":10103},"hvornår-er-statisk-ikke-det-rigtige-valg","Hvornår er statisk IKKE det rigtige valg?",[48,10106,10107],{},"Statisk generering er ikke altid svaret:",[625,10109,10110,10116,10122,10128],{},[628,10111,10112,10115],{},[67,10113,10114],{},"Meget dynamisk indhold"," — Hvis indholdet ændrer sig hvert minut (fx en aktiekurs-side), er server-side rendering eller real-time data bedre",[628,10117,10118,10121],{},[67,10119,10120],{},"Tusindvis af sider"," — Build-tiden kan blive lang. ISR (Incremental Static Regeneration) kan løse dette",[628,10123,10124,10127],{},[67,10125,10126],{},"Personaliseret indhold"," — Hvis hver bruger ser helt forskelligt indhold, kræver det server-side logik",[628,10129,10130,10133],{},[67,10131,10132],{},"Komplekse web-applikationer"," — En SaaS-platform med dashboards og real-time data er bedre som en SPA eller SSR-applikation",[48,10135,10136],{},"For de fleste virksomhedswebsites, marketing-sider, blogs og portfolios er statisk generering dog det klare førstevalg.",[43,10138,10140],{"id":10139},"min-anbefaling-i-2026","Min anbefaling i 2026",[48,10142,10143],{},"Hvis du skal have bygget en ny hjemmeside, bør statisk generering være udgangspunktet. Det giver dig den bedste kombination af hastighed, sikkerhed, SEO og driftsøkonomi.",[48,10145,10146],{},"Vælg et framework der passer til dit team:",[625,10148,10149,10155,10161,10167],{},[628,10150,10151,10154],{},[67,10152,10153],{},"Vue-udviklere"," → Nuxt 3",[628,10156,10157,10160],{},[67,10158,10159],{},"React-udviklere"," → Next.js",[628,10162,10163,10166],{},[67,10164,10165],{},"Content-sites med minimal JavaScript"," → Astro",[628,10168,10169,10172],{},[67,10170,10171],{},"Svelte-udviklere"," → SvelteKit",[48,10174,10175],{},"Og vælg en hosting-platform som Netlify, Vercel eller Cloudflare Pages. Du får automatisk deployment, CDN, HTTPS og alt hvad du har brug for — ofte helt gratis.",[48,10177,10178],{},"Har du spørgsmål om statiske websites eller overvejer at konvertere din eksisterende hjemmeside? Tag kontakt, så hjælper jeg gerne.",{"title":217,"searchDepth":218,"depth":218,"links":10180},[10181,10182,10183,10190,10191,10192],{"id":9823,"depth":218,"text":9824},{"id":9836,"depth":218,"text":9837},{"id":9861,"depth":218,"text":9862,"children":10184},[10185,10186,10187,10188,10189],{"id":9865,"depth":226,"text":9866},{"id":9898,"depth":226,"text":9899},{"id":9931,"depth":226,"text":9932},{"id":9967,"depth":226,"text":9968},{"id":10019,"depth":226,"text":10020},{"id":10052,"depth":218,"text":10053},{"id":10103,"depth":218,"text":10104},{"id":10139,"depth":218,"text":10140},"2020-01-23","Statiske websites er ikke længere bare en trend. De er blevet standarden for hurtige, sikre og skalerbare hjemmesider. Her er hvorfor.",{},"\u002Fblog\u002Fstatiske-websites",{"title":9818,"description":10194},"Statiske websites er standarden for moderne webudvikling. Lær hvorfor statisk generering med Nuxt, Next.js og Astro giver hurtigere, sikrere og billigere hjemmesider.","Statiske websites i 2026 — Hurtigere, sikrere og nemmere","statiske-websites","blog\u002Fstatiske-websites",[2005,10203,10204,10205,10206],"performance","jamstack","nuxt","statisk-generering","\u002Fimages\u002Fcontentful\u002Fstatiske-websites-blog.png","qHQaV0QP9ZJigQB5OJFPaUgPsvNbvcf_trbIn65_whI",{"id":10210,"title":10211,"body":10212,"date":13147,"description":13148,"extension":236,"meta":13149,"navigation":238,"noindex":8,"path":13150,"seo":13151,"seoDescription":13152,"seoTitle":10211,"slug":13153,"stem":13154,"tags":13155,"thumbnail":13156,"updated":13147,"__hash__":13157},"blog\u002Fblog\u002Fbyg-website-med-nuxt-og-contentful.md","Byg et website med Nuxt og Contentful — en trin-for-trin guide",{"type":40,"value":10213,"toc":13133},[10214,10222,10225,10236,10245,10256,10260,10263,10266,10273,10277,10280,10287,10299,10303,10306,10327,10330,10336,10339,10344,10351,10373,10376,10380,10383,10386,10389,10394,10397,10402,10406,10409,10426,10429,10432,10437,10568,10571,10604,10607,10672,10679,10685,10691,10783,10799,10802,10806,10813,10818,10821,10826,10829,10834,10837,10841,10844,10853,11081,11088,11097,11220,11235,11239,11242,11247,11250,11283,11290,11299,11307,11313,11320,11326,11332,11433,11451,11481,11643,11646,11651,11654,11659,11662,11665,11670,11684,11694,11697,11706,11802,11805,11810,11816,11846,11852,11858,11864,11873,12171,12173,12178,12182,12185,12196,12205,12267,12336,12343,12347,12362,12371,12491,12494,12503,12531,12794,12799,12802,12805,12814,13064,13067,13072,13075,13080,13083,13087,13094,13100,13104,13107,13110,13130],[5713,10215,10216],{},[48,10217,10218,10221],{},[67,10219,10220],{},"Bemærk:"," Denne artikel dækker Nuxt 2 og Contentful. Hvis du er interesseret i Nuxt 3, kan du læse mine andre artikler om det nyeste fra Nuxt.",[48,10223,10224],{},"Som frontend-udvikler er det en fornøjelse at arbejde med static-site-generators og serverless-arkitektur, og med det kan vi skabe meget kraftfulde og fantastiske applikationer, som vi også kan server-side rendere.",[48,10226,10227,10228,10231,10232,10235],{},"Denne artikel har til formål at give dig en trin-for-trin guide til at bygge et ",[67,10229,10230],{},"meget basalt website"," med NuxtJS + Contentful — inklusiv et ",[67,10233,10234],{},"simpelt"," Vuex-eksempel.",[48,10237,10238,10241],{},[67,10239,10240],{},"Find det fulde GIT-repo her:",[966,10242,10243],{"href":10243,"rel":10244},"https:\u002F\u002Fgithub.com\u002Fnickycdk\u002Fnuxt-contentful-example",[4114],[5713,10246,10247],{},[48,10248,10249,10250,10255],{},"Personligt kører ",[966,10251,10254],{"href":10252,"rel":10253},"https:\u002F\u002Fnickychristensen.dk",[4114],"mit eget website"," på et Nuxt\u002FContentful-setup med Continuous deployment ved at forbinde mit GIT-repo med Netlify, dette kombineret med Contentfuls webhooks til automatisk at genbygge dit site, når der publiceres nyt indhold, er bare... Fantastisk",[43,10257,10259],{"id":10258},"hvad-er-nuxt","Hvad er Nuxt",[48,10261,10262],{},"Hvis du har bygget Vue-applikationer før, har du sandsynligvis hørt om NuxtJS, som er det tilsvarende af, hvad NextJS er for React.",[48,10264,10265],{},"Nuxt er et framework, der bygger oven på Vue og forenkler udviklingen af universelle eller single page Vue-apps, hvilket er fantastisk, hvis du bygger et website og vil sikre, at det kan blive indekseret af Google.",[48,10267,10268,10269],{},"Derick Sozo har skrevet et godt indlæg om, hvorfor du bør vælge Nuxt til din næste webapplikation, som kan findes her: ",[966,10270,10271],{"href":10271,"rel":10272},"https:\u002F\u002Fmedium.com\u002Fvue-mastery\u002F10-reasons-to-use-nuxt-js-for-your-next-web-application-522397c9366b",[4114],[43,10274,10276],{"id":10275},"hvad-er-contentful","Hvad er Contentful:",[48,10278,10279],{},"Contentful er kendt som et headless CMS-system, hvilket betyder, at det er et API-first content-management-system, hvorfra du kan oprette, administrere og distribuere indhold til enhver platform eller enhed.",[48,10281,10282,10283],{},"Lær meget mere om Contentful på deres egen hjemmeside lige her: ",[966,10284,10285],{"href":10285,"rel":10286},"https:\u002F\u002Fwww.contentful.com\u002F",[4114],[5713,10288,10289],{},[48,10290,10291,10292,10295,10296],{},"I denne artikel lærer du, hvordan du bygger et ",[67,10293,10294],{},"meget simpelt"," Nuxt-website, der henter data fra Contentful. Når du har fået styr på begge dele, og hvordan du kan bruge disse to sammen, ",[67,10297,10298],{},"kan du virkelig begynde at bygge kraftfulde og fantastiske applikationer.",[43,10300,10302],{"id":10301},"nuxt-opsætning","Nuxt-opsætning",[48,10304,10305],{},"Før vi kan begynde at bygge, skal vi installere Nuxt. Det gør vi ved at bruge VueCLI. Hvis du ikke har installeret dette på dit system før, skal du installere det via terminalen:",[280,10307,10311],{"className":10308,"code":10309,"language":10310,"meta":217,"style":217},"language-bash shiki shiki-themes github-dark","npm install -g vue-cli\n","bash",[287,10312,10313],{"__ignoreMap":217},[332,10314,10315,10318,10321,10324],{"class":334,"line":335},[332,10316,10317],{"class":351},"npm",[332,10319,10320],{"class":551}," install",[332,10322,10323],{"class":364}," -g",[332,10325,10326],{"class":551}," vue-cli\n",[48,10328,10329],{},"Nu kan du bruge VueCLI til at opsætte et Nuxt-projekt.",[280,10331,10334],{"className":10332,"code":10333,"language":285},[283],"vue init nuxt\u002Fstarter nuxt-contentful-demo\n",[287,10335,10333],{"__ignoreMap":217},[48,10337,10338],{},"Følg instruktionerne og giv projektet et navn, en beskrivelse og en forfatter.",[48,10340,10341],{},[3592,10342],{"alt":217,"src":10343},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*WbEzDYO6hhSBpwdmvFZ-6Q.png",[48,10345,10346,10347,10350],{},"Når du er færdig, ",[67,10348,10349],{},"cd"," ind i mappen til dit projekt og kør",[280,10352,10354],{"className":10308,"code":10353,"language":10310,"meta":217,"style":217},"npm install\nnpm run dev\n",[287,10355,10356,10363],{"__ignoreMap":217},[332,10357,10358,10360],{"class":334,"line":335},[332,10359,10317],{"class":351},[332,10361,10362],{"class":551}," install\n",[332,10364,10365,10367,10370],{"class":334,"line":218},[332,10366,10317],{"class":351},[332,10368,10369],{"class":551}," run",[332,10371,10372],{"class":551}," dev\n",[48,10374,10375],{},"Smukt! Vi er nu et skridt tættere på, og vi har et fundament at bygge videre på.",[43,10377,10379],{"id":10378},"contentful-opsætning","Contentful-opsætning",[48,10381,10382],{},"Gå til Contentful og log ind med dit brugernavn og din adgangskode.\nHvis du ikke allerede har en bruger, skal du oprette en for at kunne bruge Contentful. De har en gratis plan, som du kan bruge.",[48,10384,10385],{},"Når du er logget ind, er det første, vi skal gøre, at opsætte et nyt space til vores website.",[48,10387,10388],{},"Når du er i Contentful, klik på \"Create space\"",[48,10390,10391],{},[3592,10392],{"alt":217,"src":10393},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*y6YPQkqvzZ_DFESKYNmSgw.png",[48,10395,10396],{},"Når du opretter et nyt space, skal vi udfylde et par detaljer.\nVælg den gratis plan, giv dit space et navn og bekræft oprettelsen.",[48,10398,10399],{},[3592,10400],{"alt":217,"src":10401},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*1PNLF8fdduRjfuKjrHwu7A.png",[43,10403,10405],{"id":10404},"integrer-contentful-i-nuxt","Integrer Contentful i Nuxt",[48,10407,10408],{},"Når vi vil bruge Contentful i Nuxt-projekter, skal vi installere JavaScript SDK'et. Det kan vi gøre ved at køre følgende kommando:",[280,10410,10412],{"className":10308,"code":10411,"language":10310,"meta":217,"style":217},"npm install --save contentful\n",[287,10413,10414],{"__ignoreMap":217},[332,10415,10416,10418,10420,10423],{"class":334,"line":335},[332,10417,10317],{"class":351},[332,10419,10320],{"class":551},[332,10421,10422],{"class":364}," --save",[332,10424,10425],{"class":551}," contentful\n",[48,10427,10428],{},"Når installationen er færdig, kan vi gå til vores projekt i vores IDE og oprette en ny fil under \"plugins\". Denne fil fortæller grundlæggende Nuxt, at den skal bruge Contentful som et plugin, hvilket gør det muligt for os nemt at hente vores data fra Contentful.",[48,10430,10431],{},"Gå videre og opret en ny fil:",[48,10433,10434],{},[3592,10435],{"alt":217,"src":10436},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*soOaiUtqbP07pLfBklIaVQ.png",[280,10438,10440],{"className":2047,"code":10439,"language":1392,"meta":217,"style":217},"const contentful = require('contentful');\n\n\u002F\u002F use default environment config for convenience\n\u002F\u002F these will be set via `env` property in nuxt.config.js\n\nconst config = {\n  space: process.env.CTF_SPACE_ID,\n  accessToken: process.env.CTF_CDA_ACCESS_TOKEN\n};\n\n\n\u002F\u002F export `createClient` to use it in page components\nmodule.exports = {\n  createClient () {\n    return contentful.createClient(config)\n  }\n}\n",[287,10441,10442,10461,10465,10470,10475,10479,10490,10500,10508,10512,10516,10520,10525,10539,10547,10560,10564],{"__ignoreMap":217},[332,10443,10444,10446,10449,10451,10454,10456,10459],{"class":334,"line":335},[332,10445,530],{"class":344},[332,10447,10448],{"class":364}," contentful",[332,10450,368],{"class":344},[332,10452,10453],{"class":351}," require",[332,10455,407],{"class":355},[332,10457,10458],{"class":551},"'contentful'",[332,10460,2825],{"class":355},[332,10462,10463],{"class":334,"line":218},[332,10464,418],{"emptyLinePlaceholder":238},[332,10466,10467],{"class":334,"line":226},[332,10468,10469],{"class":338},"\u002F\u002F use default environment config for convenience\n",[332,10471,10472],{"class":334,"line":395},[332,10473,10474],{"class":338},"\u002F\u002F these will be set via `env` property in nuxt.config.js\n",[332,10476,10477],{"class":334,"line":415},[332,10478,418],{"emptyLinePlaceholder":238},[332,10480,10481,10483,10486,10488],{"class":334,"line":421},[332,10482,530],{"class":344},[332,10484,10485],{"class":364}," config",[332,10487,368],{"class":344},[332,10489,782],{"class":355},[332,10491,10492,10495,10498],{"class":334,"line":434},[332,10493,10494],{"class":355},"  space: process.env.",[332,10496,10497],{"class":364},"CTF_SPACE_ID",[332,10499,555],{"class":355},[332,10501,10502,10505],{"class":334,"line":446},[332,10503,10504],{"class":355},"  accessToken: process.env.",[332,10506,10507],{"class":364},"CTF_CDA_ACCESS_TOKEN\n",[332,10509,10510],{"class":334,"line":466},[332,10511,2218],{"class":355},[332,10513,10514],{"class":334,"line":476},[332,10515,418],{"emptyLinePlaceholder":238},[332,10517,10518],{"class":334,"line":482},[332,10519,418],{"emptyLinePlaceholder":238},[332,10521,10522],{"class":334,"line":487},[332,10523,10524],{"class":338},"\u002F\u002F export `createClient` to use it in page components\n",[332,10526,10527,10530,10532,10535,10537],{"class":334,"line":496},[332,10528,10529],{"class":364},"module",[332,10531,1956],{"class":355},[332,10533,10534],{"class":364},"exports",[332,10536,368],{"class":344},[332,10538,782],{"class":355},[332,10540,10541,10544],{"class":334,"line":2156},[332,10542,10543],{"class":351},"  createClient",[332,10545,10546],{"class":355}," () {\n",[332,10548,10549,10551,10554,10557],{"class":334,"line":2162},[332,10550,3160],{"class":344},[332,10552,10553],{"class":355}," contentful.",[332,10555,10556],{"class":351},"createClient",[332,10558,10559],{"class":355},"(config)\n",[332,10561,10562],{"class":334,"line":2173},[332,10563,479],{"class":355},[332,10565,10566],{"class":334,"line":2179},[332,10567,499],{"class":355},[48,10569,10570],{},"Som du måske har bemærket, refererer vi til nogle environment-variabler, som vi ikke har oprettet endnu.",[280,10572,10574],{"className":2047,"code":10573,"language":1392,"meta":217,"style":217},"const config = {\n  space: process.env.CTF_SPACE_ID,\n  accessToken: process.env.CTF_CDA_ACCESS_TOKEN\n};\n",[287,10575,10576,10586,10594,10600],{"__ignoreMap":217},[332,10577,10578,10580,10582,10584],{"class":334,"line":335},[332,10579,530],{"class":344},[332,10581,10485],{"class":364},[332,10583,368],{"class":344},[332,10585,782],{"class":355},[332,10587,10588,10590,10592],{"class":334,"line":218},[332,10589,10494],{"class":355},[332,10591,10497],{"class":364},[332,10593,555],{"class":355},[332,10595,10596,10598],{"class":334,"line":226},[332,10597,10504],{"class":355},[332,10599,10507],{"class":364},[332,10601,10602],{"class":334,"line":395},[332,10603,2218],{"class":355},[48,10605,10606],{},"For at dette virker, skal vi oprette en ny fil \"contentful.json\", som vi placerer i vores rodmappe. Denne fil skal indeholde noget konfiguration.",[280,10608,10612],{"className":10609,"code":10610,"language":10611,"meta":217,"style":217},"language-css shiki shiki-themes github-dark","{\n  \"CTF_SPACE_ID\": \"YOURSPACEID\",\n  \"CTF_CDA_ACCESS_TOKEN\": \"YOURACCESSTOKEN\",\n  \"CTF_ENVIRONMENT\": \"master\"\n}\n","css",[287,10613,10614,10619,10646,10658,10668],{"__ignoreMap":217},[332,10615,10616],{"class":334,"line":335},[332,10617,10618],{"class":355},"{\n",[332,10620,10621,10624,10627,10630,10633,10635,10638,10641,10644],{"class":334,"line":218},[332,10622,10623],{"class":355},"  \"",[332,10625,10626],{"class":364},"CTF",[332,10628,10629],{"class":355},"_",[332,10631,10632],{"class":364},"SPACE",[332,10634,10629],{"class":355},[332,10636,10637],{"class":364},"ID",[332,10639,10640],{"class":355},"\": ",[332,10642,10643],{"class":551},"\"YOURSPACEID\"",[332,10645,555],{"class":355},[332,10647,10648,10651,10653,10656],{"class":334,"line":226},[332,10649,10650],{"class":551},"  \"CTF_CDA_ACCESS_TOKEN\"",[332,10652,7176],{"class":355},[332,10654,10655],{"class":551},"\"YOURACCESSTOKEN\"",[332,10657,555],{"class":355},[332,10659,10660,10663,10665],{"class":334,"line":395},[332,10661,10662],{"class":551},"  \"CTF_ENVIRONMENT\"",[332,10664,7176],{"class":355},[332,10666,10667],{"class":551},"\"master\"\n",[332,10669,10670],{"class":334,"line":415},[332,10671,499],{"class":355},[48,10673,10674,10675,10678],{},"Du kan finde disse indstillinger ved at navigere til > ",[67,10676,10677],{},"Settings > Api Keys"," i Contentful-dashboardet.",[48,10680,10681,10682],{},"Når du er færdig, gem filen og gå til ",[67,10683,10684],{},"nuxt.config.js",[48,10686,10687,10688,10690],{},"Vi skal require den nyoprettede konfigurationsfil og tilføje lidt kode til vores ",[67,10689,10684],{},"-fil",[280,10692,10694],{"className":2047,"code":10693,"language":1392,"meta":217,"style":217},"\u002F\u002F .\u002Fnuxt.config.js\nconst config = require('.\u002F.contentful.json')\n\nmodule.exports = {\n  \u002F\u002F ...\n  env: {\n    CTF_SPACE_ID: config.CTF_SPACE_ID,\n    CTF_CDA_ACCESS_TOKEN: config.CTF_CDA_ACCESS_TOKEN,\n    CTF_ENVIRONMENT: config.CTF_ENVIRONMENT\n  }\n  \u002F\u002F ...\n}\n",[287,10695,10696,10701,10718,10722,10734,10739,10744,10753,10763,10771,10775,10779],{"__ignoreMap":217},[332,10697,10698],{"class":334,"line":335},[332,10699,10700],{"class":338},"\u002F\u002F .\u002Fnuxt.config.js\n",[332,10702,10703,10705,10707,10709,10711,10713,10716],{"class":334,"line":218},[332,10704,530],{"class":344},[332,10706,10485],{"class":364},[332,10708,368],{"class":344},[332,10710,10453],{"class":351},[332,10712,407],{"class":355},[332,10714,10715],{"class":551},"'.\u002F.contentful.json'",[332,10717,392],{"class":355},[332,10719,10720],{"class":334,"line":226},[332,10721,418],{"emptyLinePlaceholder":238},[332,10723,10724,10726,10728,10730,10732],{"class":334,"line":395},[332,10725,10529],{"class":364},[332,10727,1956],{"class":355},[332,10729,10534],{"class":364},[332,10731,368],{"class":344},[332,10733,782],{"class":355},[332,10735,10736],{"class":334,"line":415},[332,10737,10738],{"class":338},"  \u002F\u002F ...\n",[332,10740,10741],{"class":334,"line":421},[332,10742,10743],{"class":355},"  env: {\n",[332,10745,10746,10749,10751],{"class":334,"line":434},[332,10747,10748],{"class":355},"    CTF_SPACE_ID: config.",[332,10750,10497],{"class":364},[332,10752,555],{"class":355},[332,10754,10755,10758,10761],{"class":334,"line":446},[332,10756,10757],{"class":355},"    CTF_CDA_ACCESS_TOKEN: config.",[332,10759,10760],{"class":364},"CTF_CDA_ACCESS_TOKEN",[332,10762,555],{"class":355},[332,10764,10765,10768],{"class":334,"line":466},[332,10766,10767],{"class":355},"    CTF_ENVIRONMENT: config.",[332,10769,10770],{"class":364},"CTF_ENVIRONMENT\n",[332,10772,10773],{"class":334,"line":476},[332,10774,479],{"class":355},[332,10776,10777],{"class":334,"line":482},[332,10778,10738],{"class":338},[332,10780,10781],{"class":334,"line":487},[332,10782,499],{"class":355},[48,10784,10785,10792,10793,10798],{},[167,10786,10787],{},[67,10788,10789],{},[67,10790,10791],{},"env","-egenskaben er en måde at definere værdier på, der vil være tilgængelige, når du bruger ",[67,10794,10795],{},[67,10796,10797],{},"process.env",", når sitet køres i en Node.js-kontekst.*",[48,10800,10801],{},"Nu hvor vi har fået alle de grundlæggende ting sat op til at bruge Contentful, er næste skridt at oprette noget indhold, vi kan trække ind i vores Nuxt-applikation.",[43,10803,10805],{"id":10804},"byg-indhold-i-contentful","Byg indhold i Contentful",[48,10807,10808,10809,10812],{},"Før vi kan hente indhold ind i applikationen, skal vi oprette en content-type og noget indhold. Start med at navigere til fanen: ",[67,10810,10811],{},"Content Model"," og opsæt en ny content-type",[48,10814,10815],{},[3592,10816],{"alt":217,"src":10817},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*CS7IIPdiD7p5e0u9rt8XlA.png",[48,10819,10820],{},"Når content-typen er oprettet, skal vi tilføje nogle felter til den.\nI dette eksempel opsætter vi en meget basal model med følgende felter:",[48,10822,10823],{},[3592,10824],{"alt":217,"src":10825},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*wpv5e9GcBLny-1gRYy00CA.png",[48,10827,10828],{},"Dernæst skal vi bruge et par sider. Gå videre og opret nogle sider baseret på den oprettede content-type. Du kan gøre dette under fanen \"Content\".",[48,10830,10831],{},[3592,10832],{"alt":217,"src":10833},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*l9nENRtdkMdh1f-Yr03iWA.png",[48,10835,10836],{},"Fantastisk — Nu har vi noget indhold oprettet, og vi er klar til at lave noget mere arbejde i vores kode.",[43,10838,10840],{"id":10839},"opret-navigationen","Opret navigationen",[48,10842,10843],{},"Vores website har brug for en navigation, så vores brugere kan navigere mellem sider. I \"Components\"-mappen opretter du en ny komponent kaldet \"Navigation\"",[280,10845,10847],{"className":2047,"code":10846,"language":1392,"meta":217,"style":217},"\u002F\u002F Navigation.vue\n",[287,10848,10849],{"__ignoreMap":217},[332,10850,10851],{"class":334,"line":335},[332,10852,10846],{"class":338},[280,10854,10856],{"className":2460,"code":10855,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n    \u003Cdiv class=\"navigation\">\n      \u003Cnav>\n        \u003Cul role=\"menu\">\n          \u003Cli v-for=\"(navItem, index) in pages\" :key=\"index\">\n            \u003Cnuxt-link :to=\"'\u002F' + navItem.fields.slug.trim()\" role=\"menuitem\">{{navItem.fields.navTitle}}\u003C\u002Fnuxt-link>\n          \u003C\u002Fli>\n        \u003C\u002Ful>\n      \u003C\u002Fnav>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n    export default {\n        name: 'Navigation',\n        props: {\n          pages: {\n            type: Array, \u002F\u002F We expect an array of pages that we need for our navigation\n            required: true\n          }\n        }\n    }\n\u003C\u002Fscript>\n",[287,10857,10858,10866,10882,10891,10907,10930,10960,10969,10978,10986,10994,11002,11006,11014,11023,11033,11038,11043,11051,11059,11064,11069,11073],{"__ignoreMap":217},[332,10859,10860,10862,10864],{"class":334,"line":335},[332,10861,374],{"class":355},[332,10863,2058],{"class":2057},[332,10865,2061],{"class":355},[332,10867,10868,10870,10872,10875,10877,10880],{"class":334,"line":218},[332,10869,2076],{"class":355},[332,10871,2069],{"class":2057},[332,10873,10874],{"class":351}," class",[332,10876,440],{"class":355},[332,10878,10879],{"class":551},"\"navigation\"",[332,10881,2061],{"class":355},[332,10883,10884,10886,10889],{"class":334,"line":226},[332,10885,2516],{"class":355},[332,10887,10888],{"class":2057},"nav",[332,10890,2061],{"class":355},[332,10892,10893,10895,10897,10900,10902,10905],{"class":334,"line":395},[332,10894,2525],{"class":355},[332,10896,625],{"class":2057},[332,10898,10899],{"class":351}," role",[332,10901,440],{"class":355},[332,10903,10904],{"class":551},"\"menu\"",[332,10906,2061],{"class":355},[332,10908,10909,10912,10914,10916,10918,10921,10923,10925,10928],{"class":334,"line":415},[332,10910,10911],{"class":355},"          \u003C",[332,10913,628],{"class":2057},[332,10915,2530],{"class":351},[332,10917,440],{"class":355},[332,10919,10920],{"class":551},"\"(navItem, index) in pages\"",[332,10922,2538],{"class":351},[332,10924,440],{"class":355},[332,10926,10927],{"class":551},"\"index\"",[332,10929,2061],{"class":355},[332,10931,10932,10935,10938,10941,10943,10946,10948,10950,10953,10956,10958],{"class":334,"line":421},[332,10933,10934],{"class":355},"            \u003C",[332,10936,10937],{"class":2057},"nuxt-link",[332,10939,10940],{"class":351}," :to",[332,10942,440],{"class":355},[332,10944,10945],{"class":551},"\"'\u002F' + navItem.fields.slug.trim()\"",[332,10947,10899],{"class":351},[332,10949,440],{"class":355},[332,10951,10952],{"class":551},"\"menuitem\"",[332,10954,10955],{"class":355},">{{navItem.fields.navTitle}}\u003C\u002F",[332,10957,10937],{"class":2057},[332,10959,2061],{"class":355},[332,10961,10962,10965,10967],{"class":334,"line":434},[332,10963,10964],{"class":355},"          \u003C\u002F",[332,10966,628],{"class":2057},[332,10968,2061],{"class":355},[332,10970,10971,10974,10976],{"class":334,"line":446},[332,10972,10973],{"class":355},"        \u003C\u002F",[332,10975,625],{"class":2057},[332,10977,2061],{"class":355},[332,10979,10980,10982,10984],{"class":334,"line":466},[332,10981,2555],{"class":355},[332,10983,10888],{"class":2057},[332,10985,2061],{"class":355},[332,10987,10988,10990,10992],{"class":334,"line":476},[332,10989,2577],{"class":355},[332,10991,2069],{"class":2057},[332,10993,2061],{"class":355},[332,10995,10996,10998,11000],{"class":334,"line":482},[332,10997,2112],{"class":355},[332,10999,2058],{"class":2057},[332,11001,2061],{"class":355},[332,11003,11004],{"class":334,"line":487},[332,11005,418],{"emptyLinePlaceholder":238},[332,11007,11008,11010,11012],{"class":334,"line":496},[332,11009,374],{"class":355},[332,11011,2127],{"class":2057},[332,11013,2061],{"class":355},[332,11015,11016,11019,11021],{"class":334,"line":2156},[332,11017,11018],{"class":344},"    export",[332,11020,3071],{"class":344},[332,11022,782],{"class":355},[332,11024,11025,11028,11031],{"class":334,"line":2162},[332,11026,11027],{"class":355},"        name: ",[332,11029,11030],{"class":551},"'Navigation'",[332,11032,555],{"class":355},[332,11034,11035],{"class":334,"line":2173},[332,11036,11037],{"class":355},"        props: {\n",[332,11039,11040],{"class":334,"line":2179},[332,11041,11042],{"class":355},"          pages: {\n",[332,11044,11045,11048],{"class":334,"line":2184},[332,11046,11047],{"class":355},"            type: Array, ",[332,11049,11050],{"class":338},"\u002F\u002F We expect an array of pages that we need for our navigation\n",[332,11052,11053,11056],{"class":334,"line":2193},[332,11054,11055],{"class":355},"            required: ",[332,11057,11058],{"class":364},"true\n",[332,11060,11061],{"class":334,"line":2204},[332,11062,11063],{"class":355},"          }\n",[332,11065,11066],{"class":334,"line":2210},[332,11067,11068],{"class":355},"        }\n",[332,11070,11071],{"class":334,"line":2215},[332,11072,3151],{"class":355},[332,11074,11075,11077,11079],{"class":334,"line":2221},[332,11076,2112],{"class":355},[332,11078,2127],{"class":2057},[332,11080,2061],{"class":355},[48,11082,11083,11084,11087],{},"Gå dernæst til mappen \"pages\" og åbn filen ",[67,11085,11086],{},"index.vue",".\nI denne fil skal vi inkludere vores navigationskomponent, så vi kan tilføje den til filen.",[280,11089,11091],{"className":2047,"code":11090,"language":1392,"meta":217,"style":217},"\u002F\u002Fpages\u002Findex.vue\n",[287,11092,11093],{"__ignoreMap":217},[332,11094,11095],{"class":334,"line":335},[332,11096,11090],{"class":338},[280,11098,11100],{"className":2460,"code":11099,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Csection class=\"container\">\n    \u003CNavigation :navItems=\"pages\" \u002F>\n  \u003C\u002Fsection>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  import Navigation from '..\u002Fcomponents\u002FNavigation';\n  export default {\n    components: {\n      Navigation\n    }\n  }\n\u003C\u002Fscript>\n",[287,11101,11102,11110,11126,11143,11151,11159,11163,11171,11185,11194,11199,11204,11208,11212],{"__ignoreMap":217},[332,11103,11104,11106,11108],{"class":334,"line":335},[332,11105,374],{"class":355},[332,11107,2058],{"class":2057},[332,11109,2061],{"class":355},[332,11111,11112,11114,11117,11119,11121,11124],{"class":334,"line":218},[332,11113,2066],{"class":355},[332,11115,11116],{"class":2057},"section",[332,11118,10874],{"class":351},[332,11120,440],{"class":355},[332,11122,11123],{"class":551},"\"container\"",[332,11125,2061],{"class":355},[332,11127,11128,11130,11133,11136,11138,11141],{"class":334,"line":226},[332,11129,2076],{"class":355},[332,11131,11132],{"class":2057},"Navigation",[332,11134,11135],{"class":351}," :navItems",[332,11137,440],{"class":355},[332,11139,11140],{"class":551},"\"pages\"",[332,11142,4424],{"class":355},[332,11144,11145,11147,11149],{"class":334,"line":395},[332,11146,2103],{"class":355},[332,11148,11116],{"class":2057},[332,11150,2061],{"class":355},[332,11152,11153,11155,11157],{"class":334,"line":415},[332,11154,2112],{"class":355},[332,11156,2058],{"class":2057},[332,11158,2061],{"class":355},[332,11160,11161],{"class":334,"line":421},[332,11162,418],{"emptyLinePlaceholder":238},[332,11164,11165,11167,11169],{"class":334,"line":434},[332,11166,374],{"class":355},[332,11168,2127],{"class":2057},[332,11170,2061],{"class":355},[332,11172,11173,11175,11178,11180,11183],{"class":334,"line":446},[332,11174,4580],{"class":344},[332,11176,11177],{"class":355}," Navigation ",[332,11179,3057],{"class":344},[332,11181,11182],{"class":551}," '..\u002Fcomponents\u002FNavigation'",[332,11184,2729],{"class":355},[332,11186,11187,11190,11192],{"class":334,"line":466},[332,11188,11189],{"class":344},"  export",[332,11191,3071],{"class":344},[332,11193,782],{"class":355},[332,11195,11196],{"class":334,"line":476},[332,11197,11198],{"class":355},"    components: {\n",[332,11200,11201],{"class":334,"line":482},[332,11202,11203],{"class":355},"      Navigation\n",[332,11205,11206],{"class":334,"line":487},[332,11207,3151],{"class":355},[332,11209,11210],{"class":334,"line":496},[332,11211,479],{"class":355},[332,11213,11214,11216,11218],{"class":334,"line":2156},[332,11215,2112],{"class":355},[332,11217,2127],{"class":2057},[332,11219,2061],{"class":355},[48,11221,11222,11223,11226,11227,11230,11231,11234],{},"Som du måske bemærker, sender vi i ",[67,11224,11225],{},"Navigation.vue"," en prop kaldet ",[67,11228,11229],{},"navItems"," med data, der ikke eksisterer endnu. For at sende ",[67,11232,11233],{},"pages"," ned til navigationskomponenten skal vi først hente dataen fra Contentful.",[43,11236,11238],{"id":11237},"hent-data-fra-contentful","Hent data fra Contentful",[48,11240,11241],{},"Det første, vi skal gøre, er at importere klienten fra det Contentful-plugin, vi oprettede tidligere i plugins-mappen:",[48,11243,11244],{},[3592,11245],{"alt":217,"src":11246},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*C0_UrQmwNmO-DhjxAxsKvQ.png",[48,11248,11249],{},"Tilføj følgende til koden:",[280,11251,11253],{"className":2047,"code":11252,"language":1392,"meta":217,"style":217},"import { createClient } from '..\u002Fplugins\u002Fcontentful';\nconst contentfulClient = createClient();\n",[287,11254,11255,11269],{"__ignoreMap":217},[332,11256,11257,11259,11262,11264,11267],{"class":334,"line":335},[332,11258,3051],{"class":344},[332,11260,11261],{"class":355}," { createClient } ",[332,11263,3057],{"class":344},[332,11265,11266],{"class":551}," '..\u002Fplugins\u002Fcontentful'",[332,11268,2729],{"class":355},[332,11270,11271,11273,11276,11278,11281],{"class":334,"line":218},[332,11272,530],{"class":344},[332,11274,11275],{"class":364}," contentfulClient",[332,11277,368],{"class":344},[332,11279,11280],{"class":351}," createClient",[332,11282,2906],{"class":355},[48,11284,11285,11286,11289],{},"Dernæst skal vi bruge asyncData-metoden. Denne giver os mulighed for at hente og rendere dataen ",[67,11287,11288],{},"server-side",". I denne henter vi alle sider oprettet i Contentful.",[48,11291,11292,11293],{},"*Interesseret i at lære mere om asyncData: *",[966,11294,11297],{"href":11295,"rel":11296},"https:\u002F\u002Fnuxtjs.org\u002Fapi\u002F",[4114],[167,11298,11295],{},[280,11300,11301],{"className":2047,"code":11090,"language":1392,"meta":217,"style":217},[287,11302,11303],{"__ignoreMap":217},[332,11304,11305],{"class":334,"line":335},[332,11306,11090],{"class":338},[280,11308,11311],{"className":11309,"code":11310,"language":285},[283],"asyncData ({env}) {\n      return Promise.all([\n        \u002F\u002F fetch all blog posts sorted by creation date\n        contentfulClient.getEntries({\n          'content_type': 'page',\n          order: '-sys.createdAt'\n        })\n      ]).then(([pages]) => {\n        \u002F\u002F return data that should be available\n        \u002F\u002F in the template\n        return {\n          navItems: pages.items\n        }\n      }).catch(console.error)\n}\n",[287,11312,11310],{"__ignoreMap":217},[48,11314,11315,11316,11319],{},"Det der sker er, at vi starter med at hente alt indhold oprettet med content-typen ",[67,11317,11318],{},"page"," sorteret efter oprettelsesdato.",[48,11321,11322,11323,11325],{},"Når vi har dataen, tildeler vi den til egenskaben ",[67,11324,11233],{},", som også er prop-dataen, der sendes til vores navigationskomponent:",[48,11327,11328,11329,11331],{},"Din ",[67,11330,11086],{},"-fil bør nu ligne noget i denne retning:",[280,11333,11335],{"className":2460,"code":11334,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Csection class=\"container\">\n    \u003CNavigation \u002F>\n    \u003Cdiv class=\"container__content\">\n      \u003Ch1>Please select a page you wish to view\u003C\u002Fh1>\n      \u003Cp>This is a website for demo purposes of using Nuxt & Contentful together\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  \u003C\u002Fsection>\n\u003C\u002Ftemplate>\n",[287,11336,11337,11345,11359,11367,11382,11396,11409,11417,11425],{"__ignoreMap":217},[332,11338,11339,11341,11343],{"class":334,"line":335},[332,11340,374],{"class":355},[332,11342,2058],{"class":2057},[332,11344,2061],{"class":355},[332,11346,11347,11349,11351,11353,11355,11357],{"class":334,"line":218},[332,11348,2066],{"class":355},[332,11350,11116],{"class":2057},[332,11352,10874],{"class":351},[332,11354,440],{"class":355},[332,11356,11123],{"class":551},[332,11358,2061],{"class":355},[332,11360,11361,11363,11365],{"class":334,"line":226},[332,11362,2076],{"class":355},[332,11364,11132],{"class":2057},[332,11366,4424],{"class":355},[332,11368,11369,11371,11373,11375,11377,11380],{"class":334,"line":395},[332,11370,2076],{"class":355},[332,11372,2069],{"class":2057},[332,11374,10874],{"class":351},[332,11376,440],{"class":355},[332,11378,11379],{"class":551},"\"container__content\"",[332,11381,2061],{"class":355},[332,11383,11384,11386,11389,11392,11394],{"class":334,"line":415},[332,11385,2516],{"class":355},[332,11387,11388],{"class":2057},"h1",[332,11390,11391],{"class":355},">Please select a page you wish to view\u003C\u002F",[332,11393,11388],{"class":2057},[332,11395,2061],{"class":355},[332,11397,11398,11400,11402,11405,11407],{"class":334,"line":421},[332,11399,2516],{"class":355},[332,11401,48],{"class":2057},[332,11403,11404],{"class":355},">This is a website for demo purposes of using Nuxt & Contentful together\u003C\u002F",[332,11406,48],{"class":2057},[332,11408,2061],{"class":355},[332,11410,11411,11413,11415],{"class":334,"line":434},[332,11412,2577],{"class":355},[332,11414,2069],{"class":2057},[332,11416,2061],{"class":355},[332,11418,11419,11421,11423],{"class":334,"line":446},[332,11420,2103],{"class":355},[332,11422,11116],{"class":2057},[332,11424,2061],{"class":355},[332,11426,11427,11429,11431],{"class":334,"line":466},[332,11428,2112],{"class":355},[332,11430,2058],{"class":2057},[332,11432,2061],{"class":355},[280,11434,11436],{"className":2047,"code":11435,"language":1392,"meta":217,"style":217},"\u003Cscript>\nimport Navigation from '..\u002Fcomponents\u002FNavigation';\n",[287,11437,11438,11446],{"__ignoreMap":217},[332,11439,11440,11442,11444],{"class":334,"line":335},[332,11441,374],{"class":355},[332,11443,2127],{"class":2057},[332,11445,2061],{"class":355},[332,11447,11448],{"class":334,"line":218},[332,11449,11450],{"class":355},"import Navigation from '..\u002Fcomponents\u002FNavigation';\n",[280,11452,11454],{"className":2047,"code":11453,"language":1392,"meta":217,"style":217},"import {createClient} from '..\u002Fplugins\u002Fcontentful';\nconst contentfulClient = createClient();\n",[287,11455,11456,11469],{"__ignoreMap":217},[332,11457,11458,11460,11463,11465,11467],{"class":334,"line":335},[332,11459,3051],{"class":344},[332,11461,11462],{"class":355}," {createClient} ",[332,11464,3057],{"class":344},[332,11466,11266],{"class":551},[332,11468,2729],{"class":355},[332,11470,11471,11473,11475,11477,11479],{"class":334,"line":218},[332,11472,530],{"class":344},[332,11474,11275],{"class":364},[332,11476,368],{"class":344},[332,11478,11280],{"class":351},[332,11480,2906],{"class":355},[280,11482,11484],{"className":2047,"code":11483,"language":1392,"meta":217,"style":217},"export default {\n    components: {\n      Navigation\n    },\n    asyncData ({env}) {\n      return Promise.all([\n        \u002F\u002F fetch all blog posts sorted by creation date\n        contentfulClient.getEntries({\n          'content_type': 'page',\n          order: '-sys.createdAt'\n        })\n      ]).then(([pages]) => {\n        \u002F\u002F return data that should be available\n        \u002F\u002F in the template\n        return {\n          pages: pages.items\n        }\n      }).catch(console.error)\n    }\n  }\n\u003C\u002Fscript>\n",[287,11485,11486,11494,11498,11502,11506,11519,11533,11538,11548,11560,11568,11573,11591,11596,11601,11608,11613,11617,11627,11631,11635],{"__ignoreMap":217},[332,11487,11488,11490,11492],{"class":334,"line":335},[332,11489,345],{"class":344},[332,11491,3071],{"class":344},[332,11493,782],{"class":355},[332,11495,11496],{"class":334,"line":218},[332,11497,11198],{"class":355},[332,11499,11500],{"class":334,"line":226},[332,11501,11203],{"class":355},[332,11503,11504],{"class":334,"line":395},[332,11505,2176],{"class":355},[332,11507,11508,11511,11514,11516],{"class":334,"line":415},[332,11509,11510],{"class":351},"    asyncData",[332,11512,11513],{"class":355}," ({",[332,11515,10791],{"class":787},[332,11517,11518],{"class":355},"}) {\n",[332,11520,11521,11523,11525,11527,11530],{"class":334,"line":421},[332,11522,2714],{"class":344},[332,11524,5081],{"class":364},[332,11526,1956],{"class":355},[332,11528,11529],{"class":351},"all",[332,11531,11532],{"class":355},"([\n",[332,11534,11535],{"class":334,"line":434},[332,11536,11537],{"class":338},"        \u002F\u002F fetch all blog posts sorted by creation date\n",[332,11539,11540,11543,11546],{"class":334,"line":446},[332,11541,11542],{"class":355},"        contentfulClient.",[332,11544,11545],{"class":351},"getEntries",[332,11547,3920],{"class":355},[332,11549,11550,11553,11555,11558],{"class":334,"line":466},[332,11551,11552],{"class":551},"          'content_type'",[332,11554,7176],{"class":355},[332,11556,11557],{"class":551},"'page'",[332,11559,555],{"class":355},[332,11561,11562,11565],{"class":334,"line":476},[332,11563,11564],{"class":355},"          order: ",[332,11566,11567],{"class":551},"'-sys.createdAt'\n",[332,11569,11570],{"class":334,"line":482},[332,11571,11572],{"class":355},"        })\n",[332,11574,11575,11578,11580,11583,11585,11587,11589],{"class":334,"line":487},[332,11576,11577],{"class":355},"      ]).",[332,11579,5159],{"class":351},[332,11581,11582],{"class":355},"(([",[332,11584,11233],{"class":787},[332,11586,7941],{"class":355},[332,11588,566],{"class":344},[332,11590,782],{"class":355},[332,11592,11593],{"class":334,"line":496},[332,11594,11595],{"class":338},"        \u002F\u002F return data that should be available\n",[332,11597,11598],{"class":334,"line":2156},[332,11599,11600],{"class":338},"        \u002F\u002F in the template\n",[332,11602,11603,11606],{"class":334,"line":2162},[332,11604,11605],{"class":344},"        return",[332,11607,782],{"class":355},[332,11609,11610],{"class":334,"line":2173},[332,11611,11612],{"class":355},"          pages: pages.items\n",[332,11614,11615],{"class":334,"line":2179},[332,11616,11068],{"class":355},[332,11618,11619,11622,11624],{"class":334,"line":2184},[332,11620,11621],{"class":355},"      }).",[332,11623,2854],{"class":351},[332,11625,11626],{"class":355},"(console.error)\n",[332,11628,11629],{"class":334,"line":2193},[332,11630,3151],{"class":355},[332,11632,11633],{"class":334,"line":2204},[332,11634,479],{"class":355},[332,11636,11637,11639,11641],{"class":334,"line":2210},[332,11638,2112],{"class":344},[332,11640,2127],{"class":355},[332,11642,2061],{"class":344},[48,11644,11645],{},"Og din side ser nogenlunde sådan ud:",[48,11647,11648],{},[3592,11649],{"alt":217,"src":11650},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*RmCdhQC2orIgurqbz8sPTw.png",[48,11652,11653],{},"Wauw",[48,11655,11656],{},[3592,11657],{"alt":217,"src":11658},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*L_aETcsEt7HbMxvKZss7Bg.png",[48,11660,11661],{},"Var nødt til at inkludere et meme til dette!\nOk, måske ikke det pæneste, men igen, style og design som du synes :)",[48,11663,11664],{},"Anyway...... så langt, så godt... Hvad sker der nu, hvis du prøver at klikke på et af navigationspunkterne? Argh, du får en fejlside",[48,11666,11667],{},[3592,11668],{"alt":217,"src":11669},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*e-bYjcutWB8Lntz5b7d-bQ.png",[48,11671,11672,11673,11676,11677,11680,11681],{},"Lad os fixe dette.\nProblemet er, at Nuxt automatisk leder efter en komponent med samme navn som child-routen, hvilket betyder, at hvis du har en URL som: ",[67,11674,11675],{},"\u002Fabout"," — vil Nuxt lede efter en ",[67,11678,11679],{},"about.vue","-komponent eller en mappestruktur som ",[67,11682,11683],{},"\u002Fabout\u002Findex.vue",[48,11685,11686,11687,11690,11691,11693],{},"For at fixe dette skal vi oprette en ny komponent i ",[67,11688,11689],{},"\"pages\u002F_id\""," — kald den ",[67,11692,11086],{},"\nDet fortæller Nuxt at bruge denne komponent til alle child-routes, f.eks.: \u002Fabout",[48,11695,11696],{},"Vi kan nemt teste det og se, om det virker ved at tilføje noget hardkodet HTML:",[280,11698,11700],{"className":2047,"code":11699,"language":1392,"meta":217,"style":217},"\u002F\u002Fpages\u002F_id\u002Findex.vue\n",[287,11701,11702],{"__ignoreMap":217},[332,11703,11704],{"class":334,"line":335},[332,11705,11699],{"class":338},[280,11707,11709],{"className":2460,"code":11708,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Cdiv class=\"page-component\">\n    \u003Cp>This is the page component\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n    export default {\n        name: 'index'\n    }\n\u003C\u002Fscript>\n",[287,11710,11711,11719,11734,11747,11755,11763,11767,11775,11783,11790,11794],{"__ignoreMap":217},[332,11712,11713,11715,11717],{"class":334,"line":335},[332,11714,374],{"class":355},[332,11716,2058],{"class":2057},[332,11718,2061],{"class":355},[332,11720,11721,11723,11725,11727,11729,11732],{"class":334,"line":218},[332,11722,2066],{"class":355},[332,11724,2069],{"class":2057},[332,11726,10874],{"class":351},[332,11728,440],{"class":355},[332,11730,11731],{"class":551},"\"page-component\"",[332,11733,2061],{"class":355},[332,11735,11736,11738,11740,11743,11745],{"class":334,"line":226},[332,11737,2076],{"class":355},[332,11739,48],{"class":2057},[332,11741,11742],{"class":355},">This is the page component\u003C\u002F",[332,11744,48],{"class":2057},[332,11746,2061],{"class":355},[332,11748,11749,11751,11753],{"class":334,"line":395},[332,11750,2103],{"class":355},[332,11752,2069],{"class":2057},[332,11754,2061],{"class":355},[332,11756,11757,11759,11761],{"class":334,"line":415},[332,11758,2112],{"class":355},[332,11760,2058],{"class":2057},[332,11762,2061],{"class":355},[332,11764,11765],{"class":334,"line":421},[332,11766,418],{"emptyLinePlaceholder":238},[332,11768,11769,11771,11773],{"class":334,"line":434},[332,11770,374],{"class":355},[332,11772,2127],{"class":2057},[332,11774,2061],{"class":355},[332,11776,11777,11779,11781],{"class":334,"line":446},[332,11778,11018],{"class":344},[332,11780,3071],{"class":344},[332,11782,782],{"class":355},[332,11784,11785,11787],{"class":334,"line":466},[332,11786,11027],{"class":355},[332,11788,11789],{"class":551},"'index'\n",[332,11791,11792],{"class":334,"line":476},[332,11793,3151],{"class":355},[332,11795,11796,11798,11800],{"class":334,"line":482},[332,11797,2112],{"class":355},[332,11799,2127],{"class":2057},[332,11801,2061],{"class":355},[48,11803,11804],{},"Når du nu klikker på et af linkene i vores navigation, bør du se noget som dette:",[48,11806,11807],{},[3592,11808],{"alt":217,"src":11809},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*9k4yvikNCzBdRRPNhUVDBA.png",[48,11811,11812,11813,11815],{},"Næste skridt er at hente indholdet af den aktuelle side. Igen importerer vi ",[67,11814],{"create-client":217}," fra vores Contentful-plugin og tildeler det til en variabel",[280,11817,11819],{"className":2047,"code":11818,"language":1392,"meta":217,"style":217},"import {createClient} from '..\u002F..\u002Fplugins\u002Fcontentful';\nconst contentfulClient = createClient();\n",[287,11820,11821,11834],{"__ignoreMap":217},[332,11822,11823,11825,11827,11829,11832],{"class":334,"line":335},[332,11824,3051],{"class":344},[332,11826,11462],{"class":355},[332,11828,3057],{"class":344},[332,11830,11831],{"class":551}," '..\u002F..\u002Fplugins\u002Fcontentful'",[332,11833,2729],{"class":355},[332,11835,11836,11838,11840,11842,11844],{"class":334,"line":218},[332,11837,530],{"class":344},[332,11839,11275],{"class":364},[332,11841,368],{"class":344},[332,11843,11280],{"class":351},[332,11845,2906],{"class":355},[48,11847,11848,11849,791],{},"Og igen skal vi bruge asyncData-metoden, men denne gang henter vi dataen ved at ",[67,11850,11851],{},"matche sluggen og parametrene fra URL'en",[280,11853,11856],{"className":11854,"code":11855,"language":285},[283],"asyncData ({ env, params }) {\n  return contentfulClient.getEntries({\n    'content_type': page,\n    'fields.slug': params.id \u002F\u002F the magic happens here\n  }).then(page => {\n    return {\n      page: page.items[0]\n    }\n  }).catch(console.error)\n}\n",[287,11857,11855],{"__ignoreMap":217},[48,11859,11860,11861,11863],{},"Nu har vi adgang til dataen i egenskaben: ",[67,11862,11318],{},". Du kan nu oprette din template HTML og style den, som du vil — den fulde komponent bør nu se nogenlunde sådan ud:",[280,11865,11867],{"className":2047,"code":11866,"language":1392,"meta":217,"style":217},"\u002F\u002F pages\u002F_id\u002Findex.vue\n",[287,11868,11869],{"__ignoreMap":217},[332,11870,11871],{"class":334,"line":335},[332,11872,11866],{"class":338},[280,11874,11876],{"className":2460,"code":11875,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Cdiv class=\"page-component\">\n    \u003Ca @click=\"$router.go(-1)\">Go back to overview\u003C\u002Fa>\n    \u003Chr \u002F>\n    \u003Ch1>{{page.fields.heading}}\u003C\u002Fh1>\n    \u003Cimg :src=\"page.fields.image.fields.file.url\" :alt=\"page.fields.heading\" v-if=\"page.fields.image\" \u002F>\n    \u003Cp>\n      {{page.fields.content}}\n    \u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  import {createClient} from '..\u002F..\u002Fplugins\u002Fcontentful';\n  const contentfulClient = createClient();\n\n  export default {\n    name: 'index',\n    asyncData ({ env, params }) {\n      return contentfulClient.getEntries({\n        'content_type': 'page',\n        'fields.slug': params.id\n      }).then(page => {\n        return {\n          page: page.items[0]\n        }\n      }).catch(console.error)\n    }\n  }\n\u003C\u002Fscript>\n",[287,11877,11878,11886,11900,11920,11928,11941,11972,11980,11985,11993,12001,12009,12013,12021,12033,12045,12049,12057,12067,12084,12095,12106,12114,12128,12134,12143,12147,12155,12159,12163],{"__ignoreMap":217},[332,11879,11880,11882,11884],{"class":334,"line":335},[332,11881,374],{"class":355},[332,11883,2058],{"class":2057},[332,11885,2061],{"class":355},[332,11887,11888,11890,11892,11894,11896,11898],{"class":334,"line":218},[332,11889,2066],{"class":355},[332,11891,2069],{"class":2057},[332,11893,10874],{"class":351},[332,11895,440],{"class":355},[332,11897,11731],{"class":551},[332,11899,2061],{"class":355},[332,11901,11902,11904,11906,11908,11910,11913,11916,11918],{"class":334,"line":226},[332,11903,2076],{"class":355},[332,11905,966],{"class":2057},[332,11907,5897],{"class":351},[332,11909,440],{"class":355},[332,11911,11912],{"class":551},"\"$router.go(-1)\"",[332,11914,11915],{"class":355},">Go back to overview\u003C\u002F",[332,11917,966],{"class":2057},[332,11919,2061],{"class":355},[332,11921,11922,11924,11926],{"class":334,"line":395},[332,11923,2076],{"class":355},[332,11925,960],{"class":2057},[332,11927,4424],{"class":355},[332,11929,11930,11932,11934,11937,11939],{"class":334,"line":415},[332,11931,2076],{"class":355},[332,11933,11388],{"class":2057},[332,11935,11936],{"class":355},">{{page.fields.heading}}\u003C\u002F",[332,11938,11388],{"class":2057},[332,11940,2061],{"class":355},[332,11942,11943,11945,11947,11950,11952,11955,11958,11960,11963,11965,11967,11970],{"class":334,"line":421},[332,11944,2076],{"class":355},[332,11946,3592],{"class":2057},[332,11948,11949],{"class":351}," :src",[332,11951,440],{"class":355},[332,11953,11954],{"class":551},"\"page.fields.image.fields.file.url\"",[332,11956,11957],{"class":351}," :alt",[332,11959,440],{"class":355},[332,11961,11962],{"class":551},"\"page.fields.heading\"",[332,11964,2488],{"class":351},[332,11966,440],{"class":355},[332,11968,11969],{"class":551},"\"page.fields.image\"",[332,11971,4424],{"class":355},[332,11973,11974,11976,11978],{"class":334,"line":434},[332,11975,2076],{"class":355},[332,11977,48],{"class":2057},[332,11979,2061],{"class":355},[332,11981,11982],{"class":334,"line":446},[332,11983,11984],{"class":355},"      {{page.fields.content}}\n",[332,11986,11987,11989,11991],{"class":334,"line":466},[332,11988,2577],{"class":355},[332,11990,48],{"class":2057},[332,11992,2061],{"class":355},[332,11994,11995,11997,11999],{"class":334,"line":476},[332,11996,2103],{"class":355},[332,11998,2069],{"class":2057},[332,12000,2061],{"class":355},[332,12002,12003,12005,12007],{"class":334,"line":482},[332,12004,2112],{"class":355},[332,12006,2058],{"class":2057},[332,12008,2061],{"class":355},[332,12010,12011],{"class":334,"line":487},[332,12012,418],{"emptyLinePlaceholder":238},[332,12014,12015,12017,12019],{"class":334,"line":496},[332,12016,374],{"class":355},[332,12018,2127],{"class":2057},[332,12020,2061],{"class":355},[332,12022,12023,12025,12027,12029,12031],{"class":334,"line":2156},[332,12024,4580],{"class":344},[332,12026,11462],{"class":355},[332,12028,3057],{"class":344},[332,12030,11831],{"class":551},[332,12032,2729],{"class":355},[332,12034,12035,12037,12039,12041,12043],{"class":334,"line":2162},[332,12036,361],{"class":344},[332,12038,11275],{"class":364},[332,12040,368],{"class":344},[332,12042,11280],{"class":351},[332,12044,2906],{"class":355},[332,12046,12047],{"class":334,"line":2173},[332,12048,418],{"emptyLinePlaceholder":238},[332,12050,12051,12053,12055],{"class":334,"line":2179},[332,12052,11189],{"class":344},[332,12054,3071],{"class":344},[332,12056,782],{"class":355},[332,12058,12059,12062,12065],{"class":334,"line":2184},[332,12060,12061],{"class":355},"    name: ",[332,12063,12064],{"class":551},"'index'",[332,12066,555],{"class":355},[332,12068,12069,12071,12074,12076,12078,12081],{"class":334,"line":2193},[332,12070,11510],{"class":351},[332,12072,12073],{"class":355}," ({ ",[332,12075,10791],{"class":787},[332,12077,687],{"class":355},[332,12079,12080],{"class":787},"params",[332,12082,12083],{"class":355}," }) {\n",[332,12085,12086,12088,12091,12093],{"class":334,"line":2204},[332,12087,2714],{"class":344},[332,12089,12090],{"class":355}," contentfulClient.",[332,12092,11545],{"class":351},[332,12094,3920],{"class":355},[332,12096,12097,12100,12102,12104],{"class":334,"line":2210},[332,12098,12099],{"class":551},"        'content_type'",[332,12101,7176],{"class":355},[332,12103,11557],{"class":551},[332,12105,555],{"class":355},[332,12107,12108,12111],{"class":334,"line":2215},[332,12109,12110],{"class":551},"        'fields.slug'",[332,12112,12113],{"class":355},": params.id\n",[332,12115,12116,12118,12120,12122,12124,12126],{"class":334,"line":2221},[332,12117,11621],{"class":355},[332,12119,5159],{"class":351},[332,12121,407],{"class":355},[332,12123,11318],{"class":787},[332,12125,7508],{"class":344},[332,12127,782],{"class":355},[332,12129,12130,12132],{"class":334,"line":2801},[332,12131,11605],{"class":344},[332,12133,782],{"class":355},[332,12135,12136,12139,12141],{"class":334,"line":2828},[332,12137,12138],{"class":355},"          page: page.items[",[332,12140,3096],{"class":364},[332,12142,620],{"class":355},[332,12144,12145],{"class":334,"line":2848},[332,12146,11068],{"class":355},[332,12148,12149,12151,12153],{"class":334,"line":2860},[332,12150,11621],{"class":355},[332,12152,2854],{"class":351},[332,12154,11626],{"class":355},[332,12156,12157],{"class":334,"line":2883},[332,12158,3151],{"class":355},[332,12160,12161],{"class":334,"line":2889},[332,12162,479],{"class":355},[332,12164,12165,12167,12169],{"class":334,"line":2895},[332,12166,2112],{"class":355},[332,12168,2127],{"class":2057},[332,12170,2061],{"class":355},[48,12172,11645],{},[48,12174,12175],{},[3592,12176],{"alt":217,"src":12177},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*0PB0VjGqseLYBJVBZZXuUw.png",[43,12179,12181],{"id":12180},"næsten-i-mål","Næsten i mål...",[48,12183,12184],{},"Vi har nu et fungerende website, men det mangler stadig et par ting. Navigationen mangler, når vi kigger på en side, og når vi er på forsiden, har vi ingen kontrol over rækkefølgen af vores navigationspunkter. Ikke ligefrem det bedste UX-mønster. Lad os også fixe dette.",[48,12186,12187,12188,12191,12192,12195],{},"Flyt navigationskomponenten ud af vores ",[67,12189,12190],{},"\"pages\u002Findex\"",", og placer den i ",[67,12193,12194],{},"\"layouts\u002Fdefault\"",", og fjern de props, der sendes til vores navigationskomponent (husk også at fjerne dem inde i selve komponenten)",[280,12197,12199],{"className":2047,"code":12198,"language":1392,"meta":217,"style":217},"\u002F\u002Flayout\u002Fdefault.vue\n",[287,12200,12201],{"__ignoreMap":217},[332,12202,12203],{"class":334,"line":335},[332,12204,12198],{"class":338},[280,12206,12208],{"className":2460,"code":12207,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n   \u003Cdiv>\n     \u003CNavigation>\u003C\u002FNavigation>\n     \u003Cnuxt\u002F>\n   \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[287,12209,12210,12218,12227,12241,12250,12259],{"__ignoreMap":217},[332,12211,12212,12214,12216],{"class":334,"line":335},[332,12213,374],{"class":355},[332,12215,2058],{"class":2057},[332,12217,2061],{"class":355},[332,12219,12220,12223,12225],{"class":334,"line":218},[332,12221,12222],{"class":355},"   \u003C",[332,12224,2069],{"class":2057},[332,12226,2061],{"class":355},[332,12228,12229,12232,12234,12237,12239],{"class":334,"line":226},[332,12230,12231],{"class":355},"     \u003C",[332,12233,11132],{"class":2057},[332,12235,12236],{"class":355},">\u003C\u002F",[332,12238,11132],{"class":2057},[332,12240,2061],{"class":355},[332,12242,12243,12245,12247],{"class":334,"line":395},[332,12244,12231],{"class":355},[332,12246,10205],{"class":2057},[332,12248,12249],{"class":355},"\u002F>\n",[332,12251,12252,12255,12257],{"class":334,"line":415},[332,12253,12254],{"class":355},"   \u003C\u002F",[332,12256,2069],{"class":2057},[332,12258,2061],{"class":355},[332,12260,12261,12263,12265],{"class":334,"line":421},[332,12262,2112],{"class":355},[332,12264,2058],{"class":2057},[332,12266,2061],{"class":355},[280,12268,12270],{"className":2460,"code":12269,"language":997,"meta":217,"style":217},"\u003Cscript>\n   import Navigation from '..\u002Fcomponents\u002FNavigation';\n \n   export default {\n     components: {\n       Navigation\n     }\n   }\n \u003C\u002Fscript>\n",[287,12271,12272,12280,12293,12298,12307,12312,12317,12322,12327],{"__ignoreMap":217},[332,12273,12274,12276,12278],{"class":334,"line":335},[332,12275,374],{"class":355},[332,12277,2127],{"class":2057},[332,12279,2061],{"class":355},[332,12281,12282,12285,12287,12289,12291],{"class":334,"line":218},[332,12283,12284],{"class":344},"   import",[332,12286,11177],{"class":355},[332,12288,3057],{"class":344},[332,12290,11182],{"class":551},[332,12292,2729],{"class":355},[332,12294,12295],{"class":334,"line":226},[332,12296,12297],{"class":355}," \n",[332,12299,12300,12303,12305],{"class":334,"line":395},[332,12301,12302],{"class":344},"   export",[332,12304,3071],{"class":344},[332,12306,782],{"class":355},[332,12308,12309],{"class":334,"line":415},[332,12310,12311],{"class":355},"     components: {\n",[332,12313,12314],{"class":334,"line":421},[332,12315,12316],{"class":355},"       Navigation\n",[332,12318,12319],{"class":334,"line":434},[332,12320,12321],{"class":355},"     }\n",[332,12323,12324],{"class":334,"line":446},[332,12325,12326],{"class":355},"   }\n",[332,12328,12329,12332,12334],{"class":334,"line":466},[332,12330,12331],{"class":355}," \u003C\u002F",[332,12333,2127],{"class":2057},[332,12335,2061],{"class":355},[48,12337,12338,12339],{},"Desværre tillader Nuxt os ikke at bruge asyncData-metoden i layoutet. Hvis vi prøver, får vi en fejl, når vi henter indhold fra Contentful.\nMere om det her: ",[966,12340,12341],{"href":12341,"rel":12342},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt.js\u002Fissues\u002F1740",[4114],[43,12344,12346],{"id":12345},"brug-vuex","Brug Vuex",[48,12348,12349,12350,12353,12354,12357,12358,12361],{},"I dette tilfælde bruger vi ",[67,12351,12352],{},"Vuex"," til at løse vores problem. Gå til ",[67,12355,12356],{},"store-mappen"," og opret en ",[67,12359,12360],{},"index.js","-fil.",[280,12363,12365],{"className":2047,"code":12364,"language":1392,"meta":217,"style":217},"\u002F\u002Fstore\u002Findex.js\n",[287,12366,12367],{"__ignoreMap":217},[332,12368,12369],{"class":334,"line":335},[332,12370,12364],{"class":338},[280,12372,12374],{"className":2047,"code":12373,"language":1392,"meta":217,"style":217},"import Vuex from 'vuex';\nimport navigation from '.\u002Fmodules\u002Fnavigation';\n\nconst createStore = () => {\n  return new Vuex.Store({\n    modules: {\n      navigation: { ...navigation, namespaced: true }\n    },\n    strict: false\n  })\n};\n\nexport default createStore\n",[287,12375,12376,12390,12404,12408,12423,12437,12442,12457,12461,12469,12474,12478,12482],{"__ignoreMap":217},[332,12377,12378,12380,12383,12385,12388],{"class":334,"line":335},[332,12379,3051],{"class":344},[332,12381,12382],{"class":355}," Vuex ",[332,12384,3057],{"class":344},[332,12386,12387],{"class":551}," 'vuex'",[332,12389,2729],{"class":355},[332,12391,12392,12394,12397,12399,12402],{"class":334,"line":218},[332,12393,3051],{"class":344},[332,12395,12396],{"class":355}," navigation ",[332,12398,3057],{"class":344},[332,12400,12401],{"class":551}," '.\u002Fmodules\u002Fnavigation'",[332,12403,2729],{"class":355},[332,12405,12406],{"class":334,"line":226},[332,12407,418],{"emptyLinePlaceholder":238},[332,12409,12410,12412,12415,12417,12419,12421],{"class":334,"line":395},[332,12411,530],{"class":344},[332,12413,12414],{"class":351}," createStore",[332,12416,368],{"class":344},[332,12418,2787],{"class":355},[332,12420,566],{"class":344},[332,12422,782],{"class":355},[332,12424,12425,12427,12429,12432,12435],{"class":334,"line":415},[332,12426,490],{"class":344},[332,12428,2866],{"class":344},[332,12430,12431],{"class":355}," Vuex.",[332,12433,12434],{"class":351},"Store",[332,12436,3920],{"class":355},[332,12438,12439],{"class":334,"line":421},[332,12440,12441],{"class":355},"    modules: {\n",[332,12443,12444,12447,12449,12452,12454],{"class":334,"line":434},[332,12445,12446],{"class":355},"      navigation: { ",[332,12448,5293],{"class":344},[332,12450,12451],{"class":355},"navigation, namespaced: ",[332,12453,2168],{"class":364},[332,12455,12456],{"class":355}," }\n",[332,12458,12459],{"class":334,"line":446},[332,12460,2176],{"class":355},[332,12462,12463,12466],{"class":334,"line":466},[332,12464,12465],{"class":355},"    strict: ",[332,12467,12468],{"class":364},"false\n",[332,12470,12471],{"class":334,"line":476},[332,12472,12473],{"class":355},"  })\n",[332,12475,12476],{"class":334,"line":482},[332,12477,2218],{"class":355},[332,12479,12480],{"class":334,"line":487},[332,12481,418],{"emptyLinePlaceholder":238},[332,12483,12484,12486,12488],{"class":334,"line":496},[332,12485,345],{"class":344},[332,12487,3071],{"class":344},[332,12489,12490],{"class":355}," createStore\n",[48,12492,12493],{},"Som du kan se, importerer vi en fil kaldet navigation, der ikke eksisterer endnu, så vi skal oprette den og lave lidt arbejde:",[280,12495,12497],{"className":2047,"code":12496,"language":1392,"meta":217,"style":217},"\u002F\u002Fstore\u002Fmodules\u002Fnavigation.js\n",[287,12498,12499],{"__ignoreMap":217},[332,12500,12501],{"class":334,"line":335},[332,12502,12496],{"class":338},[280,12504,12505],{"className":2047,"code":11818,"language":1392,"meta":217,"style":217},[287,12506,12507,12519],{"__ignoreMap":217},[332,12508,12509,12511,12513,12515,12517],{"class":334,"line":335},[332,12510,3051],{"class":344},[332,12512,11462],{"class":355},[332,12514,3057],{"class":344},[332,12516,11831],{"class":551},[332,12518,2729],{"class":355},[332,12520,12521,12523,12525,12527,12529],{"class":334,"line":218},[332,12522,530],{"class":344},[332,12524,11275],{"class":364},[332,12526,368],{"class":344},[332,12528,11280],{"class":351},[332,12530,2906],{"class":355},[280,12532,12534],{"className":2047,"code":12533,"language":1392,"meta":217,"style":217},"export const state = {\n  navItems: null\n};\n\nexport const mutations = {\n  setMenuItems(state, data) {\n    state.navItems = data;\n  }\n};\n\nexport const actions = {\n  getPageItems({commit}) {\n    contentfulClient.getEntries({\n      'content_type': page,\n      order: '-sys.createdAt'\n    }).then((page) => {\n      if(page) {\n        const navItems = page.items;\n        commit('setMenuItems', navItems);\n      }\n    }).catch((err) => {\n      console.log(\"error\", err);\n    });\n  }\n};\n\nexport default {\n  state,\n  mutations,\n  actions,\n};\n",[287,12535,12536,12549,12557,12561,12565,12578,12594,12604,12608,12612,12616,12629,12642,12651,12659,12666,12683,12691,12703,12716,12720,12736,12751,12755,12759,12763,12767,12775,12780,12785,12790],{"__ignoreMap":217},[332,12537,12538,12540,12542,12545,12547],{"class":334,"line":335},[332,12539,345],{"class":344},[332,12541,6833],{"class":344},[332,12543,12544],{"class":364}," state",[332,12546,368],{"class":344},[332,12548,782],{"class":355},[332,12550,12551,12554],{"class":334,"line":218},[332,12552,12553],{"class":355},"  navItems: ",[332,12555,12556],{"class":364},"null\n",[332,12558,12559],{"class":334,"line":226},[332,12560,2218],{"class":355},[332,12562,12563],{"class":334,"line":395},[332,12564,418],{"emptyLinePlaceholder":238},[332,12566,12567,12569,12571,12574,12576],{"class":334,"line":415},[332,12568,345],{"class":344},[332,12570,6833],{"class":344},[332,12572,12573],{"class":364}," mutations",[332,12575,368],{"class":344},[332,12577,782],{"class":355},[332,12579,12580,12583,12585,12588,12590,12592],{"class":334,"line":421},[332,12581,12582],{"class":351},"  setMenuItems",[332,12584,407],{"class":355},[332,12586,12587],{"class":787},"state",[332,12589,687],{"class":355},[332,12591,3501],{"class":787},[332,12593,6543],{"class":355},[332,12595,12596,12599,12601],{"class":334,"line":434},[332,12597,12598],{"class":355},"    state.navItems ",[332,12600,440],{"class":344},[332,12602,12603],{"class":355}," data;\n",[332,12605,12606],{"class":334,"line":446},[332,12607,479],{"class":355},[332,12609,12610],{"class":334,"line":466},[332,12611,2218],{"class":355},[332,12613,12614],{"class":334,"line":476},[332,12615,418],{"emptyLinePlaceholder":238},[332,12617,12618,12620,12622,12625,12627],{"class":334,"line":482},[332,12619,345],{"class":344},[332,12621,6833],{"class":344},[332,12623,12624],{"class":364}," actions",[332,12626,368],{"class":344},[332,12628,782],{"class":355},[332,12630,12631,12634,12637,12640],{"class":334,"line":487},[332,12632,12633],{"class":351},"  getPageItems",[332,12635,12636],{"class":355},"({",[332,12638,12639],{"class":787},"commit",[332,12641,11518],{"class":355},[332,12643,12644,12647,12649],{"class":334,"line":496},[332,12645,12646],{"class":355},"    contentfulClient.",[332,12648,11545],{"class":351},[332,12650,3920],{"class":355},[332,12652,12653,12656],{"class":334,"line":2156},[332,12654,12655],{"class":551},"      'content_type'",[332,12657,12658],{"class":355},": page,\n",[332,12660,12661,12664],{"class":334,"line":2162},[332,12662,12663],{"class":355},"      order: ",[332,12665,11567],{"class":551},[332,12667,12668,12671,12673,12675,12677,12679,12681],{"class":334,"line":2173},[332,12669,12670],{"class":355},"    }).",[332,12672,5159],{"class":351},[332,12674,5162],{"class":355},[332,12676,11318],{"class":787},[332,12678,4055],{"class":355},[332,12680,566],{"class":344},[332,12682,782],{"class":355},[332,12684,12685,12688],{"class":334,"line":2179},[332,12686,12687],{"class":344},"      if",[332,12689,12690],{"class":355},"(page) {\n",[332,12692,12693,12695,12698,12700],{"class":334,"line":2184},[332,12694,2804],{"class":344},[332,12696,12697],{"class":364}," navItems",[332,12699,368],{"class":344},[332,12701,12702],{"class":355}," page.items;\n",[332,12704,12705,12708,12710,12713],{"class":334,"line":2193},[332,12706,12707],{"class":351},"        commit",[332,12709,407],{"class":355},[332,12711,12712],{"class":551},"'setMenuItems'",[332,12714,12715],{"class":355},", navItems);\n",[332,12717,12718],{"class":334,"line":2204},[332,12719,2886],{"class":355},[332,12721,12722,12724,12726,12728,12730,12732,12734],{"class":334,"line":2210},[332,12723,12670],{"class":355},[332,12725,2854],{"class":351},[332,12727,5162],{"class":355},[332,12729,5187],{"class":787},[332,12731,4055],{"class":355},[332,12733,566],{"class":344},[332,12735,782],{"class":355},[332,12737,12738,12741,12743,12745,12748],{"class":334,"line":2215},[332,12739,12740],{"class":355},"      console.",[332,12742,4804],{"class":351},[332,12744,407],{"class":355},[332,12746,12747],{"class":551},"\"error\"",[332,12749,12750],{"class":355},", err);\n",[332,12752,12753],{"class":334,"line":2221},[332,12754,2734],{"class":355},[332,12756,12757],{"class":334,"line":2801},[332,12758,479],{"class":355},[332,12760,12761],{"class":334,"line":2828},[332,12762,2218],{"class":355},[332,12764,12765],{"class":334,"line":2848},[332,12766,418],{"emptyLinePlaceholder":238},[332,12768,12769,12771,12773],{"class":334,"line":2860},[332,12770,345],{"class":344},[332,12772,3071],{"class":344},[332,12774,782],{"class":355},[332,12776,12777],{"class":334,"line":2883},[332,12778,12779],{"class":355},"  state,\n",[332,12781,12782],{"class":334,"line":2889},[332,12783,12784],{"class":355},"  mutations,\n",[332,12786,12787],{"class":334,"line":2895},[332,12788,12789],{"class":355},"  actions,\n",[332,12791,12792],{"class":334,"line":2900},[332,12793,2218],{"class":355},[48,12795,12796],{},[67,12797,12798],{},"Bemærk: Husk at fjerne al asyncData fra pages\u002Findex.vue, da vi ikke længere har brug for det",[48,12800,12801],{},"Vi opretter en action, der committer vores navigationspunkter. Når vi committer, muterer vi staten og gemmer grundlæggende navigationspunkterne i staten.",[48,12803,12804],{},"Dernæst skal vi refaktorere vores navigationskomponent til at hente data fra storen.",[280,12806,12808],{"className":2047,"code":12807,"language":1392,"meta":217,"style":217},"\u002F\u002Fcomponents\u002FNavigation.vue\n",[287,12809,12810],{"__ignoreMap":217},[332,12811,12812],{"class":334,"line":335},[332,12813,12807],{"class":338},[280,12815,12817],{"className":2460,"code":12816,"language":997,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Cdiv class=\"navigation\">\n    \u003Cnav>\n      \u003Cul role=\"menu\">\n        \u003Cli v-for=\"(navItem, index) in navItems\" :key=\"index\">\n          \u003Cnuxt-link :to=\"'\u002F' + navItem.fields.slug.trim()\" role=\"menuitem\">{{navItem.fields.navTitle}}\u003C\u002Fnuxt-link>\n        \u003C\u002Fli>\n      \u003C\u002Ful>\n    \u003C\u002Fnav>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n  import {mapState} from 'vuex';\n  export default {\n    name: 'Navigation',\n    computed: {\n      ...mapState('navigation', [\n        'navItems'\n      ])\n    },\n    mounted() {\n      this.$store.dispatch(\"navigation\u002FgetPageItems\");\n    }\n  }\n\u003C\u002Fscript>\n",[287,12818,12819,12827,12841,12849,12863,12884,12908,12916,12924,12932,12940,12948,12952,12960,12973,12981,12989,12994,13010,13015,13020,13024,13031,13048,13052,13056],{"__ignoreMap":217},[332,12820,12821,12823,12825],{"class":334,"line":335},[332,12822,374],{"class":355},[332,12824,2058],{"class":2057},[332,12826,2061],{"class":355},[332,12828,12829,12831,12833,12835,12837,12839],{"class":334,"line":218},[332,12830,2066],{"class":355},[332,12832,2069],{"class":2057},[332,12834,10874],{"class":351},[332,12836,440],{"class":355},[332,12838,10879],{"class":551},[332,12840,2061],{"class":355},[332,12842,12843,12845,12847],{"class":334,"line":226},[332,12844,2076],{"class":355},[332,12846,10888],{"class":2057},[332,12848,2061],{"class":355},[332,12850,12851,12853,12855,12857,12859,12861],{"class":334,"line":395},[332,12852,2516],{"class":355},[332,12854,625],{"class":2057},[332,12856,10899],{"class":351},[332,12858,440],{"class":355},[332,12860,10904],{"class":551},[332,12862,2061],{"class":355},[332,12864,12865,12867,12869,12871,12873,12876,12878,12880,12882],{"class":334,"line":415},[332,12866,2525],{"class":355},[332,12868,628],{"class":2057},[332,12870,2530],{"class":351},[332,12872,440],{"class":355},[332,12874,12875],{"class":551},"\"(navItem, index) in navItems\"",[332,12877,2538],{"class":351},[332,12879,440],{"class":355},[332,12881,10927],{"class":551},[332,12883,2061],{"class":355},[332,12885,12886,12888,12890,12892,12894,12896,12898,12900,12902,12904,12906],{"class":334,"line":421},[332,12887,10911],{"class":355},[332,12889,10937],{"class":2057},[332,12891,10940],{"class":351},[332,12893,440],{"class":355},[332,12895,10945],{"class":551},[332,12897,10899],{"class":351},[332,12899,440],{"class":355},[332,12901,10952],{"class":551},[332,12903,10955],{"class":355},[332,12905,10937],{"class":2057},[332,12907,2061],{"class":355},[332,12909,12910,12912,12914],{"class":334,"line":434},[332,12911,10973],{"class":355},[332,12913,628],{"class":2057},[332,12915,2061],{"class":355},[332,12917,12918,12920,12922],{"class":334,"line":446},[332,12919,2555],{"class":355},[332,12921,625],{"class":2057},[332,12923,2061],{"class":355},[332,12925,12926,12928,12930],{"class":334,"line":466},[332,12927,2577],{"class":355},[332,12929,10888],{"class":2057},[332,12931,2061],{"class":355},[332,12933,12934,12936,12938],{"class":334,"line":476},[332,12935,2103],{"class":355},[332,12937,2069],{"class":2057},[332,12939,2061],{"class":355},[332,12941,12942,12944,12946],{"class":334,"line":482},[332,12943,2112],{"class":355},[332,12945,2058],{"class":2057},[332,12947,2061],{"class":355},[332,12949,12950],{"class":334,"line":487},[332,12951,418],{"emptyLinePlaceholder":238},[332,12953,12954,12956,12958],{"class":334,"line":496},[332,12955,374],{"class":355},[332,12957,2127],{"class":2057},[332,12959,2061],{"class":355},[332,12961,12962,12964,12967,12969,12971],{"class":334,"line":2156},[332,12963,4580],{"class":344},[332,12965,12966],{"class":355}," {mapState} ",[332,12968,3057],{"class":344},[332,12970,12387],{"class":551},[332,12972,2729],{"class":355},[332,12974,12975,12977,12979],{"class":334,"line":2162},[332,12976,11189],{"class":344},[332,12978,3071],{"class":344},[332,12980,782],{"class":355},[332,12982,12983,12985,12987],{"class":334,"line":2173},[332,12984,12061],{"class":355},[332,12986,11030],{"class":551},[332,12988,555],{"class":355},[332,12990,12991],{"class":334,"line":2179},[332,12992,12993],{"class":355},"    computed: {\n",[332,12995,12996,12999,13002,13004,13007],{"class":334,"line":2184},[332,12997,12998],{"class":344},"      ...",[332,13000,13001],{"class":351},"mapState",[332,13003,407],{"class":355},[332,13005,13006],{"class":551},"'navigation'",[332,13008,13009],{"class":355},", [\n",[332,13011,13012],{"class":334,"line":2193},[332,13013,13014],{"class":551},"        'navItems'\n",[332,13016,13017],{"class":334,"line":2204},[332,13018,13019],{"class":355},"      ])\n",[332,13021,13022],{"class":334,"line":2210},[332,13023,2176],{"class":355},[332,13025,13026,13029],{"class":334,"line":2215},[332,13027,13028],{"class":351},"    mounted",[332,13030,356],{"class":355},[332,13032,13033,13035,13038,13041,13043,13046],{"class":334,"line":2221},[332,13034,3339],{"class":364},[332,13036,13037],{"class":355},".$store.",[332,13039,13040],{"class":351},"dispatch",[332,13042,407],{"class":355},[332,13044,13045],{"class":551},"\"navigation\u002FgetPageItems\"",[332,13047,2825],{"class":355},[332,13049,13050],{"class":334,"line":2801},[332,13051,3151],{"class":355},[332,13053,13054],{"class":334,"line":2828},[332,13055,479],{"class":355},[332,13057,13058,13060,13062],{"class":334,"line":2848},[332,13059,2112],{"class":355},[332,13061,2127],{"class":2057},[332,13063,2061],{"class":355},[48,13065,13066],{},"Når du nu tjekker, bør vores navigation være fuldt funktionel igen, og når du går til en side, vil vores navigation være synlig.",[48,13068,13069],{},[3592,13070],{"alt":217,"src":13071},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*6GN1jcv54g8tcSgMhRaXlw.png",[48,13073,13074],{},"For at kontrollere rækkefølgen af navigationspunkterne kan du tilføje et order-felt i din content-type. Det er også muligt at oprette en separat content-type til navigationspunkter, oprette en global \"container\" og bruge reference-feltet i Contentful.",[48,13076,13077],{},[3592,13078],{"alt":217,"src":13079},"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*hFE6A3wkLreidwiP_OzlpA.png",[48,13081,13082],{},"Der er masser af forskellige måder, du kan gøre dette på, og det afhænger alt sammen af, hvordan du vælger at strukturere og administrere dine data i Contentful, da der ikke er nogen specifikke retningslinjer for, hvordan man strukturerer indhold.",[43,13084,13086],{"id":13085},"du-er-i-mål","Du er i mål",[48,13088,13089,13090,13093],{},"Du har nu bygget dit første meget basale website med Nuxt og Contentful, og selvom ",[67,13091,13092],{},"dette er et meget basalt eksempel",", håber jeg, du får idéen om, hvordan du kan bruge disse to platforme til at skabe meget kraftfulde og fantastiske applikationer.",[48,13095,13096,13097],{},"Find det fulde repo her:\n",[966,13098,10243],{"href":10243,"rel":13099},[4114],[43,13101,13103],{"id":13102},"næste-skridt","Næste skridt:",[48,13105,13106],{},"Nu hvor du har fået styr på det grundlæggende, opfordrer jeg dig til at prøve at bygge et rigtigt website med det, du har lært.",[48,13108,13109],{},"I fremtiden vil jeg prøve at dække emner som",[625,13111,13112,13115,13118,13121,13124,13127],{},[628,13113,13114],{},"Hvordan du forbinder og deployer dit statiske site til Netlify",[628,13116,13117],{},"Hvordan du genererer et sitemap med Nuxt",[628,13119,13120],{},"Generering af filer fra dynamiske routes",[628,13122,13123],{},"Rendering af markdown fra dine indholdsfelter i Contentful",[628,13125,13126],{},"Rendering af indhold fra et WYSIWYG-felt i Contentful",[628,13128,13129],{},"Og meget mere...",[972,13131,13132],{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":217,"searchDepth":218,"depth":218,"links":13134},[13135,13136,13137,13138,13139,13140,13141,13142,13143,13144,13145,13146],{"id":10258,"depth":218,"text":10259},{"id":10275,"depth":218,"text":10276},{"id":10301,"depth":218,"text":10302},{"id":10378,"depth":218,"text":10379},{"id":10404,"depth":218,"text":10405},{"id":10804,"depth":218,"text":10805},{"id":10839,"depth":218,"text":10840},{"id":11237,"depth":218,"text":11238},{"id":12180,"depth":218,"text":12181},{"id":12345,"depth":218,"text":12346},{"id":13085,"depth":218,"text":13086},{"id":13102,"depth":218,"text":13103},"2019-05-31","Lær hvordan du bygger et simpelt website med Vue\u002FNuxtJS og Contentful — inklusiv et Vuex-eksempel.",{},"\u002Fblog\u002Fbyg-website-med-nuxt-og-contentful",{"title":10211,"description":13148},"Trin-for-trin guide til at bygge et website med Nuxt og Contentful CMS. Inklusiv Vuex state management, dynamiske sider og deployment.","byg-website-med-nuxt-og-contentful","blog\u002Fbyg-website-med-nuxt-og-contentful",[10205,997,2005],"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F800\u002F1*EbMY_0E_B40JWXQgQ1B_Yg.jpeg","ODVbEPDuVVZOnnNe8KlCCdEcYCm2z_L2yhefYzhbNOk",{"id":13159,"title":13160,"body":13161,"date":13207,"description":13208,"extension":236,"meta":13209,"navigation":238,"noindex":238,"path":13210,"seo":13211,"seoDescription":13208,"seoTitle":13160,"slug":13212,"stem":13213,"tags":13214,"thumbnail":13216,"updated":13207,"__hash__":13217},"blog\u002Fblog\u002Fsets-i-javascript.md","Sets i Javascript",{"type":40,"value":13162,"toc":13205},[13163,13172,13175,13195,13202],[48,13164,13165,13166,13171],{},"Som naevnt har jeg benyttet ",[167,13167,13168],{},[67,13169,13170],{},"Sets"," nogle gange nar jeg har vaeret igang med en specifik opgave, og alt efter use case kan de vaere ret nyttige.",[48,13173,13174],{},"I denne artikel vil jeg komme lidt naermere ind pa folgende:",[625,13176,13177,13180,13183,13186,13189,13192],{},[628,13178,13179],{},"Hvad er Sets i Javascript og hvordan laver du et Set",[628,13181,13182],{},"Hvordan du finder et specifikt element",[628,13184,13185],{},"Hvordan du finder ud af hvad storrelsen er pa dit Set",[628,13187,13188],{},"Fjerner dubletter fra et array ved at benytte Sets",[628,13190,13191],{},"Iterere over Sets",[628,13193,13194],{},"Hvordan performance er pa Sets kontra Arrays",[48,13196,13197,13198],{},"Hele artiklen kan du laese pa min Medium profil:\n",[966,13199,13200],{"href":13200,"rel":13201},"https:\u002F\u002Fmedium.com\u002F@nickychristensen\u002Fes6-sets-are-awesome-e2b16b2e168",[4114],[48,13203,13204],{},"Jeg vil meget gerne hore dine erfaringer med Sets i Javascript - Sa smid endelig en kommentar ;)",{"title":217,"searchDepth":218,"depth":218,"links":13206},[],"2019-05-01","Som naevnt har jeg benyttet Sets nogle gange nar jeg har vaeret igang med en specifik opgave, og alt efter use case kan de vaere ret nyttige.",{},"\u002Fblog\u002Fsets-i-javascript",{"title":13160,"description":13208},"sets-i-javascript","blog\u002Fsets-i-javascript",[1392,13215],"datastrukturer","\u002Fimages\u002Fcontentful\u002Fsets-blog.jpg","G0y0rH1JH01VahYKuqkiwzFc-dWPNjaELqS6jP2D9mM",{"id":13219,"title":13220,"body":13221,"date":13287,"description":13288,"extension":236,"meta":13289,"navigation":238,"noindex":8,"path":13290,"seo":13291,"seoDescription":13288,"seoTitle":13220,"slug":13292,"stem":13293,"tags":13294,"thumbnail":13296,"updated":13287,"__hash__":13297},"blog\u002Fblog\u002Frest-and-spread-operators-i-javascript.md","Sma tricks med Rest & Spread operators I Javascript",{"type":40,"value":13222,"toc":13281},[13223,13226,13230,13233,13239,13243,13246,13252,13256,13259,13265,13269,13272,13278],[48,13224,13225],{},"Hvis du kender til ES6, sa har nu formentlig hort lidt om rest\u002Fspread operators, ogsa kendt som de tre \"...\". De tre prikker sa at sige kan bruge pa 2 mader, som en spread operator eller som \"rest parameter\".\nI denne artikel vil jeg komme ind pa lidt sma tips og tricks til hvad du kan gore med dem.",[119,13227,13229],{"id":13228},"klon-objekt-og-tilføj-properties-samtidig","Klon objekt og tilføj properties samtidig.",[48,13231,13232],{},"Du kan nemt klone et objekt, og samtidig tilføje nye properties til objektet. I nednestaende eksempel kan du se hvordan jeg kloner \"nicky\", samt hvordan \"lastName\" er tilføjet til objektet.",[280,13234,13237],{"className":13235,"code":13236,"language":285},[283],"const nicky = { id: 1, firstName: 'Nicky'}\nconst nickyExtended = { ...user, lastName: 'christensen' }\n\nnicky \u002F\u002F=> { id: 1, firstName: 'Nicky' }\nnickyExtended \u002F\u002F=> { id: 1, firstName: 'Nicky', lastName: 'Christensen' }\n",[287,13238,13236],{"__ignoreMap":217},[119,13240,13242],{"id":13241},"sammenlaeg-2-objekter","Sammenlaeg 2 objekter",[48,13244,13245],{},"Har du 2 objekter du gerne vil sammenlaegge til 1 objekt kan det gores utrolig nemt.\nI nednestaende eksempel sammenlaegger vi \"nicky\" + \"job\" til 1 objekt ved bare 3 liniers kode.",[280,13247,13250],{"className":13248,"code":13249,"language":285},[283],"const nicky = { id: 1, firstName: 'Nicky' }\nconst job = { jobTitle: 'Frontend Dev!' }\n\nconst nickyExtended = { ...nicky, ...job }\n\u002F\u002F=> { id: 1, firstName: 'Nicky', jobTitle: 'Frontend Dev!' }\n",[287,13251,13249],{"__ignoreMap":217},[119,13253,13255],{"id":13254},"ekskluder-properties-fra-et-objekt","Ekskluder properties fra et objekt.",[48,13257,13258],{},"Properties kan til tider indeholde vaerdier du ikke har behov for, hvorfor det kan vaere en god ide at fjerne det fra det objekt du skal arbejde med. Dette kan gores med destructuring kombineret med rest parameters. I eksemplet nedenfor fjerner jeg alderen fra objektet, og resten af vores properties er returneret som \"rest\"",[280,13260,13263],{"className":13261,"code":13262,"language":285},[283],"const noAge = ({ age, ...rest }) => rest\nconst user = {\n  id: 1,\n  firstName: 'Nicky',\n  lastName: 'Christensen',\n  age: 34\n}\n\nnoAge(user) \u002F\u002F=> { id: 1, firstName: 'Nicky', lastName: 'Christensen' }\n",[287,13264,13262],{"__ignoreMap":217},[119,13266,13268],{"id":13267},"specifik-data-fra-2-objekter","Specifik data fra 2 objekter",[48,13270,13271],{},"I visse tilfaelde har man kun brug for noget specifikt data fra flere objekter. Her kan vi benytte destructuring sammen med spread operators for at opna det. I nednestaende eksempel kan du se hvordan vi nemt hiver \"name\" og \"city\" ud fra 2 forskellige objekter.",[280,13273,13276],{"className":13274,"code":13275,"language":285},[283],"const obj = {\n  firstName: \"Nicky\",\n  lastName: \"Christensen\",\n  age: 34,\n  jobTitle: \"Frontend Dev!\"\n}\n\nconst objTwo = {\n  city: \"Aarhus\",\n  country: \"Denmark\"\n}\n\nlet {firstName, city} = {...obj, ...objTwo};\nconsole.log(firstName, city);  \u002F\u002F=> Nicky Aarhus\n",[287,13277,13275],{"__ignoreMap":217},[48,13279,13280],{},"Det var lige hvad det kunne blive til sadan en lordag morgen. Jeg haber du kan bruge det til lidt, og smid gerne andre tips og tricks min vej hvis du kommer pa nogle",{"title":217,"searchDepth":218,"depth":218,"links":13282},[13283,13284,13285,13286],{"id":13228,"depth":226,"text":13229},{"id":13241,"depth":226,"text":13242},{"id":13254,"depth":226,"text":13255},{"id":13267,"depth":226,"text":13268},"2019-03-23","Hvis du kender til ES6, sa har nu formentlig hort lidt om rest\u002Fspread operators, ogsa kendt som de tre \"...\". De tre prikker sa at sige kan bruge pa 2 mader, som en spread operator eller som \"rest par",{},"\u002Fblog\u002Frest-and-spread-operators-i-javascript",{"title":13220,"description":13288},"rest-and-spread-operators-i-javascript","blog\u002Frest-and-spread-operators-i-javascript",[1392,13295],"es6","\u002Fimages\u002Fcontentful\u002Frest-spread-operators.png","vRfLzNoV-VMuziXugjIEfqCGw6k-qpgDshGSMdnnDLU",{"id":13299,"title":13300,"body":13301,"date":13446,"description":13447,"extension":236,"meta":13448,"navigation":238,"noindex":238,"path":13449,"seo":13450,"seoDescription":13447,"seoTitle":13300,"slug":13451,"stem":13452,"tags":13453,"thumbnail":13456,"updated":13446,"__hash__":13457},"blog\u002Fblog\u002F4-google-chrome-extensions-til-udvikleren.md","4 Google Chrome Extensions til udvikleren",{"type":40,"value":13302,"toc":13440},[13303,13306,13309,13313,13318,13321,13324,13331,13335,13341,13344,13347,13364,13371,13377,13380,13383,13387,13393,13396,13399,13402,13406,13412,13415,13418,13421,13432,13435,13437],[48,13304,13305],{},"Der er blandt andet nogle extensions jeg benytter som er med til at holde min viden up-to-date, der er nogle der er med til at fremme mine evner som udvikler, og andre extensions jeg bare er glade for.",[48,13307,13308],{},"Da det alligevel sner udenfor lige pt, sa taenker jeg at jeg lige ville lave en lille artikel om nogle af de Google Chrome extensions jeg benytter til hverdag. Jeg horer ogsa meget gerne om dine favorit extensions, sa vaer endelig ikke bleg for at smid en kommentar nederst.",[119,13310,13312],{"id":13311},"panda-5","Panda 5",[48,13314,13315],{},[3592,13316],{"alt":13311,"src":13317},"\u002Fimages\u002Fcontentful\u002Fpanda-5.png",[48,13319,13320],{},"Dette er den perfekte extension til nar man onsker at holde sig opdateret indenfor frontend-verdenen. I hvert fald i mit tilfaelde. Jeg benytter mange medier, blandt andet Flipboard & Medium, men det er primaert til nar jeg sidder med min telefon. Nar jeg sidder foran PC'en er dette min go-to buddy.",[48,13322,13323],{},"Panda 5 er en extension som gor du kan fa nyheder fra forskellige medier direkte pa din forside af din browser. Der er mange forskellige medier at feede nyheder ind fra. Min favorit er Frontend Front & EchoJS.",[48,13325,13326,13327,13330],{},"Her samles der en bred vifte af artikler indenfor frontend-udvikling. Jeg kan altid sortere pa seneste eller mest populaere artikler. En kanon made at holde sig opdateret, samt ogsa kan vaere med til at fremme ens udvikling nar man falder over en artikel som gor man kan laere lidt nyt.",[13328,13329],"br",{},"\nEn rigtig god og nyttig nyhedsfeed app som gor det er nemt at holde sig opdateret indenfor ens felt.",[119,13332,13334],{"id":13333},"google-lighthouse","Google Lighthouse",[48,13336,13337],{},[3592,13338],{"alt":13339,"src":13340},"LightHouse","\u002Fimages\u002Fcontentful\u002Flighthouse.jpg",[48,13342,13343],{},"Lighthouse er et genialt vaerktoj efter min mening. Det automatiserer processen til at analysere performance, kode kvalitet, accessibility og mere pa en hjemmeside. Du kan indtaste hvilken som helst URL og kore test pa det.",[48,13345,13346],{},"Dette er et must have tool til dig som bygger hjemmesider & progressive web apps. Bestemt et vaerktoj jeg ikke ville kunne undvaere.\nNar du korer Lighthouse pa en hjemmeside, vil du fa genereret en rapport som indeholder 5 overordnede punkter:",[625,13348,13349,13352,13355,13358,13361],{},[628,13350,13351],{},"Performance",[628,13353,13354],{},"SEO",[628,13356,13357],{},"Accessibility",[628,13359,13360],{},"Progressive Web Apps",[628,13362,13363],{},"Best Practices",[48,13365,13366,13367],{},"Til hvert punkt vil du fa gode rad og vejledning om hvad der kan optimeres og gores bedre. Dermed kan du sikre dig en hjemmeside som spiller bade ift SEO, Performance, Accessibility og Best Practices.\nHer kan du se en rapport kort pa websitet ",[966,13368,13369],{"href":13369,"rel":13370},"https:\u002F\u002Fnemtmaltid.dk",[4114],[48,13372,13373],{},[3592,13374],{"alt":13375,"src":13376},"lighthouse-rapport","\u002Fimages\u002Fcontentful\u002Flighthouse-rapport.png",[48,13378,13379],{},"Her vil du kunne se at det faktisk klarer sig rigtig fint i storstedelen af scores, men under PWA klarer den sig ikke saerlig godt. Her vil det sa vaere muligt at dykke ned i rapporten for at se hvad der kan gores bedre for at fa en hojere score.",[48,13381,13382],{},"Onsker du ikke at have det som en extension til din browser kan du ogsa gore det til en del af dit build-setup til nar du bygger din applikation.",[119,13384,13386],{"id":13385},"google-font-previewer","Google Font Previewer",[48,13388,13389],{},[3592,13390],{"alt":13391,"src":13392},"FontPreview","\u002Fimages\u002Fcontentful\u002Ffontpreview.png",[48,13394,13395],{},"Endnu en super extensions om jeg benytter en del.\nBesog hvilket som helst website og se hvordan det vil tage sig ud med en font fra Google Webfonts.",[48,13397,13398],{},"Pa den made kan du hurtigt og nemt finde den font du onsker at benytte pa dit website, og dermed hurtigt lave en POC pa hvordan det vil tage sig ud hvis du skal til udskifte fonten pa et website.",[48,13400,13401],{},"Jeg har brugt dette en del og elsker at jeg nemt kan lave et preview af hvordan en hjemmeside vil se ud, uden at jeg skal implementere fonten pa ny hver gang og dermed spare lidt tid.",[119,13403,13405],{"id":13404},"vue-devtools","Vue Devtools",[48,13407,13408],{},[3592,13409],{"alt":13410,"src":13411},"vue-dev","\u002Fimages\u002Fcontentful\u002Fvue-dev.gif",[48,13413,13414],{},"Nu laver jeg rigtig meget udvikling med VueJS, derfor er Vue Devtools en extension der er umulig at leve uden. Det gor det muligt at inspicere din webapplikation og interagere med den -- Dermed bliver det meget lettere at lave debugging, samt fa en forstaelse af hvordan din applikation fungerer.",[48,13416,13417],{},"Nar du udvikler med Vue vil du automatisk fa en besked i Chrome Devtools om at du kan installere denne extension.",[48,13419,13420],{},"Alt i alt er denne extension til stor hjaelp nar du udvikler med VueJS\nDu kan installere denne extension pa 3 mader, enten via",[625,13422,13423,13426,13429],{},[628,13424,13425],{},"Chrome",[628,13427,13428],{},"Firefox",[628,13430,13431],{},"Standalone",[48,13433,13434],{},"Desvaerre sa understotter hverken Safari, IE eller Edge ikke denne extension endnu, men benytter du standalone metoden er det stadig muligt at debugge sin applikation",[960,13436],{},[48,13438,13439],{},"Jeg horer meget gerne om hvilke du benytter meget i din hverdag -- Smid en kommentar og lad mig hore.",{"title":217,"searchDepth":218,"depth":218,"links":13441},[13442,13443,13444,13445],{"id":13311,"depth":226,"text":13312},{"id":13333,"depth":226,"text":13334},{"id":13385,"depth":226,"text":13386},{"id":13404,"depth":226,"text":13405},"2019-01-27","Der er blandt andet nogle extensions jeg benytter som er med til at holde min viden up-to-date, der er nogle der er med til at fremme mine evner som udvikler, og andre extensions jeg bare er glade for",{},"\u002Fblog\u002F4-google-chrome-extensions-til-udvikleren",{"title":13300,"description":13447},"4-google-chrome-extensions-til-udvikleren","blog\u002F4-google-chrome-extensions-til-udvikleren",[13454,13455,2441],"tools","chrome","\u002Fimages\u002Fcontentful\u002Fform-handling.jpg","M748pSr1LqPuysQLZpgW3oeCJFTQjdC8VoYZ89FPNc0",{"id":13459,"title":13460,"body":13461,"date":14563,"description":13465,"extension":236,"meta":14564,"navigation":238,"noindex":238,"path":14565,"seo":14566,"seoDescription":13465,"seoTitle":13460,"slug":14567,"stem":14568,"tags":14569,"thumbnail":13456,"updated":14563,"__hash__":14571},"blog\u002Fblog\u002Fsend-formular-med-nuxt-and-netlify.md","Send formular med NuxtJS & Netlify",{"type":40,"value":13462,"toc":14554},[13463,13466,13469,13472,13475,13479,13482,13493,13496,13500,13503,13506,13509,13520,13523,13866,13869,13872,13875,13879,13882,13886,13889,13894,13897,13900,13905,13908,14551],[48,13464,13465],{},"I denne lille tutorial vil jeg vise dig hvordan du nemt handterer og sender formularer med Nuxt sammen med Netlify Forms.",[48,13467,13468],{},"Formularer i vores applikationer er noget, vi ofte benytter. Det er en made at sende et request til en server med en stump data, som vi sa kan fa tilsendt eller lagret i vores systemer. Nar man bygger et statisk site med fx Nuxt, sa har man ikke et formularmodul, som man oftest ser i et traditionelt CMS-system som Umbraco, Episerver, Wordpress osv. Pa et statisk site er det op til os selv at handtere formularer og data hertil.",[48,13470,13471],{},"Heldigvis kan dette loses meget nemt ved at benytte Netlify forms, kombineret med lidt frontend-udvikling i Vue og Nuxt.",[48,13473,13474],{},"Med Netlify forms far vi mulighed for at handtere formularer, uden vi behover en masse backend-konfigurering eller kode.",[119,13476,13478],{"id":13477},"sadan-kommer-du-igang","Sadan kommer du igang",[48,13480,13481],{},"For at komme i gang med at implementere formularer i din Nuxt-applikation kraever det lige et par ting:",[625,13483,13484,13487,13490],{},[628,13485,13486],{},"Du skal have et statisk site, som er hosted pa Netlify",[628,13488,13489],{},"Et unikt domaene -- Ikke din test-url pa Netlify",[628,13491,13492],{},"Du skal have slaet HTTPS til inde i Netlify's kontrolpanel",[48,13494,13495],{},"Pa Netlify far du automatisk gratis HTTPS med, sa du skal ikke bekymre dig om at kobe et certifikat. Husk, det ogsa altid er en god ide at have slaet HTTPS til, nar du har at gore med formularer -- pa den made sikrer du, at din applikation ikke sender ikke-krypterede data over en usikker forbindelse.",[119,13497,13499],{"id":13498},"byg-en-formular","Byg en formular",[48,13501,13502],{},"Det forste, vi skal have klaret, er at lave en basal kontaktformular med noget simpelt HTML. Start din lokale dev server op med kommandoen: \"npm run dev\"",[48,13504,13505],{},"Lokaliser mappen \"Pages\" i din Nuxt-applikation, og opret en side, den kan du kalde \"kontakt.vue\".",[48,13507,13508],{},"I vores formular skal vi bruge 3 felter:",[625,13510,13511,13514,13517],{},[628,13512,13513],{},"Navn",[628,13515,13516],{},"Email",[628,13518,13519],{},"Besked",[48,13521,13522],{},"Min formular ser nogenlunde sadanne ud:",[280,13524,13526],{"className":4471,"code":13525,"language":4473,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Cdiv class=\"form\">\n    \u003Cform name=\"contact\" method=\"POST\">\n      \u003Cdiv class=\"form__input\">\n        \u003Cinput type=\"text\" name=\"name\" id=\"name\" required \u002F>\n        \u003Clabel for=\"name\">Navn\u003C\u002Flabel>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form__input\">\n        \u003Clabel for=\"email\">Email\u003C\u002Flabel>\n        \u003Cinput type=\"email\" name=\"email\" id=\"email\" required \u002F>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form__textarea\">\n        \u003Clabel for=\"message\">Besked\u003C\u002Flabel>\n        \u003Ctextarea name=\"message\" id=\"message\" required>\u003C\u002Ftextarea>\n      \u003C\u002Fdiv>\n      \u003Cbutton type=\"submit\" class=\"button button--submit\">\n        \u003Cspan>\n          Send besked\n        \u003C\u002Fspan>\n      \u003C\u002Fbutton>\n    \u003C\u002Fform>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[287,13527,13528,13536,13551,13575,13590,13622,13643,13651,13665,13685,13713,13721,13736,13756,13783,13791,13813,13821,13826,13834,13842,13850,13858],{"__ignoreMap":217},[332,13529,13530,13532,13534],{"class":334,"line":335},[332,13531,374],{"class":355},[332,13533,2058],{"class":2057},[332,13535,2061],{"class":355},[332,13537,13538,13540,13542,13544,13546,13549],{"class":334,"line":218},[332,13539,2066],{"class":355},[332,13541,2069],{"class":2057},[332,13543,10874],{"class":351},[332,13545,440],{"class":355},[332,13547,13548],{"class":551},"\"form\"",[332,13550,2061],{"class":355},[332,13552,13553,13555,13558,13560,13562,13565,13568,13570,13573],{"class":334,"line":226},[332,13554,2076],{"class":355},[332,13556,13557],{"class":2057},"form",[332,13559,6098],{"class":351},[332,13561,440],{"class":355},[332,13563,13564],{"class":551},"\"contact\"",[332,13566,13567],{"class":351}," method",[332,13569,440],{"class":355},[332,13571,13572],{"class":551},"\"POST\"",[332,13574,2061],{"class":355},[332,13576,13577,13579,13581,13583,13585,13588],{"class":334,"line":395},[332,13578,2516],{"class":355},[332,13580,2069],{"class":2057},[332,13582,10874],{"class":351},[332,13584,440],{"class":355},[332,13586,13587],{"class":551},"\"form__input\"",[332,13589,2061],{"class":355},[332,13591,13592,13594,13596,13599,13601,13604,13606,13608,13610,13613,13615,13617,13620],{"class":334,"line":415},[332,13593,2525],{"class":355},[332,13595,1894],{"class":2057},[332,13597,13598],{"class":351}," type",[332,13600,440],{"class":355},[332,13602,13603],{"class":551},"\"text\"",[332,13605,6098],{"class":351},[332,13607,440],{"class":355},[332,13609,4920],{"class":551},[332,13611,13612],{"class":351}," id",[332,13614,440],{"class":355},[332,13616,4920],{"class":551},[332,13618,13619],{"class":351}," required",[332,13621,4424],{"class":355},[332,13623,13624,13626,13629,13632,13634,13636,13639,13641],{"class":334,"line":421},[332,13625,2525],{"class":355},[332,13627,13628],{"class":2057},"label",[332,13630,13631],{"class":351}," for",[332,13633,440],{"class":355},[332,13635,4920],{"class":551},[332,13637,13638],{"class":355},">Navn\u003C\u002F",[332,13640,13628],{"class":2057},[332,13642,2061],{"class":355},[332,13644,13645,13647,13649],{"class":334,"line":434},[332,13646,2555],{"class":355},[332,13648,2069],{"class":2057},[332,13650,2061],{"class":355},[332,13652,13653,13655,13657,13659,13661,13663],{"class":334,"line":446},[332,13654,2516],{"class":355},[332,13656,2069],{"class":2057},[332,13658,10874],{"class":351},[332,13660,440],{"class":355},[332,13662,13587],{"class":551},[332,13664,2061],{"class":355},[332,13666,13667,13669,13671,13673,13675,13678,13681,13683],{"class":334,"line":466},[332,13668,2525],{"class":355},[332,13670,13628],{"class":2057},[332,13672,13631],{"class":351},[332,13674,440],{"class":355},[332,13676,13677],{"class":551},"\"email\"",[332,13679,13680],{"class":355},">Email\u003C\u002F",[332,13682,13628],{"class":2057},[332,13684,2061],{"class":355},[332,13686,13687,13689,13691,13693,13695,13697,13699,13701,13703,13705,13707,13709,13711],{"class":334,"line":476},[332,13688,2525],{"class":355},[332,13690,1894],{"class":2057},[332,13692,13598],{"class":351},[332,13694,440],{"class":355},[332,13696,13677],{"class":551},[332,13698,6098],{"class":351},[332,13700,440],{"class":355},[332,13702,13677],{"class":551},[332,13704,13612],{"class":351},[332,13706,440],{"class":355},[332,13708,13677],{"class":551},[332,13710,13619],{"class":351},[332,13712,4424],{"class":355},[332,13714,13715,13717,13719],{"class":334,"line":482},[332,13716,2555],{"class":355},[332,13718,2069],{"class":2057},[332,13720,2061],{"class":355},[332,13722,13723,13725,13727,13729,13731,13734],{"class":334,"line":487},[332,13724,2516],{"class":355},[332,13726,2069],{"class":2057},[332,13728,10874],{"class":351},[332,13730,440],{"class":355},[332,13732,13733],{"class":551},"\"form__textarea\"",[332,13735,2061],{"class":355},[332,13737,13738,13740,13742,13744,13746,13749,13752,13754],{"class":334,"line":496},[332,13739,2525],{"class":355},[332,13741,13628],{"class":2057},[332,13743,13631],{"class":351},[332,13745,440],{"class":355},[332,13747,13748],{"class":551},"\"message\"",[332,13750,13751],{"class":355},">Besked\u003C\u002F",[332,13753,13628],{"class":2057},[332,13755,2061],{"class":355},[332,13757,13758,13760,13763,13765,13767,13769,13771,13773,13775,13777,13779,13781],{"class":334,"line":2156},[332,13759,2525],{"class":355},[332,13761,13762],{"class":2057},"textarea",[332,13764,6098],{"class":351},[332,13766,440],{"class":355},[332,13768,13748],{"class":551},[332,13770,13612],{"class":351},[332,13772,440],{"class":355},[332,13774,13748],{"class":551},[332,13776,13619],{"class":351},[332,13778,12236],{"class":355},[332,13780,13762],{"class":2057},[332,13782,2061],{"class":355},[332,13784,13785,13787,13789],{"class":334,"line":2162},[332,13786,2555],{"class":355},[332,13788,2069],{"class":2057},[332,13790,2061],{"class":355},[332,13792,13793,13795,13797,13799,13801,13804,13806,13808,13811],{"class":334,"line":2173},[332,13794,2516],{"class":355},[332,13796,5894],{"class":2057},[332,13798,13598],{"class":351},[332,13800,440],{"class":355},[332,13802,13803],{"class":551},"\"submit\"",[332,13805,10874],{"class":351},[332,13807,440],{"class":355},[332,13809,13810],{"class":551},"\"button button--submit\"",[332,13812,2061],{"class":355},[332,13814,13815,13817,13819],{"class":334,"line":2179},[332,13816,2525],{"class":355},[332,13818,332],{"class":2057},[332,13820,2061],{"class":355},[332,13822,13823],{"class":334,"line":2184},[332,13824,13825],{"class":355},"          Send besked\n",[332,13827,13828,13830,13832],{"class":334,"line":2193},[332,13829,10973],{"class":355},[332,13831,332],{"class":2057},[332,13833,2061],{"class":355},[332,13835,13836,13838,13840],{"class":334,"line":2204},[332,13837,2555],{"class":355},[332,13839,5894],{"class":2057},[332,13841,2061],{"class":355},[332,13843,13844,13846,13848],{"class":334,"line":2210},[332,13845,2577],{"class":355},[332,13847,13557],{"class":2057},[332,13849,2061],{"class":355},[332,13851,13852,13854,13856],{"class":334,"line":2215},[332,13853,2103],{"class":355},[332,13855,2069],{"class":2057},[332,13857,2061],{"class":355},[332,13859,13860,13862,13864],{"class":334,"line":2221},[332,13861,2112],{"class":355},[332,13863,2058],{"class":2057},[332,13865,2061],{"class":355},[48,13867,13868],{},"Hvis du kender til HTML, skulle dette vaere velkendt for dig. Vi har en form med 3 inputfelter og en submit-knap. Som du maske har bemaerket, er der ikke tilfojet en \"action\". Det handterer vi senere.",[48,13870,13871],{},"Dine inputfelter skal have en \"name\"-attribut, i og med det er disse, der vil blive mappet til Netlify. Husk ogsa at give formen et navn. I vores tilfaelde navngiver vi den \"contact\"",[48,13873,13874],{},"Tilføj lidt CSS til din formular, og sa vil du maske have noget, der ligner min:",[48,13876,13877],{},[3592,13878],{"alt":13557,"src":13456},[48,13880,13881],{},"Normalt ville jeg oprette en side og derefter en separat komponent til formularen og sa inkludere komponenten pa siden, men for at holde det simpelt gor vi det direkte pa vores side.",[119,13883,13885],{"id":13884},"enter-netlify","Enter Netlify",[48,13887,13888],{},"For at vores formular virker korrekt og sender dataen til Netlify, kraever vores formular lige et par ekstra ting.",[48,13890,13891],{},[67,13892,13893],{},"Tilføjelse af Netlify-attributten",[48,13895,13896],{},"Nar den besogende trykker pa submit-knappen, onsker vi at sende dataen videre til Netlify, derfor er vi nodt til at lade Netlify vide, at de skal handtere formularen.",[48,13898,13899],{},"Dette kan vi gore ved at tilføje \"data-netlify=\"true\"-attributten til vores form-tag. Derved handterer Netlify vores formular, og den data, der bliver submitted hertil, vil du nu kunne se i dit Netlify-kontrolpanel under forms.",[48,13901,13902],{},[67,13903,13904],{},"Tilføjelse af form-name input",[48,13906,13907],{},"Da et website oftest har mere end en formular, er det en god ide at lade serveren vide, hvor data kommer fra. Det kan vi klare ved at lave et inputfelt, der er skjult, samt give det en vaerdi af det, vores form hedder -- dvs. \"name\"-attributten, vi gav vores ",[13557,13909,13910,13911,13914,13948,13952,13955,13958,13963,13966,13969,13972,13975,13978,13981,14363,14367,14370,14377,14385,14390,14393,14397,14400,14403,14406,14532,14535,14538,14542,14545,14548],{}," tag.",[48,13912,13913],{},"Tilføj folgende til din formular - det gor, at Netlify nu gemmer data under Contact.",[280,13915,13917],{"className":4471,"code":13916,"language":4473,"meta":217,"style":217},"\u003Cinput type=\"hidden\" name=\"form-name\" value=\"contact\">\n",[287,13918,13919],{"__ignoreMap":217},[332,13920,13921,13923,13925,13927,13929,13932,13934,13936,13939,13942,13944,13946],{"class":334,"line":335},[332,13922,374],{"class":355},[332,13924,1894],{"class":2057},[332,13926,13598],{"class":351},[332,13928,440],{"class":355},[332,13930,13931],{"class":551},"\"hidden\"",[332,13933,6098],{"class":351},[332,13935,440],{"class":355},[332,13937,13938],{"class":551},"\"form-name\"",[332,13940,13941],{"class":351}," value",[332,13943,440],{"class":355},[332,13945,13564],{"class":551},[332,13947,2061],{"class":355},[119,13949,13951],{"id":13950},"sadan-sikrer-du-din-formular-mod-spam","Sadan sikrer du din formular mod spam",[48,13953,13954],{},"Du kender det formentligt -- uden en eller anden form for spam-sikring flyder din indbakke over af irriterende spam-mails.",[48,13956,13957],{},"Det er muligt at implementere flere forskellige losninger, hvor du selv handterer spam, eller du kan benytte Netlify's indbyggede handtering.",[48,13959,13960],{},[67,13961,13962],{},"Honeypot metoden",[48,13964,13965],{},"Ved at implementere Honeypot-metoden fra Netlify kan du komme problemet til livs. Dermed kan vi sikre os, at vi ikke bliver spammet. Honeypot-metoden er skjulte formfelter, som narrer bots til at udfylde det, vi mennesker ikke kan se. Lad os prove at udvide vores form.",[48,13967,13968],{},"Vi starter med at udvide vores  med \"netlify-honeypot\" med en vaerdi, der tilsvarer vaerdien pa vores skjulte felt. I vores tilfaelde giver det vaerdien \"bot-field\".",[48,13970,13971],{},"Lav herefter dit skjulte input felt i formularen -- husk herefter at skjule feltet med CSS.",[48,13973,13974],{},"Det, der sker, er, hvis nogle udfylder feltet \"bot-field\", sa vil Netlify se det som spam, da det vil vaere en spam-bot, der formentlig har udfyldt dette, da det ikke er synligt for brugeren.",[48,13976,13977],{},"Dette er en af de sma gemte guldkorn ved Netlify, nemlig automatisk \"spam-bot detection\"",[48,13979,13980],{},"Nu skulle din form gerne ligne noget a la:",[280,13982,13984],{"className":4471,"code":13983,"language":4473,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Cdiv class=\"form\">\n    \u003Cform name=\"contact\" method=\"POST\" netlify-honeypot=\"bot-field\" data-netlify=\"true\">\n      \u003Cp class=\"hidden\">\n        \u003Clabel>Skal ikke udfyldes: \u003Cinput name=\"bot-field\">\u003C\u002Flabel>\n      \u003C\u002Fp>\n      \u003Cdiv class=\"form__input\">\n        \u003Cinput type=\"text\" name=\"name\" id=\"name\" required \u002F>\n        \u003Clabel for=\"name\">Navn\u003C\u002Flabel>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form__input\">\n        \u003Clabel for=\"email\">Email\u003C\u002Flabel>\n        \u003Cinput type=\"email\" name=\"email\" id=\"email\" required \u002F>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"form__textarea\">\n        \u003Clabel for=\"message\">Besked\u003C\u002Flabel>\n        \u003Ctextarea name=\"message\" id=\"message\" required>\u003C\u002Ftextarea>\n      \u003C\u002Fdiv>\n      \u003Cbutton type=\"submit\" class=\"button button--submit\">\n        \u003Cspan>\n          Send besked\n        \u003C\u002Fspan>\n      \u003C\u002Fbutton>\n    \u003C\u002Fform>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[287,13985,13986,13994,14008,14044,14058,14081,14089,14103,14131,14149,14157,14171,14189,14217,14225,14239,14257,14283,14291,14311,14319,14323,14331,14339,14347,14355],{"__ignoreMap":217},[332,13987,13988,13990,13992],{"class":334,"line":335},[332,13989,374],{"class":355},[332,13991,2058],{"class":2057},[332,13993,2061],{"class":355},[332,13995,13996,13998,14000,14002,14004,14006],{"class":334,"line":218},[332,13997,2066],{"class":355},[332,13999,2069],{"class":2057},[332,14001,10874],{"class":351},[332,14003,440],{"class":355},[332,14005,13548],{"class":551},[332,14007,2061],{"class":355},[332,14009,14010,14012,14014,14016,14018,14020,14022,14024,14026,14029,14031,14034,14037,14039,14042],{"class":334,"line":226},[332,14011,2076],{"class":355},[332,14013,13557],{"class":2057},[332,14015,6098],{"class":351},[332,14017,440],{"class":355},[332,14019,13564],{"class":551},[332,14021,13567],{"class":351},[332,14023,440],{"class":355},[332,14025,13572],{"class":551},[332,14027,14028],{"class":351}," netlify-honeypot",[332,14030,440],{"class":355},[332,14032,14033],{"class":551},"\"bot-field\"",[332,14035,14036],{"class":351}," data-netlify",[332,14038,440],{"class":355},[332,14040,14041],{"class":551},"\"true\"",[332,14043,2061],{"class":355},[332,14045,14046,14048,14050,14052,14054,14056],{"class":334,"line":395},[332,14047,2516],{"class":355},[332,14049,48],{"class":2057},[332,14051,10874],{"class":351},[332,14053,440],{"class":355},[332,14055,13931],{"class":551},[332,14057,2061],{"class":355},[332,14059,14060,14062,14064,14067,14069,14071,14073,14075,14077,14079],{"class":334,"line":415},[332,14061,2525],{"class":355},[332,14063,13628],{"class":2057},[332,14065,14066],{"class":355},">Skal ikke udfyldes: \u003C",[332,14068,1894],{"class":2057},[332,14070,6098],{"class":351},[332,14072,440],{"class":355},[332,14074,14033],{"class":551},[332,14076,12236],{"class":355},[332,14078,13628],{"class":2057},[332,14080,2061],{"class":355},[332,14082,14083,14085,14087],{"class":334,"line":421},[332,14084,2555],{"class":355},[332,14086,48],{"class":2057},[332,14088,2061],{"class":355},[332,14090,14091,14093,14095,14097,14099,14101],{"class":334,"line":434},[332,14092,2516],{"class":355},[332,14094,2069],{"class":2057},[332,14096,10874],{"class":351},[332,14098,440],{"class":355},[332,14100,13587],{"class":551},[332,14102,2061],{"class":355},[332,14104,14105,14107,14109,14111,14113,14115,14117,14119,14121,14123,14125,14127,14129],{"class":334,"line":446},[332,14106,2525],{"class":355},[332,14108,1894],{"class":2057},[332,14110,13598],{"class":351},[332,14112,440],{"class":355},[332,14114,13603],{"class":551},[332,14116,6098],{"class":351},[332,14118,440],{"class":355},[332,14120,4920],{"class":551},[332,14122,13612],{"class":351},[332,14124,440],{"class":355},[332,14126,4920],{"class":551},[332,14128,13619],{"class":351},[332,14130,4424],{"class":355},[332,14132,14133,14135,14137,14139,14141,14143,14145,14147],{"class":334,"line":466},[332,14134,2525],{"class":355},[332,14136,13628],{"class":2057},[332,14138,13631],{"class":351},[332,14140,440],{"class":355},[332,14142,4920],{"class":551},[332,14144,13638],{"class":355},[332,14146,13628],{"class":2057},[332,14148,2061],{"class":355},[332,14150,14151,14153,14155],{"class":334,"line":476},[332,14152,2555],{"class":355},[332,14154,2069],{"class":2057},[332,14156,2061],{"class":355},[332,14158,14159,14161,14163,14165,14167,14169],{"class":334,"line":482},[332,14160,2516],{"class":355},[332,14162,2069],{"class":2057},[332,14164,10874],{"class":351},[332,14166,440],{"class":355},[332,14168,13587],{"class":551},[332,14170,2061],{"class":355},[332,14172,14173,14175,14177,14179,14181,14183,14185,14187],{"class":334,"line":487},[332,14174,2525],{"class":355},[332,14176,13628],{"class":2057},[332,14178,13631],{"class":351},[332,14180,440],{"class":355},[332,14182,13677],{"class":551},[332,14184,13680],{"class":355},[332,14186,13628],{"class":2057},[332,14188,2061],{"class":355},[332,14190,14191,14193,14195,14197,14199,14201,14203,14205,14207,14209,14211,14213,14215],{"class":334,"line":496},[332,14192,2525],{"class":355},[332,14194,1894],{"class":2057},[332,14196,13598],{"class":351},[332,14198,440],{"class":355},[332,14200,13677],{"class":551},[332,14202,6098],{"class":351},[332,14204,440],{"class":355},[332,14206,13677],{"class":551},[332,14208,13612],{"class":351},[332,14210,440],{"class":355},[332,14212,13677],{"class":551},[332,14214,13619],{"class":351},[332,14216,4424],{"class":355},[332,14218,14219,14221,14223],{"class":334,"line":2156},[332,14220,2555],{"class":355},[332,14222,2069],{"class":2057},[332,14224,2061],{"class":355},[332,14226,14227,14229,14231,14233,14235,14237],{"class":334,"line":2162},[332,14228,2516],{"class":355},[332,14230,2069],{"class":2057},[332,14232,10874],{"class":351},[332,14234,440],{"class":355},[332,14236,13733],{"class":551},[332,14238,2061],{"class":355},[332,14240,14241,14243,14245,14247,14249,14251,14253,14255],{"class":334,"line":2173},[332,14242,2525],{"class":355},[332,14244,13628],{"class":2057},[332,14246,13631],{"class":351},[332,14248,440],{"class":355},[332,14250,13748],{"class":551},[332,14252,13751],{"class":355},[332,14254,13628],{"class":2057},[332,14256,2061],{"class":355},[332,14258,14259,14261,14263,14265,14267,14269,14271,14273,14275,14277,14279,14281],{"class":334,"line":2179},[332,14260,2525],{"class":355},[332,14262,13762],{"class":2057},[332,14264,6098],{"class":351},[332,14266,440],{"class":355},[332,14268,13748],{"class":551},[332,14270,13612],{"class":351},[332,14272,440],{"class":355},[332,14274,13748],{"class":551},[332,14276,13619],{"class":351},[332,14278,12236],{"class":355},[332,14280,13762],{"class":2057},[332,14282,2061],{"class":355},[332,14284,14285,14287,14289],{"class":334,"line":2184},[332,14286,2555],{"class":355},[332,14288,2069],{"class":2057},[332,14290,2061],{"class":355},[332,14292,14293,14295,14297,14299,14301,14303,14305,14307,14309],{"class":334,"line":2193},[332,14294,2516],{"class":355},[332,14296,5894],{"class":2057},[332,14298,13598],{"class":351},[332,14300,440],{"class":355},[332,14302,13803],{"class":551},[332,14304,10874],{"class":351},[332,14306,440],{"class":355},[332,14308,13810],{"class":551},[332,14310,2061],{"class":355},[332,14312,14313,14315,14317],{"class":334,"line":2204},[332,14314,2525],{"class":355},[332,14316,332],{"class":2057},[332,14318,2061],{"class":355},[332,14320,14321],{"class":334,"line":2210},[332,14322,13825],{"class":355},[332,14324,14325,14327,14329],{"class":334,"line":2215},[332,14326,10973],{"class":355},[332,14328,332],{"class":2057},[332,14330,2061],{"class":355},[332,14332,14333,14335,14337],{"class":334,"line":2221},[332,14334,2555],{"class":355},[332,14336,5894],{"class":2057},[332,14338,2061],{"class":355},[332,14340,14341,14343,14345],{"class":334,"line":2801},[332,14342,2577],{"class":355},[332,14344,13557],{"class":2057},[332,14346,2061],{"class":355},[332,14348,14349,14351,14353],{"class":334,"line":2828},[332,14350,2103],{"class":355},[332,14352,2069],{"class":2057},[332,14354,2061],{"class":355},[332,14356,14357,14359,14361],{"class":334,"line":2848},[332,14358,2112],{"class":355},[332,14360,2058],{"class":2057},[332,14362,2061],{"class":355},[119,14364,14366],{"id":14365},"test-formularen","Test formularen",[48,14368,14369],{},"Vi kan desvaerre ikke teste vores form lokalt, derfor kraever det, at vi laver et deploy til Netlify. Derefter tester vi vores formular. Nar du har lavet et deploy, naviger da til siden, hvor din kontaktformular er.",[48,14371,14372,14373],{},"Dette kan eksempelvis vaere: ",[966,14374,14375],{"href":14375,"rel":14376},"https:\u002F\u002Fnickychristensen.dk\u002Fkontakt\u002F",[4114],[48,14378,14379,14380,14384],{},"Udfyld felterne, og tryk pa submit-knappen. Log herefter ind i Netllify (",[966,14381,14382],{"href":14382,"rel":14383},"https:\u002F\u002Fwww.netlify.com\u002F",[4114],"), og ga til forms. Hvis alt er gaet som forventet, vil du nu kunne se dine data:",[48,14386,14387],{},[3592,14388],{"alt":14389,"src":13456},"form-netlify",[48,14391,14392],{},"Super godt -- vi er nu ved at vaere i mal. Dataen kommer ind i systemet, og vores formular fungerer naesten, som den skal. Vi mangler blot at give brugeren et svar om, at formularen er blevet afsendt. Lad os prove at se pa, hvordan vi klarer denne udfordring.",[119,14394,14396],{"id":14395},"sig-tak-til-brugeren","Sig tak til brugeren",[48,14398,14399],{},"I din applikation opretter du en ny side under \"pages\" -- den kan du kalde: \"tak.vue\".",[48,14401,14402],{},"Style din side, som du onsker. Den vigtigste laering her er blot, at vi skal kunne vise brugeren en takkeside.",[48,14404,14405],{},"Min kode for denne side ser saledes ud:",[280,14407,14409],{"className":4471,"code":14408,"language":4473,"meta":217,"style":217},"\u003Ctemplate>\n  \u003Cdiv class=\"contact-page\">\n    \u003Csection class=\"content__intro content--gutter\">\n      \u003Carticle>\n        \u003Ch2>\n          Tak for din besked\n        \u003C\u002Fh2>\n        \u003Cp>\n          Jeg vender tilbage hurtigst muligt.\n        \u003C\u002Fp>\n      \u003C\u002Farticle>\n    \u003C\u002Fsection>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[287,14410,14411,14419,14434,14449,14458,14466,14471,14479,14487,14492,14500,14508,14516,14524],{"__ignoreMap":217},[332,14412,14413,14415,14417],{"class":334,"line":335},[332,14414,374],{"class":355},[332,14416,2058],{"class":2057},[332,14418,2061],{"class":355},[332,14420,14421,14423,14425,14427,14429,14432],{"class":334,"line":218},[332,14422,2066],{"class":355},[332,14424,2069],{"class":2057},[332,14426,10874],{"class":351},[332,14428,440],{"class":355},[332,14430,14431],{"class":551},"\"contact-page\"",[332,14433,2061],{"class":355},[332,14435,14436,14438,14440,14442,14444,14447],{"class":334,"line":226},[332,14437,2076],{"class":355},[332,14439,11116],{"class":2057},[332,14441,10874],{"class":351},[332,14443,440],{"class":355},[332,14445,14446],{"class":551},"\"content__intro content--gutter\"",[332,14448,2061],{"class":355},[332,14450,14451,14453,14456],{"class":334,"line":395},[332,14452,2516],{"class":355},[332,14454,14455],{"class":2057},"article",[332,14457,2061],{"class":355},[332,14459,14460,14462,14464],{"class":334,"line":415},[332,14461,2525],{"class":355},[332,14463,43],{"class":2057},[332,14465,2061],{"class":355},[332,14467,14468],{"class":334,"line":421},[332,14469,14470],{"class":355},"          Tak for din besked\n",[332,14472,14473,14475,14477],{"class":334,"line":434},[332,14474,10973],{"class":355},[332,14476,43],{"class":2057},[332,14478,2061],{"class":355},[332,14480,14481,14483,14485],{"class":334,"line":446},[332,14482,2525],{"class":355},[332,14484,48],{"class":2057},[332,14486,2061],{"class":355},[332,14488,14489],{"class":334,"line":466},[332,14490,14491],{"class":355},"          Jeg vender tilbage hurtigst muligt.\n",[332,14493,14494,14496,14498],{"class":334,"line":476},[332,14495,10973],{"class":355},[332,14497,48],{"class":2057},[332,14499,2061],{"class":355},[332,14501,14502,14504,14506],{"class":334,"line":482},[332,14503,2555],{"class":355},[332,14505,14455],{"class":2057},[332,14507,2061],{"class":355},[332,14509,14510,14512,14514],{"class":334,"line":487},[332,14511,2577],{"class":355},[332,14513,11116],{"class":2057},[332,14515,2061],{"class":355},[332,14517,14518,14520,14522],{"class":334,"line":496},[332,14519,2103],{"class":355},[332,14521,2069],{"class":2057},[332,14523,2061],{"class":355},[332,14525,14526,14528,14530],{"class":334,"line":2156},[332,14527,2112],{"class":355},[332,14529,2058],{"class":2057},[332,14531,2061],{"class":355},[48,14533,14534],{},"Nar du har opsat din side, skal vi have redigeret vores formular fra tidligere. Abn ContactForm.vue og tilføj en action til din form. Saet denne til at vaere \"action=\"\u002Ftak-for-din-besked\".",[48,14536,14537],{},"Dette gor, at Netlify automatisk redirecter til din takkeside.",[119,14539,14541],{"id":14540},"du-klarede-det","Du klarede det",[48,14543,14544],{},"Det eneste, du mangler nu, er at deploye dine seneste aendringer til Netlify og derefter teste det hele igen, simpelt, ikke?",[48,14546,14547],{},"Jeg er blevet super glad for at bruge Netlify til mine statiske sites. Jeg er stor fan af deres integration til Contentful, GIT, hvilket gor, at man nemt kan opsaette Continues Deployment, men mere om det pa et andet tidspunkt.",[48,14549,14550],{},"Det var alt for nu. Jeg haber, du fik en smule ud af det, og skulle du sidde tilbage med nogle sporgsmal, sa smid mig en besked, sa vil jeg meget gerne vaere behjaelpelig.",[972,14552,14553],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":217,"searchDepth":218,"depth":218,"links":14555},[14556,14557,14558,14559,14560,14561,14562],{"id":13477,"depth":226,"text":13478},{"id":13498,"depth":226,"text":13499},{"id":13884,"depth":226,"text":13885},{"id":13950,"depth":226,"text":13951},{"id":14365,"depth":226,"text":14366},{"id":14395,"depth":226,"text":14396},{"id":14540,"depth":226,"text":14541},"2019-01-17",{},"\u002Fblog\u002Fsend-formular-med-nuxt-and-netlify",{"title":13460,"description":13465},"send-formular-med-nuxt-and-netlify","blog\u002Fsend-formular-med-nuxt-and-netlify",[10205,14570,997],"netlify","23veY3YFwCgkstxRWqhiUUsD7MdIhvE1q_6zP4NTA7I",{"id":14573,"title":14574,"body":14575,"date":14983,"description":14984,"extension":236,"meta":14985,"navigation":238,"noindex":8,"path":14986,"seo":14987,"seoDescription":14988,"seoTitle":14989,"slug":14990,"stem":14991,"tags":14992,"thumbnail":14996,"updated":234,"__hash__":14997},"blog\u002Fblog\u002Fgode-raad-til-en-hurtigere-hjemmeside.md","Optimering af hjemmeside — Den komplette guide i 2026",{"type":40,"value":14576,"toc":14962},[14577,14581,14584,14587,14590,14594,14597,14601,14604,14608,14611,14615,14618,14621,14625,14629,14632,14662,14666,14692,14696,14699,14719,14723,14726,14759,14763,14766,14786,14789,14793,14796,14822,14826,14829,14852,14856,14859,14885,14889,14892,14895,14921,14925,14928,14952,14955,14959],[43,14578,14580],{"id":14579},"hvorfor-hastighed-er-afgørende-for-din-forretning","Hvorfor hastighed er afgørende for din forretning",[48,14582,14583],{},"En langsom hjemmeside koster dig kunder, konverteringer og synlighed på Google. Det er ikke en overdrivelse — det er dokumenteret fakta.",[48,14585,14586],{},"Google bruger hastighed som en direkte rankeringsfaktor, og deres Core Web Vitals er blevet en central del af, hvordan din hjemmeside bliver vurderet. Samtidig viser undersøgelser, at 53% af mobile besøgende forlader en side, der tager mere end 3 sekunder at loade.",[48,14588,14589],{},"Med 19+ års erfaring som webudvikler har jeg optimeret hastigheden på alt fra virksomhedswebsites til SaaS-platforme og webshops. I denne guide deler jeg de vigtigste teknikker til at gøre din hjemmeside hurtigere.",[43,14591,14593],{"id":14592},"hvad-er-core-web-vitals","Hvad er Core Web Vitals?",[48,14595,14596],{},"Core Web Vitals er Googles officielle målestok for brugeroplevelsen på din hjemmeside. Der er tre centrale værdier du skal kende:",[119,14598,14600],{"id":14599},"lcp-largest-contentful-paint","LCP (Largest Contentful Paint)",[48,14602,14603],{},"Måler hvor hurtigt det største synlige element på siden bliver vist. Mål: under 2,5 sekunder.",[119,14605,14607],{"id":14606},"inp-interaction-to-next-paint","INP (Interaction to Next Paint)",[48,14609,14610],{},"Måler hvor hurtigt siden reagerer på brugerinteraktion (klik, tryk, tastatur). Mål: under 200 millisekunder. INP erstattede FID (First Input Delay) i 2024.",[119,14612,14614],{"id":14613},"cls-cumulative-layout-shift","CLS (Cumulative Layout Shift)",[48,14616,14617],{},"Måler hvor meget sidens layout \"hopper\" mens den loader. Mål: under 0,1.",[48,14619,14620],{},"Disse tre værdier påvirker direkte din Google-rangering. Scorer du dårligt her, bliver du nedprioriteret i søgeresultaterne.",[43,14622,14624],{"id":14623},"de-8-vigtigste-optimeringer-du-kan-lave","De 8 vigtigste optimeringer du kan lave",[119,14626,14628],{"id":14627},"_1-optimer-dine-billeder","1. Optimer dine billeder",[48,14630,14631],{},"Billeder er næsten altid den største synder når en hjemmeside er langsom. Her er hvad du kan gøre:",[625,14633,14634,14640,14646,14656],{},[628,14635,14636,14639],{},[67,14637,14638],{},"Brug moderne formater"," — WebP og AVIF er markant mindre end PNG og JPEG, uden synligt kvalitetstab",[628,14641,14642,14645],{},[67,14643,14644],{},"Responsive billeder"," — Server det rigtige billedstørrelse til det rigtige device. En mobilbruger behøver ikke et 4K-billede",[628,14647,14648,14651,14652,14655],{},[67,14649,14650],{},"Lazy loading"," — Billeder der ikke er synlige på skærmen skal først loades når brugeren scroller derhen. I moderne HTML kan du bruge ",[287,14653,14654],{},"loading=\"lazy\""," attributten",[628,14657,14658,14661],{},[67,14659,14660],{},"Komprimering"," — Brug værktøjer som Squoosh, Sharp eller din hosting-udbyders automatiske billedoptimering",[119,14663,14665],{"id":14664},"_2-minimer-og-optimer-din-kode","2. Minimer og optimer din kode",[625,14667,14668,14674,14680,14686],{},[628,14669,14670,14673],{},[67,14671,14672],{},"Code splitting"," — Indlæs kun den JavaScript der er nødvendig for den aktuelle side, ikke hele applikationen",[628,14675,14676,14679],{},[67,14677,14678],{},"Tree shaking"," — Fjern ubrugt kode automatisk via moderne build-værktøjer som Vite eller Webpack",[628,14681,14682,14685],{},[67,14683,14684],{},"Minificering"," — Fjern whitespace, kommentarer og forkort kode ned til mindst mulig filstørrelse",[628,14687,14688,14691],{},[67,14689,14690],{},"Fjern unødig JavaScript"," — Tredjepartsscripts, analytics-værktøjer og widgets kan være overraskende tunge. Auditér regelmæssigt hvad der kører på din side",[119,14693,14695],{"id":14694},"_3-udnyt-browser-caching","3. Udnyt browser-caching",[48,14697,14698],{},"Caching sørger for at tilbagevendende besøgende ikke skal downloade de samme filer igen:",[625,14700,14701,14707,14713],{},[628,14702,14703,14706],{},[67,14704,14705],{},"Sæt cache-headers korrekt"," — Statiske assets (billeder, CSS, JS) kan caches i lang tid",[628,14708,14709,14712],{},[67,14710,14711],{},"Service Workers"," — For progressive web apps kan en service worker cache sider og assets til offline-brug",[628,14714,14715,14718],{},[67,14716,14717],{},"CDN (Content Delivery Network)"," — Server dine filer fra det datacenter der er tættest på brugeren. Tjenester som Cloudflare, Netlify og Vercel tilbyder dette automatisk",[119,14720,14722],{"id":14721},"_4-optimer-web-fonts","4. Optimer web fonts",[48,14724,14725],{},"Fonts er en ofte overset synder:",[625,14727,14728,14737,14747,14753],{},[628,14729,14730,14736],{},[67,14731,14732,14733],{},"Brug ",[287,14734,14735],{},"font-display: swap"," — Vis tekst med en fallback-font mens den rigtige font loader",[628,14738,14739,14742,14743,14746],{},[67,14740,14741],{},"Preload kritiske fonts"," — Brug ",[287,14744,14745],{},"\u003Clink rel=\"preload\">"," for dine vigtigste fonts",[628,14748,14749,14752],{},[67,14750,14751],{},"Begræns antal fonte"," — Hver font-vægt (regular, bold, italic) er en ekstra fil der skal downloades",[628,14754,14755,14758],{},[67,14756,14757],{},"Brug variable fonts"," — En enkelt fil kan indeholde alle vægte og stilarter",[119,14760,14762],{"id":14761},"_5-server-side-rendering-og-statisk-generering","5. Server-side rendering og statisk generering",[48,14764,14765],{},"Moderne frameworks som Nuxt og Next.js giver dig mulighed for at pre-rendere dine sider:",[625,14767,14768,14774,14780],{},[628,14769,14770,14773],{},[67,14771,14772],{},"Statisk generering (SSG)"," — Siderne bliver bygget på forhånd og serveret som statiske HTML-filer. Lynhurtigt og fantastisk til SEO",[628,14775,14776,14779],{},[67,14777,14778],{},"Server-side rendering (SSR)"," — Sider genereres på serveren for hvert request. Bedre til dynamisk indhold",[628,14781,14782,14785],{},[67,14783,14784],{},"Incremental Static Regeneration (ISR)"," — Det bedste fra begge verdener: statiske sider der kan opdateres uden et fuldt rebuild",[48,14787,14788],{},"Mit eget website bruger statisk generering med Nuxt 3, hvilket giver en ekstremt hurtig brugeroplevelse.",[119,14790,14792],{"id":14791},"_6-reducer-http-requests","6. Reducer HTTP-requests",[48,14794,14795],{},"Hver fil din side skal hente er et HTTP-request der tager tid:",[625,14797,14798,14804,14810,14816],{},[628,14799,14800,14803],{},[67,14801,14802],{},"Kombiner CSS og JavaScript"," — Moderne build-værktøjer gør dette automatisk",[628,14805,14806,14809],{},[67,14807,14808],{},"Inline kritisk CSS"," — Den CSS der er nødvendig for at vise den første skærm kan inlines direkte i HTML'en",[628,14811,14812,14815],{},[67,14813,14814],{},"Brug HTTP\u002F2 eller HTTP\u002F3"," — Disse protokoller kan sende flere filer parallelt, hvilket er markant hurtigere end HTTP\u002F1.1",[628,14817,14818,14821],{},[67,14819,14820],{},"Fjern unødige tredjepartsscripts"," — Hvert analytics-, chat- og tracking-script tilføjer load-tid",[119,14823,14825],{"id":14824},"_7-undgå-layout-shifts","7. Undgå layout shifts",[48,14827,14828],{},"Layout shifts (CLS) sker når elementer på siden ændrer position efter de er blevet vist:",[625,14830,14831,14837,14843],{},[628,14832,14833,14836],{},[67,14834,14835],{},"Sæt dimensioner på billeder og videoer"," — Angiv altid width og height, så browseren kan reservere plads",[628,14838,14839,14842],{},[67,14840,14841],{},"Undgå dynamisk indsat indhold over eksisterende indhold"," — Bannere, cookie-notifikationer og ads der skubber indhold ned",[628,14844,14845,14851],{},[67,14846,14732,14847,14850],{},[287,14848,14849],{},"aspect-ratio"," i CSS"," — Reservér plads til medieindhold før det er loadet",[119,14853,14855],{"id":14854},"_8-mål-og-overvåg-din-performance","8. Mål og overvåg din performance",[48,14857,14858],{},"Du kan ikke forbedre det du ikke måler:",[625,14860,14861,14867,14873,14879],{},[628,14862,14863,14866],{},[67,14864,14865],{},"Google PageSpeed Insights"," — Giver dig en score og konkrete forbedringsforslag baseret på Core Web Vitals",[628,14868,14869,14872],{},[67,14870,14871],{},"Google Search Console"," — Viser dig Core Web Vitals for alle dine sider baseret på rigtige brugerdata",[628,14874,14875,14878],{},[67,14876,14877],{},"WebPageTest"," — Detaljeret waterfall-analyse af din sides load-tid",[628,14880,14881,14884],{},[67,14882,14883],{},"Lighthouse i Chrome DevTools"," — Kør en performance-audit direkte i din browser",[43,14886,14888],{"id":14887},"performance-og-seo-hænger-sammen","Performance og SEO hænger sammen",[48,14890,14891],{},"Google har gjort det helt klart: hastighed er en rankeringsfaktor. Sider der scorer godt på Core Web Vitals får en fordel i søgeresultaterne.",[48,14893,14894],{},"Men det handler ikke kun om Google. En hurtig hjemmeside giver også:",[625,14896,14897,14903,14909,14915],{},[628,14898,14899,14902],{},[67,14900,14901],{},"Højere konverteringsrate"," — Amazon har dokumenteret at 100ms ekstra load-tid koster dem 1% i omsætning",[628,14904,14905,14908],{},[67,14906,14907],{},"Lavere bounce rate"," — Besøgende bliver længere på hurtige sider",[628,14910,14911,14914],{},[67,14912,14913],{},"Bedre mobiloplevelse"," — Hvor over halvdelen af al webtrafik kommer fra",[628,14916,14917,14920],{},[67,14918,14919],{},"Større kundetilfredshed"," — Hastighed er den mest basale del af brugeroplevelsen",[43,14922,14924],{"id":14923},"sæt-dig-et-performance-mål","Sæt dig et performance-mål",[48,14926,14927],{},"Min anbefaling er at sætte konkrete mål for din hjemmeside:",[625,14929,14930,14936,14941,14946],{},[628,14931,14932,14935],{},[67,14933,14934],{},"LCP under 2,5 sekunder"," på mobil",[628,14937,14938],{},[67,14939,14940],{},"INP under 200ms",[628,14942,14943],{},[67,14944,14945],{},"CLS under 0,1",[628,14947,14948,14951],{},[67,14949,14950],{},"PageSpeed score over 90"," på både desktop og mobil",[48,14953,14954],{},"Disse mål bør være en del af din digitale strategi, ikke bare noget man \"fixér en gang\" og glemmer. Performance er løbende vedligeholdelse — præcis som en bil kræver regelmæssig service.",[43,14956,14958],{"id":14957},"har-du-brug-for-hjælp","Har du brug for hjælp?",[48,14960,14961],{},"Optimering af en hjemmeside kræver teknisk ekspertise og erfaring. Hvis din hjemmeside er langsom, eller du er i tvivl om din performance, er du velkommen til at tage kontakt. Jeg hjælper gerne med en analyse og konkrete anbefalinger.",{"title":217,"searchDepth":218,"depth":218,"links":14963},[14964,14965,14970,14980,14981,14982],{"id":14579,"depth":218,"text":14580},{"id":14592,"depth":218,"text":14593,"children":14966},[14967,14968,14969],{"id":14599,"depth":226,"text":14600},{"id":14606,"depth":226,"text":14607},{"id":14613,"depth":226,"text":14614},{"id":14623,"depth":218,"text":14624,"children":14971},[14972,14973,14974,14975,14976,14977,14978,14979],{"id":14627,"depth":226,"text":14628},{"id":14664,"depth":226,"text":14665},{"id":14694,"depth":226,"text":14695},{"id":14721,"depth":226,"text":14722},{"id":14761,"depth":226,"text":14762},{"id":14791,"depth":226,"text":14792},{"id":14824,"depth":226,"text":14825},{"id":14854,"depth":226,"text":14855},{"id":14887,"depth":218,"text":14888},{"id":14923,"depth":218,"text":14924},{"id":14957,"depth":218,"text":14958},"2019-01-13","Er din hjemmeside for langsom? Lær hvordan du optimerer hastighed, Core Web Vitals og performance så din hjemmeside ranker højere og konverterer bedre.",{},"\u002Fblog\u002Fgode-raad-til-en-hurtigere-hjemmeside",{"title":14574,"description":14984},"Komplet guide til optimering af din hjemmeside. Lær om Core Web Vitals, billedoptimering, caching og moderne performance-teknikker der gør din side hurtigere og synlig på Google.","Optimering af hjemmeside — Guide til hurtigere load-tider i 2026","gode-raad-til-en-hurtigere-hjemmeside","blog\u002Fgode-raad-til-en-hurtigere-hjemmeside",[10203,2005,14993,14994,14995],"optimering","seo","core-web-vitals","\u002Fimages\u002Fcontentful\u002Fwebsite-hastighed.png","SCZOeDcYUXtgbFJphViF8lsVxIuFOMWIND7c0Z8rPS0",{"id":14999,"title":15000,"body":15001,"date":15031,"description":15006,"extension":236,"meta":15032,"navigation":238,"noindex":8,"path":15033,"seo":15034,"seoDescription":15006,"seoTitle":15000,"slug":15035,"stem":15036,"tags":15037,"thumbnail":15039,"updated":14983,"__hash__":15040},"blog\u002Fblog\u002Fnyt-website-er-gaet-live.md","Nyt website er live",{"type":40,"value":15002,"toc":15028},[15003,15007,15010,15013,15016,15019,15022,15025],[43,15004,15006],{"id":15005},"_2019-blev-aret-hvor-nickychristensendk-sa-lyset","2019 blev aret hvor NickyChristensen.dk sa lyset",[48,15008,15009],{},"Et af mine nytarsforsaet har vaeret at fa lavet mig et personligt website hvor jeg kan fremvise nogle af de cases jeg lavet igennem tiden, samt ogsa at fa et taleror hvor jeg kan dele alle mine tanker, tips osv. Det kan jeg nu tjekke af.",[48,15011,15012],{},"Den 13.01-2019 er jeg endelig gaet live.",[48,15014,15015],{},"Bloggen pa mit website vil primaert blive brugt til at snakke om alt indenfor den digitale verden, heriblandt webudvikling, design, ivaerksaetteri, tips & guides til hvordan kan man laerer at komme i gang med at laere og kode osv...\nFor den nysgerrig sjael kan det naevnes at mit personlige website er bygget pa VueJS, Nuxt og Contentful til data.\nJeg benytter Git til versionsstyring, hvor jeg har opsat continues deployment sammen med Netlify.",[48,15017,15018],{},"Dette betyder at hver gang jeg laver et \"commit\" til min master branch pa GIT, bliver der automatisk lavet et build\u002Fdeploy til netlify, og mine aendringer ryger live uden at jeg egentlig skal rore en finger. Et virkeligt fedt og staerkt setup.",[48,15020,15021],{},"Som naevnt sa bruger jeg Contentful til data. Dvs, alle tekster, billeder kommre fra Contenful. Et headless CMS som er super elegant og let at arbejde med. Det kan jeg kun anbefale hvis ikke du har provet at arbejde med dette.",[48,15023,15024],{},"Jeg vil senere hen lave en mere udforlig guide til hvordan du selv kommer i gang med at lign setup, so stay tuned.",[48,15026,15027],{},"Det var alt lige i denne omgang. Jeg haber du vil folge med fremadrettet, og husk du altid er velkommen til at skrive til mig eller smide mig en besked pa Twitter eller andet socialt medie.",{"title":217,"searchDepth":218,"depth":218,"links":15029},[15030],{"id":15005,"depth":218,"text":15006},"2018-12-29",{},"\u002Fblog\u002Fnyt-website-er-gaet-live",{"title":15000,"description":15006},"nyt-website-er-gaet-live","blog\u002Fnyt-website-er-gaet-live",[15038,2005],"generelt","\u002Fimages\u002Fcontentful\u002Fwebsite-launch.png","F4TKRh4alrhVkHZXw1IziwcSTZ7rNABhBUMSpIu4Gbk",1775291276222]