Nuxt.js Vue aplikacijų kūrimui

Kas yra Nuxt.js ir kodėl jis atsirado

Kai Vue.js ekosistema pradėjo sparčiai augti, daugelis kūrėjų susidūrė su panašiomis problemomis – kaip sukonfigūruoti server-side rendering, kaip organizuoti routing’ą, kaip optimizuoti aplikacijos performansą. Kiekvienas projektas reikalavo panašių sprendimų, o tai reiškė daug pasikartojančio darbo. Būtent čia ir įsiterpia Nuxt.js – framework’as, kuris paima Vue.js ir prideda visą reikalingą infrastruktūrą, kad galėtumėte iš karto pradėti kurti aplikaciją.

Nuxt.js atsirado 2016 metais, įkvėptas Next.js (React ekosistemos framework’o). Pagrindinė idėja buvo paprasta – suteikti Vue kūrėjams galimybę kurti universalias aplikacijas be papildomo galvos skausmo. Ir reikia pripažinti, kad jiems tai pavyko. Šiandien Nuxt.js yra vienas populiariausių Vue framework’ų, turintis didelę bendruomenę ir nuolat besivystantis.

Kas įdomiausia – Nuxt.js nėra tik apie SSR (server-side rendering). Jis siūlo kelis skirtingus rendering režimus: klasikinį SSR, static site generation (SSG), client-side rendering (CSR) ir net hybrid režimą, kur galite maišyti skirtingus metodus vienoje aplikacijoje. Tai suteikia neįtikėtiną lankstumą priklausomai nuo jūsų projekto poreikių.

Nuxt 3 – naujos kartos framework’as

2022 metais oficialiai buvo išleista Nuxt 3 versija, kuri atnešė didžiulių pokyčių. Jei dirbote su Nuxt 2, tai Nuxt 3 gali atrodyti kaip visiškai naujas framework’as. Ir iš dalies taip ir yra.

Pirmiausia, Nuxt 3 yra parašytas TypeScript ir pilnai jį palaiko iš dėžės. Nebereikia jokių papildomų konfigūracijų ar plugin’ų – tiesiog pradedame rašyti TypeScript kodą ir viskas veikia. Composition API tapo standartu (nors Options API vis dar palaikomas), o tai reiškia geresnį kodo organizavimą ir pakartotinį panaudojimą.

Antra, performance’as. Nuxt 3 naudoja Vite kaip development serverį, o tai reiškia žaibiškai greitą hot module replacement. Nebereikia laukti kelių sekundžių, kol aplikacija perkraus – pakeitimai matomi beveik akimirksniu. Production build’ai taip pat tapo gerokai mažesni dėka gerai apgalvotam tree-shaking ir code splitting.

Trečia, Nitro engine. Tai nauja serverio dalis, kuri leidžia deploy’inti Nuxt aplikacijas praktiškai bet kur – Vercel, Netlify, AWS, Cloudflare Workers, Node.js serveris ar net static hosting. Viena komanda, ir jūsų aplikacija adaptuojama konkrečiai platformai automatiškai.

Kaip pradėti projektą ir kas vyksta po gaubtu

Pradėti naują Nuxt projektą yra neįtikėtinai paprasta. Tiesiog paleiskite:

npx nuxi@latest init mano-projektas

Po kelių sekundžių turėsite veikiančią aplikaciją su visa reikalinga struktūra. Bet kas iš tikrųjų vyksta šioje struktūroje?

Pages direktorija – čia magija prasideda. Kiekvienas .vue failas šioje direktorijoje automatiškai tampa route’u. Pavyzdžiui, pages/about.vue tampa /about route’u. Norite dinaminių route’ų? Tiesiog pavadinkite failą [id].vue, ir Nuxt supras, kad tai parametras. Nested route’ai? Sukurkite subdirektoriją. Nereikia jokio routing konfigūracijos failo – viskas veikia konvencijomis.

