Tarkibga o'tish

07 β€” Nuxt asoslari

⬅️ Oldingi: 06 β€” Pinia Β· 🏠 README Β· Keyingi: 08 β€” Data & Server ➑️


Vue β€” kutubxona/freymvork. Nuxt β€” Vue ustiga qurilgan meta-framework: routing, SSR, server API, auto-import, SEO β€” hammasini "convention" bilan tayyor beradi.

Eng aniq analogiya: Vue β†’ React kabi, Nuxt β†’ Laravel kabi. Sen Laravel'da har safar router, ORM, middleware'ni noldan yozmaysan β€” convention bor. Nuxt ham xuddi shunday: papkaga fayl tashlaysan, route o'zi paydo bo'ladi.

Nuxt nima beradi (Vue'da o'zing qilishing kerak bo'lganini)

  • File-based routing β€” router/index.js yozmaysan (05-modulni eslagin β€” endi avtomatik)
  • SSR/SSG β€” server'da render (SEO, tezlik)
  • Auto-imports β€” import { ref } yozmaysan; composable/komponentlar avtomatik
  • Server engine (Nitro) β€” /api/... backend endpointlar shu loyihaning ichida
  • Layouts, middleware, plugins β€” Laravel'dagidek tuzilma

Bu modul Nuxt 4 strukturasiga asoslangan. Nuxt 3 farqlari belgilab ketiladi.


7.1 O'rnatish

npx nuxi@latest init my-nuxt-app
cd my-nuxt-app
npm install
npm run dev      # http://localhost:3000

Nuxt 4 papka strukturasi

my-nuxt-app/
β”œβ”€β”€ app/                  # ← brauzerga ketadigan HAMMA narsa shu yerda (Nuxt 4)
β”‚   β”œβ”€β”€ app.vue           # ildiz komponent (Laravel layouts/app.blade.php kabi)
β”‚   β”œβ”€β”€ pages/            # routing β€” har fayl = route
β”‚   β”œβ”€β”€ components/       # auto-import komponentlar
β”‚   β”œβ”€β”€ composables/      # auto-import composable'lar
β”‚   β”œβ”€β”€ layouts/          # qayta ishlatiladigan sahifa qoliplari
β”‚   β”œβ”€β”€ middleware/       # route middleware (auth va h.k.)
β”‚   β”œβ”€β”€ plugins/          # ilova boot'ida ishlaydigan kod
β”‚   β”œβ”€β”€ assets/           # build qilinadigan CSS/rasm
β”‚   └── utils/            # auto-import sof funksiyalar
β”œβ”€β”€ server/               # ← Nitro backend (root'da qoladi)
β”‚   β”œβ”€β”€ api/              # /api/... endpointlar
β”‚   └── ...
β”œβ”€β”€ shared/               # app + server BIRGA ishlatadigan kod (types, utils)
β”œβ”€β”€ public/               # to'g'ridan-to'g'ri xizmat (favicon, robots.txt)
β”œβ”€β”€ nuxt.config.ts        # asosiy konfiguratsiya
└── package.json

Nuxt 3 da farq: app/ papkasi yo'q edi β€” pages/, components/, composables/, app.vue to'g'ridan-to'g'ri ildizda turardi. Nuxt 4 ularni app/ ichiga ko'chirdi (toza ajratish + tezroq startup). Eski tuzilma hali ishlaydi (backward compat), lekin yangi loyihada app/ ishlat.

Nega app/ va server/ ajratilgan? app/ β€” brauzer konteksti, server/ β€” Node/Nitro konteksti. Ikkisida turli global'lar, turli import'lar bor. Ajratish IDE type-safety va xatolarning oldini oladi. Backend dasturchi sifatida bu mantiq senga tushunarli β€” frontend va backend kodi aralashmasligi kerak.


7.2 app.vue β€” ildiz komponent

Eng minimal Nuxt ilovasi β€” faqat app/app.vue:

<!-- app/app.vue -->
<template>
  <div>
    <h1>Salom Nuxt!</h1>
  </div>
</template>

Routing kerak bo'lsa β€” <NuxtPage /> qo'shasan (bu Vue Router'dagi <RouterView> ning Nuxt versiyasi):

<!-- app/app.vue -->
<template>
  <div>
    <AppHeader />          <!-- auto-import! import yozish shart emas -->
    <NuxtPage />           <!-- joriy sahifa shu yerda render bo'ladi -->
    <AppFooter />
  </div>
</template>

app/pages/ papkasi bo'lmasa, Nuxt vue-router ni umuman qo'shmaydi (faqat bitta app.vue β€” landing page uchun). Routing kerak bo'lganda pages/ ochasan.


7.3 File-based routing β€” eng katta "wow"

app/pages/ ichidagi har fayl avtomatik route bo'ladi. router/index.js YO'Q.

app/pages/
β”œβ”€β”€ index.vue            β†’  /
β”œβ”€β”€ about.vue            β†’  /about
β”œβ”€β”€ contact.vue          β†’  /contact
β”œβ”€β”€ blog/
β”‚   β”œβ”€β”€ index.vue        β†’  /blog
β”‚   └── [slug].vue       β†’  /blog/:slug      (dynamic)
β”œβ”€β”€ users/
β”‚   └── [id].vue         β†’  /users/:id
└── [...slug].vue        β†’  404 catch-all

05-modul bilan solishtir: o'sha yerda routes massivini qo'lda yozgansan. Nuxt'da β€” papka tuzilishi = route. Bu Laravel'ning php artisan route:list mantiqiga o'xshaydi: convention bor, qo'lda ro'yxat yo'q.

Quyidagi diagramma app/pages/ papkasidagi har bir fayl qanday qilib avtomatik URL route'iga aylanishini ko'rsatadi:

File-based routing: app/pages papkasidagi har fayl avtomatik route'ga aylanadi

Dynamic route va parametr

<!-- app/pages/users/[id].vue  β†’  /users/123 -->
<script setup>
const route = useRoute()          // auto-import β€” vue-router'dan import yo'q
const id = route.params.id
</script>

<template>
  <h1>User #{{ id }}</h1>
</template>
<template>
  <nav>
    <NuxtLink to="/">Bosh</NuxtLink>
    <NuxtLink to="/about">Haqida</NuxtLink>
    <NuxtLink :to="`/users/${user.id}`">{{ user.name }}</NuxtLink>
  </nav>
</template>

<NuxtLink> β€” <RouterLink> ning aqlli versiyasi: prefetch (ko'rinishga kirganda sahifani oldindan yuklaydi), tashqi linklarni avtomatik aniqlaydi. Dasturiy navigatsiya: navigateTo('/about') (auto-import).

Nested routes

app/pages/dashboard.vue + app/pages/dashboard/ papka:

app/pages/
β”œβ”€β”€ dashboard.vue        ← ota (ichida <NuxtPage/> bo'lishi kerak)
└── dashboard/
    β”œβ”€β”€ index.vue        β†’  /dashboard
    β”œβ”€β”€ profile.vue      β†’  /dashboard/profile
    └── settings.vue     β†’  /dashboard/settings
<!-- app/pages/dashboard.vue -->
<template>
  <div>
    <aside>Yon menyu (doim qoladi)</aside>
    <NuxtPage />          <!-- bola sahifa shu yerda -->
  </div>
</template>

7.4 Layouts β€” qayta ishlatiladigan qoliplar

Bir nechta sahifa bir xil ramkani (header/footer/sidebar) baham ko'rsa β€” layout. Laravel @extends('layouts.app') ning aynan o'zi.

<!-- app/layouts/default.vue -->
<template>
  <div>
    <AppHeader />
    <main>
      <slot />            <!-- sahifa kontenti shu yerga tushadi -->
    </main>
    <AppFooter />
  </div>
</template>
<!-- app/layouts/admin.vue -->
<template>
  <div class="admin">
    <AdminSidebar />
    <slot />
  </div>
</template>

Sahifada layout tanlash:

<!-- app/pages/admin/index.vue -->
<script setup>
definePageMeta({ layout: 'admin' })   // default'dan boshqa
</script>

app/app.vue da <NuxtLayout> bo'lishi kerak (yoki Nuxt avtomatik o'raydi):

<!-- app/app.vue -->
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

default.vue nomli layout β€” avtomatik standart. Boshqasini xohlasang definePageMeta({ layout: 'admin' }).

Diagrammada layout doimiy ramka bo'lib qolishi va <slot /> ichiga har bir sahifa kontenti tushishi tasvirlangan:

Layouts: doimiy ramka ichidagi slot'ga har sahifa kontenti tushadi


7.5 Auto-imports β€” "import yo'q" sehri

Nuxt avtomatik import qiladi: - Vue API: ref, computed, watch, onMounted β€” import yozma - app/components/ β€” har komponent global ishlatishga tayyor - app/composables/ β€” useX() avtomatik - app/utils/ β€” sof funksiyalar avtomatik - Nuxt composable'lari: useRoute, useRouter, useFetch, useState, navigateTo, ...

<script setup>
// HECH QANDAY import yo'q β€” hammasi avtomatik
const count = ref(0)
const route = useRoute()
const { data } = await useFetch('/api/users')
</script>

<template>
  <MyButton @click="count++">Bosildi: {{ count }}</MyButton>
  <!-- MyButton = app/components/MyButton.vue, import qilinmagan! -->
</template>

Komponent nomlash (nested)

app/components/
β”œβ”€β”€ AppHeader.vue              β†’  <AppHeader />
β”œβ”€β”€ base/
β”‚   └── Button.vue             β†’  <BaseButton />     (papka + fayl nomi)
└── user/
    └── Card.vue               β†’  <UserCard />

Nuxt papka nomini prefiks qiladi: base/Button.vue β†’ <BaseButton>. Bu β€” komponentlarni guruhlash + nom to'qnashuvini oldini oladi.

Quyidagi diagramma Nuxt build paytida belgilangan papkalarni skanerlab, kerakli import'larni o'zi qanday qo'shishini ko'rsatadi:

Auto-imports: Nuxt belgilangan papkalarni skanerlab import yozmasdan ishlatish imkonini beradi

Auto-import yoqdimi-yo'qmi? Ko'pchilik yoqtiradi (kam boilerplate). Aniq import xohlasang nuxt.config da o'chirsa bo'ladi, lekin tavsiya β€” convention'ga ergash.


7.6 definePageMeta va useHead (SEO)

<script setup>
definePageMeta({
  layout: 'admin',
  middleware: 'auth',          // app/middleware/auth.ts
  title: 'Boshqaruv paneli',
})

// SEO/meta teglar
useHead({
  title: 'EduCore β€” Boshqaruv',
  meta: [
    { name: 'description', content: 'O\'quv markazi boshqaruv tizimi' },
  ],
})

// Yoki qulayroq:
useSeoMeta({
  title: 'EduCore',
  description: 'O\'quv markazlari uchun SaaS',
  ogImage: '/og.png',
})
</script>

useSeoMeta/useHead β€” har sahifaga unikal SEO. SSR tufayli bu meta teglar server HTML'ida bo'ladi β†’ Google/ijtimoiy tarmoq to'g'ri o'qiydi. (Oddiy Vue SPA'da bu muammo, Nuxt hal qiladi.)


7.7 nuxt.config.ts β€” markaziy konfiguratsiya

// nuxt.config.ts
export default defineNuxtConfig({
  devtools: { enabled: true },

  modules: [
    '@pinia/nuxt',
    '@nuxtjs/tailwindcss',
    '@nuxt/image',
  ],

  css: ['~/assets/css/main.css'],

  runtimeConfig: {
    apiSecret: '',                          // faqat server (maxfiy)
    public: {
      apiBase: 'https://api.educore.uz',    // brauzerga ham ochiq
    },
  },

  app: {
    head: {
      title: 'EduCore',
      htmlAttrs: { lang: 'uz' },
    },
  },
})

~/ yoki @/ β€” app/ papkani bildiradi (Nuxt 4). runtimeConfig β€” .env qiymatlarni xavfsiz boshqarish (apiSecret brauzerga chiqmaydi, public chiqadi). Laravel'dagi config() + .env ajratimiga o'xshaydi.


7.8 Pinia'ni Nuxt'ga ulash

npm install pinia @pinia/nuxt
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@pinia/nuxt'],
})