Components direktorija – visi komponentai čia yra automatiškai importuojami. Nebereikia rašyti import Button from '~/components/Button.vue' kiekviename faile. Tiesiog naudojate <Button /> ir Nuxt pats viską sutvarko. Tai gali atrodyti kaip smulkmena, bet realiai sutaupo daug laiko ir sumažina boilerplate kodą.

Composables direktorija – jūsų custom composition functions. Kaip ir komponentai, jie automatiškai prieinami visoje aplikacijoje. Čia galite laikyti logiką, kurią norite pakartotinai naudoti – API calls, state management, utility funkcijas.

Server direktorija – štai čia Nuxt tikrai išsiskiria. Galite kurti API endpoint’us tiesiog sukurdami failus server/api/ direktorijoje. Pavyzdžiui, server/api/users.get.ts automatiškai tampa GET endpoint’u /api/users. Tai full-stack framework’as viename pakete.

SSR, SSG ar CSR – kaip pasirinkti

Viena dažniausių klausimų, su kuriuo susiduria Nuxt kūrėjai – kurį rendering metodą pasirinkti? Atsakymas, kaip ir daugelyje IT sričių – depends.

Server-Side Rendering (SSR) puikiai tinka dinaminiui turiniui, kuris dažnai keičiasi. E-commerce platformos, social media aplikacijos, news portalai – visur, kur turinys personalizuotas ar nuolat atnaujinamas. SSR privalumai akivaizdūs – geresnė SEO, greičiau matomas initial content, geresnė performance’as lėtesniuose įrenginiuose. Bet yra ir minusų – reikia serverio, kuris sugeba handle’inti request’us, didesni infrastructure costs, sudėtingesnis debugging.

Praktinis patarimas: jei kuriate SSR aplikaciją, būtinai naudokite caching strategijas. Nuxt 3 turi puikų useFetch composable su built-in caching. Pavyzdžiui:

const { data } = await useFetch('/api/products', {
key: 'products',
getCachedData: (key) => nuxtApp.payload.data[key] || nuxtApp.static.data[key]
})

Static Site Generation (SSG) – mano asmeniškai mėgstamiausias metodas dokumentacijai, blog’ams, portfolio svetainėms. Generuojate visus puslapius build time, ir turite grynai statinius HTML failus, kuriuos galite host’inti bet kur už centus. Performance’as neįtikėtinas, nes nėra jokio serverio processing. Vienintelis minusas – jei turite tūkstančius puslapių, build laikas gali užtrukti.

Client-Side Rendering (CSR) – kai SEO nėra prioritetas ir turite labai interaktyvią aplikaciją. Admin panelės, dashboard’ai, internal tools – čia CSR puikiai tinka. Paprasčiau develop’inti, nereikia galvoti apie hydration issues, bet SEO ir initial load time kenčia.

Nuxt 3 leidžia net maišyti šiuos metodus vienoje aplikacijoje naudojant routeRules. Pavyzdžiui:

export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // SSG
'/admin/**': { ssr: false }, // CSR
'/api/**': { cors: true },
'/blog/**': { swr: 3600 } // SSR su cache
}
})

State management be Vuex galvos skausmo

Jei dirbote su Vue 2 ir Vuex, žinote, kad tai galėjo būti gana verbose. Mutations, actions, getters – daug boilerplate kodo net paprastoms operacijoms. Nuxt 3 eroje turime geresnius variantus.

Pinia yra oficialus Vue state management sprendimas, ir jis puikiai integruotas su Nuxt 3. Jis daug paprastesnis už Vuex, turi geresnį TypeScript support’ą ir intuityvesnį API. Store sukūrimas atrodo taip:

// stores/counter.ts
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++
}
}
})

Bet daugeliu atvejų jums gali net nereikėti Pinia. Nuxt 3 turi useState composable, kuris sukuria reactive state, dalijamą tarp komponentų ir išliekantį per SSR hydration:

// composables/useCounter.ts
export const useCounter = () => {
const count = useState('counter', () => 0)
const increment = () => count.value++
return { count, increment }
}

Dabar bet kuris komponentas gali naudoti useCounter() ir gauti tą patį state. Paprasta, efektyvu, be papildomo setup.

Kai kuriems projektams net šito per daug. Jei jūsų state yra paprastas ir lokalus, tiesiog naudokite ref ar reactive. Nebūkite kaip tie kūrėjai, kurie state management biblioteką naudoja net counter’iui.

Data fetching strategijos ir optimizacijos

Viena iš svarbiausių dalių kuriant bet kokią aplikaciją – kaip efektyviai gauti duomenis. Nuxt 3 siūlo kelis composables šiam tikslui, ir svarbu suprasti, kada kurį naudoti.

useFetch – jūsų pagrindinis įrankis. Jis automatiškai handle’ina SSR, deduplicate’ina request’us, cache’ina rezultatus. Naudokite jį, kai fetch’inate duomenis component setup fazėje:

const { data, pending, error, refresh } = await useFetch('/api/products')

Svarbu: useFetch turi būti naudojamas top-level setup funkcijoje, ne event handler’iuose ar lifecycle hook’uose. Tai dėl to, kaip Nuxt tvarko SSR ir hydration.

useAsyncData – kai reikia daugiau kontrolės. Pavyzdžiui, kai naudojate trečiųjų šalių bibliotekas ar norite custom logic:

const { data } = await useAsyncData('products', () => {
return $fetch('/api/products').then(res => {
// Custom processing
return res.filter(p => p.active)
})
})

$fetch – kai reikia imperatyviai fetch’inti duomenis, pavyzdžiui, form submission’e ar button click’e:

async function submitForm() {
try {
await $fetch('/api/submit', {
method: 'POST',
body: formData
})
} catch (error) {
// Handle error
}
}

Praktinis patarimas: visada naudokite lazy variantus (useLazyFetch, useLazyAsyncData), kai duomenys nėra kritiniai pirminiam page render’ui. Tai leidžia page’ui render’intis greičiau, o duomenys užsikrauna background’e:

const { pending, data } = useLazyFetch('/api/comments')

Dar vienas dažnai pamirštamas dalykas – error handling. Nuxt turi built-in error page, bet galite sukurti custom:

// error.vue root direktorijoje
<template>
<div>
<h1>{{ error.statusCode }}</h1>
<p>{{ error.message }}</p>
<button @click="handleError">Go Home</button>
</div>
</template>

Modules ekosistema ir kaip ją išnaudoti

Viena stipriausių Nuxt pusių – modules sistema. Tai plugin’ai sterodiuose, kurie gali modifikuoti Nuxt konfigūraciją, pridėti naujus features, integruoti third-party services. Ir jų ekosistema yra įspūdinga.

@nuxt/image – must-have kiekvienam projektui. Automatinis image optimization, lazy loading, responsive images, support’as įvairiems image providers (Cloudinary, Imgix, etc.). Setup’as paprastas:

npm install @nuxt/image
// nuxt.config.ts
modules: ['@nuxt/image']

Naudojimas dar paprastesnis:

<NuxtImg src="/photo.jpg" width="300" height="200" />

Ir viskas – turite optimizuotą, lazy-loaded, responsive image. Module automatiškai generuoja skirtingų dydžių versijas, naudoja modern formats (WebP, AVIF), ir dar cache’ina rezultatus.

@nuxtjs/tailwind – jei naudojate Tailwind CSS (o turėtumėte), šis module’is sutvarko visą setup’ą. Hot reload veikia puikiai, purging automatinis, dark mode support built-in.

@pinia/nuxt – jau minėjau Pinia, bet module’is prideda auto-import’us, SSR support’ą, dev tools integraciją.

@nuxt/content – jei kuriate blog’ą ar dokumentaciją, šis module’is game-changer. Rašote Markdown ar YAML failus content/ direktorijoje, ir jie tampa queryable database:

const { data } = await useAsyncData('blog', () =>
queryContent('blog').sort({ date: -1 }).find()
)

Support’ina syntax highlighting, Vue components Markdown’e, full-text search, ir dar daugiau.