Endi app/stores/ dagi store'lar auto-import bo'ladi β€” createPinia() qo'lda kerak emas (06-moduldagi setup Nuxt qiladi). Store'larni xuddi 06-moduldagidek yozasan.


Xulosa

  • Nuxt = "Vue uchun Laravel" β€” convention over configuration
  • Nuxt 4: ilova kodi app/ da, backend server/ da, umumiy kod shared/ da
  • app/pages/ = file-based routing ([id].vue = dynamic, [...slug].vue = catch-all) β€” qo'lda router yo'q
  • <NuxtPage> (= RouterView), <NuxtLink> (= aqlli RouterLink, prefetch), navigateTo()
  • Layouts (app/layouts/) = Blade @extends; <slot/> ga sahifa tushadi
  • Auto-imports: Vue API, komponent, composable, util β€” import yozmaysan
  • definePageMeta (layout/middleware), useSeoMeta/useHead (SSR SEO)
  • nuxt.config.ts + runtimeConfig (maxfiy/public ajratish)

🎯 Masalalar (kamida 20 ta)

Setup & routing (1–8)

  1. nuxi init bilan loyiha yarat, ishga tushir, app/app.vue ni o'zgartirib brauzerda ko'r.
  2. app/pages/index.vue, about.vue, contact.vue yarat; <NuxtLink> bilan nav qil. router/index.js yo'qligiga e'tibor ber.
  3. Dynamic route (β˜…): app/pages/users/[id].vue; /users/5, /users/42 ga kirib route.params.id ni ko'rsat.
  4. Catch-all (β˜…): app/pages/[...slug].vue 404 sahifa yasa; mavjud bo'lmagan URL'ni ushla.
  5. <NuxtLink> prefetch (β˜…): Network tab'da, linkga hover qilganda sahifa oldindan yuklanishini kuzat.
  6. navigateTo (β˜…): tugma bosilganda dasturiy ravishda /about ga o't.
  7. Nested route (β˜…β˜…): app/pages/dashboard.vue + dashboard/profile.vue, dashboard/settings.vue; yon menyu doim qolsin.
  8. Blog (β˜…β˜…): app/pages/blog/index.vue (ro'yxat) + blog/[slug].vue (post); ro'yxatdan postga <NuxtLink> bilan o't.

Layouts (9–12)

  1. app/layouts/default.vue (header+footer+slot) yarat; barcha sahifalar undan foydalansin.
  2. app/layouts/admin.vue (β˜…) yarat; definePageMeta({ layout: 'admin' }) bilan faqat admin sahifalarga qo'lla.
  3. Layout'siz sahifa (β˜…): Login sahifasiga layout: false yoki bo'sh layout ber.
  4. Dinamik layout (β˜…β˜…): foydalanuvchi rolega qarab layout almashtirish (definePageMeta + computed/middleware).

Auto-import & komponentlar (13–17)

  1. app/components/AppHeader.vue yarat; import qilmasdan app.vue da ishlat.
  2. Nested komponent (β˜…): app/components/base/Button.vue β†’ <BaseButton> sifatida ishlat.
  3. Composable auto-import (β˜…): app/composables/useCounter.ts yarat (04-moduldan); import yozmasdan sahifada ishlat.
  4. Util auto-import (β˜…): app/utils/formatDate.ts yarat; sahifada to'g'ridan-to'g'ri chaqir.
  5. 04-moduldagi useToggle ni app/composables/ ga ko'chir va modal komponentida ishlat.

Meta, config, integratsiya (18–24)

  1. SEO (β˜…): har sahifaga useSeoMeta bilan unikal title/description ber; View Source'da meta'lar HTML'da ekanini tasdiqla (SSR isboti).
  2. definePageMeta({ title }) (β˜…): app/layouts yoki plugin orqali sahifa title'ini boshqar.
  3. TailwindCSS (β˜…): @nuxtjs/tailwindcss modulini ulab, sahifani Tailwind bilan stilla.
  4. Pinia (β˜…β˜…): @pinia/nuxt ni ulab, 06-moduldagi useCartStore ni Nuxt'da ishlat (auto-import store).
  5. runtimeConfig (β˜…β˜…): public.apiBase qo'sh; sahifada useRuntimeConfig().public.apiBase ni o'qib ko'rsat.
  6. 05↔07 solishtiruv (β˜…β˜…): 05-moduldagi qo'lda Vue Router setup'ini Nuxt file-based routing bilan taqqosla; xulosani izoh sifatida yoz (qaysi convention nimani avtomatlashtirdi).
  7. EduCore skeleti (β˜…β˜…β˜…): app/pages/ da index, login, app/ (dashboard, students, payments β€” nested), admin/; default + admin + auth layout'lar; auto-import header/sidebar komponentlari. (Middleware/auth β€” keyingi modulda to'liq.)

βœ… Tanlangan yechimlar

7 β€” Nested dashboard

<!-- app/pages/dashboard.vue (ota) -->
<template>
  <div style="display:flex; gap:1rem">
    <aside>
      <NuxtLink to="/dashboard/profile">Profil</NuxtLink>
      <NuxtLink to="/dashboard/settings">Sozlamalar</NuxtLink>
    </aside>
    <main>
      <NuxtPage />   <!-- bola sahifalar shu yerda -->
    </main>
  </div>
</template>
<!-- app/pages/dashboard/profile.vue -->
<template><h2>Profil sahifasi</h2></template>

10 β€” Admin layout

<!-- app/layouts/admin.vue -->
<template>
  <div class="admin-wrap">
    <AdminSidebar />
    <section class="content"><slot /></section>
  </div>
</template>
<!-- app/pages/admin/index.vue -->
<script setup>
definePageMeta({ layout: 'admin' })
</script>
<template><h1>Admin Dashboard</h1></template>

➑️ Keyingi: 08 β€” Data Fetching & Server (Nitro)