Bet ne visi modules vienodai naudingi. Prieš įdiegdami module’į, paklauskite savęs: ar tikrai man to reikia, ar galiu tai padaryti paprasčiau? Kiekvienas module’is prideda dependency, didina bundle size, ir gali sukelti konfliktų su kitais modules. Būkite selektyvūs.

Performance optimization – ne tik teorija

Visi kalba apie performance, bet praktikoje dažnai pamirštama. Štai keletas konkrečių dalykų, kuriuos darau kiekviename Nuxt projekte.

Code splitting ir lazy loading – Nuxt automatiškai split’ina kodą pagal routes, bet galite eiti toliau. Lazy load’inkite komponentus, kurie nėra kritiniai:

const HeavyComponent = defineAsyncComponent(() =>
import('~/components/HeavyComponent.vue')
)

Arba naudokite Nuxt’s LazyComponentName konvenciją – tiesiog prefix’inkite komponentą su „Lazy”:

<LazyHeavyComponent v-if="showComponent" />

Preloading ir prefetching – Nuxt automatiškai preload’ina critical assets ir prefetch’ina links, kurie matomi viewport’e. Bet galite kontroliuoti šį behavior’ą:

// Disable automatic prefetching
export default defineNuxtConfig({
experimental: {
writeEarlyHints: false
}
})

Arba selektyviai:

<NuxtLink to="/about" :prefetch="false">About</NuxtLink>

Bundle analysis – reguliariai tikrinkite, kas sudaro jūsų bundle. Nuxt 3 turi built-in analyzer:

npx nuxi analyze

Dažnai rasite, kad kažkokia biblioteka, kurią naudojate vienai funkcijai, užima 200KB. Gal yra lengvesnė alternatyva? Ar galite tą funkciją parašyti patys?

Database queries optimization – jei naudojate Nuxt su backend, optimizuokite queries. Naudokite select’us, kad gautumėte tik reikalingus laukus, pridėkite indexes, cache’inkite rezultatus:

// server/api/products.get.ts
export default defineEventHandler(async (event) => {
const cached = await useStorage().getItem('products')
if (cached) return cached

const products = await db.select(['id', 'name', 'price'])
.from('products')
.where('active', true)
.limit(50)

await useStorage().setItem('products', products, { ttl: 3600 })
return products
})

Kai viskas susideda į vietą

Nuxt.js nėra tik framework’as – tai visas mindset’as, kaip kurti Vue aplikacijas. Jis priima sprendimus už jus (file-based routing, auto-imports, SSR setup), bet palieka pakankamai lankstumo pritaikyti viską savo poreikiams.

Ar Nuxt tinka visiems projektams? Žinoma, ne. Jei kuriate mažą, paprastą single-page aplikaciją be SEO reikalavimų, galbūt vanilla Vue būtų paprastesnis pasirinkimas. Bet jei jūsų projektas turi bet kokį kompleksiškumo lygį, Nuxt sutaupys jums begalę laiko ir nervų.

Kas man labiausiai patinka Nuxt 3 – tai, kad jis jaučiasi modernus. TypeScript support’as nėra afterthought, Composition API yra first-class citizen, performance yra prioritetas, o ne nice-to-have. Komanda už Nuxt aktyviai klauso community feedback’o ir greitai reaguoja į issues.

Jei dar nenaudojote Nuxt arba застряли su Nuxt 2, rekomenduoju išbandyti Nuxt 3 kitame projekte. Taip, bus learning curve, ypač jei įpratę prie Options API ir Nuxt 2 konvencijų. Bet investicija atsipirks – kodas bus švaresnis, aplikacija greitesnė, o development experience malonesnis.

Ir paskutinis patarimas – skaitykite dokumentaciją. Nuxt dokumentacija yra viena geriausių, kokias mačiau. Ji ne tik paaiškina, kaip kažką padaryti, bet ir kodėl tai veikia taip, kaip veikia. Tai sutaupo begalę laiko debugging’ui ir padeda geriau suprasti framework’ą.

Parašykite komentarą

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *