Vue 3 և Nuxt
Ռեակտիվ կոմպոնենտներ Composition API-ով, Pinia store-եր և full-stack Nuxt հավելվածներ SSR-ով։
30 վայրկյանում
Vue-ն JavaScript ֆրեյմվորք է կոմպոնենտներից օգտատիրոջ ինտերֆեյսներ կառուցելու համար, որը հայտնի է մեղմ ուսուցման կորով և ճշգրիտ ռեակտիվության համակարգով։ Vue 3-ի Composition API-ն տրամաբանությունը կազմակերպում է վերաօգտագործելի ֆունկցիաներում, իսկ Pinia-ն նրա պաշտոնական state store-ն է։ Nuxt-ը Vue-ի վրա կառուցված full-stack ֆրեյմվորքն է, որը կատարում է նույն դերը, ինչ Next.js-ը React-ի համար՝ ֆայլերով routing, server-side rendering, տվյալների ստացում և սերվերային API route-եր մեկ նախագծում։
Իմ ամենօրյա stack-ում չէ․ գիտեմ հիմնական գաղափարները և մանրամասները կսովորեմ, երբ նախագիծը դա պահանջի։
Ինչու է սա կարևոր
- Vue-ն ամենատարածված ֆրոնտենդ ֆրեյմվորքներից է, հատկապես ուժեղ Եվրոպայում և Ասիայում, և շատ գործող պրոդուկտներ ու գործակալություններ կառուցված են դրա վրա։
- Նրա նուրբ ռեակտիվությունը ճշգրիտ հետևում է, թե որ տվյալներն է օգտագործում կոմպոնենտը, ուստի թարմացումները արդյունավետ են՝ առանց ձեռքով memoization-ի։
- Single-file կոմպոնենտները template-ը, տրամաբանությունը և ոճերը պահում են միասին, ինչը շատ թիմերի համար հեշտ է կարդալ և նոր մարդկանց ներգրավել։
- Nuxt-ը Vue թիմերին տալիս է SSR, SEO-ի համար հարմար էջեր, սերվերային route-եր և հիբրիդ ռենդերինգ ուժեղ կոնվենցիաներով՝ համեմատելի այն բանի հետ, ինչ Next.js-ը տալիս է React թիմերին։
Ինչպես է աշխատում
01Գաղափարը՝ ռեակտիվ տվյալները ղեկավարում են view-ը
Vue-ում դուք հայտարարում եք state, և template-ը նկարագրում է, թե ինչպիսին պետք է լինի UI-ը այդ state-ի համար։ Երբ state-ը փոխվում է, Vue-ն թարմացնում է DOM-ի միայն այն մասերը, որոնք կախված են դրանից։ Ներքուստ Vue 3-ը ձեր տվյալները փաթաթում է JavaScript Proxy-ներով. երբ կոմպոնենտը ռենդեր է լինում, Vue-ն գրանցում է, թե որ ռեակտիվ հատկություններն է այն կարդացել, և երբ դրանցից մեկը փոխվում է, նորից աշխատեցնում է միայն այդ կոմպոնենտի render-ը։ Պատկերացրեք աղյուսակ (spreadsheet). բանաձևերով բջիջները ավտոմատ վերահաշվարկվում են, երբ փոխվում են այն բջիջները, որոնց հղում են անում։ Vue հավելվածը կոմպոնենտների ծառ է, որոնք սովորաբար գրվում են որպես Single-File Component-ներ (.vue ֆայլեր)՝ template-ով, script-ով և ընտրովի scoped ոճերով։ Vue 3.5-ը ներկայիս կայուն տարբերակն է. Vue 3.6-ը նոր, կոմպիլյատորի վրա հիմնված «Vapor mode»-ով 2026-ի վերջի դրությամբ release-candidate փուլում է։
02Կոմպոնենտ Composition API-ով
script setup-ի ներսում ref()-ը ստեղծում է ռեակտիվ արժեք (script-ում կարդացվում և գրվում է .value-ով, template-ում օգտագործվում է ուղղակիորեն), reactive()-ը ստեղծում է ռեակտիվ օբյեկտ, computed()-ը ստանում է քեշավորված ածանցյալ արժեքներ, իսկ watch()-ը կատարում է կողմնակի ազդեցություններ, երբ աղբյուրները փոխվում են։ Props-ը հայտարարվում են defineProps-ով և, սկսած Vue 3.5-ից, կարող են destructure արվել՝ մնալով ռեակտիվ։ Իրադարձությունները վեր են բարձրանում defineEmits-ով, իսկ defineModel-ը ստեղծում է երկկողմանի կապ v-model-ի համար։ Template-ներն օգտագործում են դիրեկտիվներ՝ v-if, v-for (:key-ով), v-bind (կարճ՝ :) և v-on (կարճ՝ @)։
<script setup lang="ts">
import { ref, computed } from "vue";
const { items = [] } = defineProps<{ items?: { id: number; name: string; price: number }[] }>();
const emit = defineEmits<{ select: [id: number] }>();
const query = ref("");
const filtered = computed(() =>
items.filter((i) => i.name.toLowerCase().includes(query.value.toLowerCase()))
);
</script>
<template>
<input v-model="query" placeholder="Search products" />
<p v-if="!filtered.length">No results</p>
<ul v-else>
<li v-for="item in filtered" :key="item.id" @click="emit('select', item.id)">
{{ item.name }} — {{ item.price.toFixed(2) }}
</li>
</ul>
</template>
03Composable-ներ. վերաօգտագործելի տրամաբանություն
Composable-ը սովորական ֆունկցիա է՝ useSomething անունով, որն օգտագործում է Vue-ի ռեակտիվության API-ները և վերադարձնում ռեակտիվ state։ Այն React-ի custom hook-ի Vue համարժեքն է, բայց աշխատում է մեկ անգամ կոմպոնենտի setup-ի ժամանակ, ոչ թե յուրաքանչյուր render-ի, ուստի չկան dependency array-եր կամ stale closure-ի թակարդներ։ Composable-ները փոխարինում են Vue 2-ի mixin-ներին, որոնք ունեին անունների բախումներ և անհասկանալի ծագում։ Օգտագործեք դրանք տվյալների ստացման, ձևերի տրամաբանության, բրաուզերի API-ների (online կարգավիճակ, media query-ներ) և ընդհանուր վարքագծի համար։ VueUse գրադարանն առաջարկում է հարյուրավոր պատրաստի composable-ներ։ Lifecycle hook-երը, ինչպես onMounted-ը և onUnmounted-ը, կարելի է կանչել composable-ների ներսում՝ listener-ներ կարգավորելու և մաքրելու համար։
// composables/useOnline.ts
import { ref, onMounted, onUnmounted } from "vue";
export function useOnline() {
const online = ref(typeof navigator === "undefined" ? true : navigator.onLine);
const update = () => (online.value = navigator.onLine);
onMounted(() => {
window.addEventListener("online", update);
window.addEventListener("offline", update);
});
onUnmounted(() => {
window.removeEventListener("online", update);
window.removeEventListener("offline", update);
});
return { online };
}
04State-ի կառավարում Pinia-ով
Բազմաթիվ կոմպոնենտների միջև կիսվող state-ի համար, օրինակ՝ մուտք գործած օգտատերը կամ զամբյուղը, Vue-ի պաշտոնական store-ը Pinia-ն է (այն փոխարինեց Vuex-ին)։ Store-ը սահմանվում է defineStore-ով և կարող է օգտագործել նույն setup շարահյուսությունը, ինչ կոմպոնենտները. ref-երը state են, computed-ները՝ getter-ներ, ֆունկցիաները՝ action-ներ։ Pinia-ն type-safe է, մոդուլային (մեկ store յուրաքանչյուր դոմենի համար), աջակցում է Vue DevTools-ը և աշխատում է SSR-ի հետ Nuxt-ում։ State-ը destructure անելիս օգտագործեք storeToRefs, որպեսզի արժեքները մնան ռեակտիվ։ Ամեն ինչ չէ, որ պետք է store-ում լինի. սերվերի տվյալները հաճախ ավելի լավ է պահել տվյալների ստացման շերտում, ինչպես Nuxt-ի useFetch-ը կամ TanStack Query-ն Vue-ի համար, իսկ լոկալ UI state-ը մնում է կոմպոնենտներում։
// stores/cart.ts
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useCartStore = defineStore("cart", () => {
const items = ref<{ id: number; qty: number; price: number }[]>([]);
const total = computed(() => items.value.reduce((s, i) => s + i.qty * i.price, 0));
function add(id: number, price: number) {
const line = items.value.find((i) => i.id === id);
line ? line.qty++ : items.value.push({ id, qty: 1, price });
}
return { items, total, add };
});
05Nuxt. full-stack Vue ֆրեյմվորքը
Nuxt 4-ը ներկայիս major տարբերակն է (Nuxt 3-ի աջակցությունն ավարտվեց 2026-ի կեսերին)։ Այն տալիս է ֆայլերի վրա հիմնված routing app/pages-ից, layout-ներ, ավտոմատ import արվող կոմպոնենտներ և composable-ներ, լռելյայն server-side rendering և Nitro-ով աշխատող server թղթապանակ API route-երի և middleware-ի համար։ Nitro-ն preset-երի միջոցով կարող է նույն հավելվածը deploy անել Node.js սերվերների, serverless պլատֆորմների կամ edge runtime-երի վրա։ Nuxt 4-ը հավելվածի կոդը լռելյայն տեղափոխեց app/ թղթապանակ՝ առանձնացնելով այն server/-ից, և բարելավեց տվյալների ստացման վարքագիծը և TypeScript նախագծերի բաժանումը։ Մոդուլները (@nuxt/image, @nuxt/content, @pinia/nuxt, @nuxtjs/i18n) հնարավորություններ են ավելացնում կոնֆիգի մեկ տողով։
npx nuxi@latest init my-shop
cd my-shop && npm run dev
# Project layout (Nuxt 4)
# app/pages/index.vue -> /
# app/pages/products/[id].vue -> /products/:id
# app/components/ProductCard.vue (auto-imported)
# app/composables/useCart.ts (auto-imported)
# server/api/products/[id].get.ts -> GET /api/products/:id
# nuxt.config.ts
06Տվյալների ստացում և սերվերային route-եր Nuxt-ում
Էջերում և կոմպոնենտներում օգտագործեք useFetch կամ useAsyncData։ Դրանք SSR-ի ժամանակ աշխատում են սերվերում, արդյունքը սերիալիզացնում են HTML payload-ի մեջ և hydration-ի ժամանակ նորից օգտագործում client-ում, ուստի տվյալները երկու անգամ չեն բերվում։ Դրանք վերադարձնում են ռեակտիվ data, status, error և refresh ֆունկցիա, և ընդունում են key, lazy-ի և server-ի նման ընտրանքներ և ռեակտիվ պարամետրեր, որոնց փոփոխության դեպքում տվյալները նորից են բերվում։ Իրադարձությունների handler-ների համար, ինչպես ձևի ուղարկումը, ուղղակիորեն օգտագործեք $fetch։ Սերվերային route-երն ապրում են server/api-ում և export են անում defineEventHandler. դրանք աշխատում են միայն սերվերում, ուստի կարող են գաղտնիքներ կարդալ runtimeConfig-ից և աշխատել բազաների հետ։
// server/api/products/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, "id");
const product = await findProduct(id); // your DB call
if (!product) throw createError({ statusCode: 404, statusMessage: "Not found" });
return product;
});
<!-- app/pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute();
const { data: product, status, error } = await useFetch(`/api/products/${route.params.id}`);
useSeoMeta({ title: () => product.value?.name ?? "Product" });
</script>
07Ռենդերինգի ռեժիմներ և deploy
Nuxt-ը աջակցում է universal rendering (SSR գումարած hydration), միայն client-ի SPA ռեժիմ, static generation և հիբրիդ ռենդերինգ, որտեղ յուրաքանչյուր route ստանում է իր կանոնը։ nuxt.config-ի route rules-ը թույլ են տալիս մարքեթինգային էջերը prerender անել build-ի ժամանակ, ապրանքների էջերը քեշավորել stale-while-revalidate-ով, dashboard-ը ռենդեր անել միայն client-ում և ավելացնել redirect-ներ կամ header-ներ՝ ամբողջը մեկ հավելվածում։ Build արեք nuxi build-ով server կամ serverless թիրախի համար, կամ nuxi generate-ով՝ ստատիկ կայքի համար։ .output-ի արդյունքը ինքնաբավ է. VPS-ի վրա գործարկում եք node .output/server/index.mjs nginx-ի կամ process manager-ի հետևում. Vercel-ում, Netlify-ում կամ Cloudflare-ում preset-ը հայտնաբերվում է ավտոմատ։
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["@pinia/nuxt", "@nuxt/image"],
runtimeConfig: {
apiSecret: "", // NUXT_API_SECRET, server only
public: { apiBase: "/api" }, // NUXT_PUBLIC_API_BASE, exposed to client
},
routeRules: {
"/": { prerender: true },
"/products/**": { swr: 600 },
"/dashboard/**": { ssr: false },
"/old-shop/**": { redirect: "/products/**" },
},
});
Օգտագործեք, երբ
- Թիմեր, որոնց դուր են գալիս HTML-ի նման template-ները և մեղմ ուսուցման կորը, կամ որոնք արդեն Vue-ի փորձ ունեն։
- Բովանդակային կայքեր, e-commerce և մարքեթինգային էջեր, որոնց SEO-ի համար պետք է SSR կամ prerendering՝ կառուցված Nuxt-ով։
- Սերվերում ռենդեր արվող էջերի (Laravel, Django) աստիճանական հարստացում ինտերակտիվ widget-ներով, որտեղ Vue-ն հեշտությամբ ներդրվում է։
- Ադմին վահանակներ և dashboard-ներ, որտեղ Vue-ի էկոհամակարգը (Vuetify, PrimeVue, Element Plus, Nuxt UI) արագացնում է առաքումը։
Մի՛ օգտագործեք, երբ
- Երբ թիմը և կոմպոնենտների գրադարաններն արդեն React-ի վրա են. էկոհամակարգերը խառնելը կրկնապատկում է սպասարկումը։
- Երբ մոբայլի համար React Native-ի հետ կոդի կիսումը պարտադիր պահանջ է. Vue-ի native տարբերակները շատ ավելի քիչ հասուն են։
- Շատ փոքր ստատիկ էջեր, որտեղ բավական է պարզ HTML կամ Astro-ի նման թեթև գործիք։
Այլընտրանքներ
- React + Next.js
Ամենամեծ էկոհամակարգն ու աշխատանքի շուկան. Server Components և JSX-ի վրա հիմնված մոդել։
- Svelte + SvelteKit
Compiler-first, շատ փոքր bundle-ներ, rune-երի վրա հիմնված ռեակտիվություն։
- Angular
«Batteries included» enterprise ֆրեյմվորք՝ signal-ներով, DI-ով և խիստ կառուցվածքով։
- Astro
Բովանդակությունը առաջնային դարձնող կայքեր, որոնք քիչ JavaScript են ուղարկում. կարող է Vue կոմպոնենտներ տեղադրել որպես island-ներ։
Լավագույն պրակտիկաներ
- Բոլոր նոր կոդի համար օգտագործեք script setup TypeScript-ով և Composition API-ով։
- v-for-ի տարրերին միշտ տվեք կայուն, եզակի :key, և երբեք մի համատեղեք v-if-ը և v-for-ը նույն տարրի վրա։
- Վերաօգտագործելի տրամաբանությունը հանեք composable-ների մեջ, իսկ կոմպոնենտները պահեք ռենդերինգի վրա կենտրոնացած։
- Nuxt-ում էջի տվյալները բերեք useFetch-ով կամ useAsyncData-ով, ոչ թե setup-ի ներսում $fetch-ով, որպեսզի խուսափեք կրկնակի բեռնումից։
- Գաղտնիքները պահեք միայն սերվերի համար նախատեսված runtimeConfig-ում և runtimeConfig.public-ի տակ տրամադրեք միայն հանրային key-երը։
- Մեծ անփոփոխ տվյալների համար օգտագործեք shallowRef, իսկ ածանցյալ արժեքների համար՝ computed, state-ը պատճենող watcher-ների փոխարեն։
- Lint արեք ESLint-ով գումարած eslint-plugin-vue, և CI-ում template-ների տիպերը ստուգեք vue-tsc-ով։
Տարածված սխալներ
- reactive() օբյեկտը կամ Pinia store-ը destructure անելը առանց toRefs-ի կամ storeToRefs-ի, ինչը լուռ կոտրում է ռեակտիվությունը։
- watch-ի օգտագործումը state-ի երկու կտոր համաժամեցված պահելու համար՝ computed արժեքի փոխարեն։
- SSR setup-ի ժամանակ window-ին կամ localStorage-ին դիմելը, ինչը առաջացնում է սերվերի սխալներ կամ hydration mismatch-եր։
- $fetch-ը Nuxt էջի վերին մակարդակում կանչելը, ինչը տվյալները բերում է մեկ անգամ սերվերում և նորից client-ում։
- Հավելվածի ամբողջ state-ը Pinia-ում պահելը, ներառյալ սերվերի քեշը և ժամանակավոր UI state-ը։
Խորը վերլուծություն
08Ռեակտիվության համակարգի ներսում
Յուրաքանչյուր ռեակտիվ օբյեկտ Proxy է, որի get trap-ը կանչում է track(target, key), իսկ set trap-ը՝ trigger(target, key)։ Effect-ները, օրինակ՝ կոմպոնենտի render ֆունկցիան, computed-ը կամ watcher-ը, աշխատում են active-effect կոնտեքստում. այդ աշխատանքի ընթացքում յուրաքանչյուր հետևվող ընթերցում effect-ը գրանցում է որպես այդ key-ի բաժանորդ։ Trigger-ի դեպքում Vue-ն պլանավորում է բաժանորդ effect-ները. կոմպոնենտների թարմացումները խմբավորվում են և ասինխրոն կատարվում microtask-ում, ահա թե ինչու DOM-ը թարմացվում է nextTick()-ից հետո։ Vue 3.4-ը computed արժեքները դարձրեց ծույլ և ծանուցող միայն այն ժամանակ, երբ դրանց արդյունքն իրականում փոխվում է, իսկ Vue 3.5-ը ներքին մասը վերակառուցեց version-counting, doubly-linked-list դիզայնով, որը զգալիորեն կրճատեց հիշողության օգտագործումը։ Օգտագործեք markRaw այն օբյեկտների համար, որոնք երբեք չպետք է ռեակտիվ լինեն, օրինակ՝ քարտեզի կամ գծապատկերների գրադարանների instance-ները։
import { ref, computed, nextTick, markRaw, shallowRef } from "vue";
const count = ref(0);
const isEven = computed(() => count.value % 2 === 0); // only notifies on true<->false
count.value++; // DOM not updated yet
await nextTick(); // now it is
// Large third-party instance: keep it out of reactivity
const map = shallowRef(markRaw(createMap("#map")));
09Կոմպիլյատորի օպտիմալացումներ և Vapor mode
Vue-ի template կոմպիլյատորն է պատճառը, որ Vue-ի virtual DOM-ն ավելի էժան է, քան պարզունակը։ Այն բարձրացնում (hoist) է ստատիկ node-երը, որպեսզի դրանք ստեղծվեն մեկ անգամ, դինամիկ node-երը նշում է patch flag-երով (փոխվում է միայն տեքստը, միայն class-ը) և դինամիկ երեխաներին խմբավորում է block-երում, որպեսզի diff-ը ամբողջությամբ բաց թողնի ստատիկ կառուցվածքը։ Սա հնարավոր է, որովհետև template-ները ստատիկ վերլուծելի են՝ ի տարբերություն կամայական JSX-ի։ Vapor mode-ը, որը գալիս է Vue 3.6-ում, ավելի հեռու է գնում. script setup vapor-ով ընտրված կոմպոնենտը կոմպիլյացվում է ուղիղ DOM գործողությունների, որոնք կապված են ռեակտիվ effect-ներին, ընդհանրապես առանց virtual DOM-ի՝ Solid-ի կամ Svelte-ի նման։ Այն կարող է համագործակցել սովորական կոմպոնենտների հետ, ուստի թիմերը կայունանալուց հետո կարող են այն ընդունել ըստ կոմպոնենտի՝ արտադրողականության համար կրիտիկական էկրաններում։
10SSR-ի ներքին մանրամասները Nuxt-ում. payload, key-եր և քեշավորում
SSR-ի ժամանակ Nuxt-ը ձեր կոմպոնենտները գործարկում է սերվերում, և յուրաքանչյուր useAsyncData կամ useFetch արդյունք պահվում է իր key-ի տակ payload-ում՝ սերիալիզացված HTML-ի մեջ։ Hydration-ի ժամանակ client-ը տվյալները կարդում է payload-ից՝ նորից բերելու փոխարեն։ Key-երը կարևոր են. նույն key-ով երկու կանչ կիսում են տվյալները, իսկ ֆայլից և տողից ավտոմատ գեներացված key-ն աշխատում է միայն այն դեպքում, երբ կանչը setup-ի վերին մակարդակում է։ Պայմանի կամ ցիկլի ներսում բեռնելը բացահայտ key-եր է պահանջում։ Nitro-ի routeRules-ը swr-ով կամ isr-ով ռենդեր արված HTML-ը քեշավորում է սերվերի կամ CDN-ի շերտում, իսկ defineCachedEventHandler-ը քեշավորում է API պատասխանները։ Հիշեք, որ սերվերի state-ը կիսվում է հարցումների միջև. երբեք մի պահեք կոնկրետ օգտատիրոջ տվյալներ մոդուլի մակարդակի փոփոխականներում սերվերի կոդում կամ composable-ներում։
// Explicit key + transform to keep the payload small
const { data } = await useAsyncData(
`product-${id}`,
() => $fetch(`/api/products/${id}`),
{ pick: ["id", "name", "price"] }
);
// server/api/rates.get.ts — cached for 10 minutes
export default defineCachedEventHandler(async () => {
return await $fetch("https://api.example.com/rates");
}, { maxAge: 600 });
11Մեծ Vue կոդային բազայի արտադրողականություն և մասշտաբավորում
Bundle-ի չափի համար օգտագործեք defineAsyncComponent և route-ի մակարդակով lazy loading, որպեսզի յուրաքանչյուր էջ բեռնի միայն այն, ինչ պետք է. Nuxt-ը route splitting-ն անում է ավտոմատ, իսկ Lazy նախածանցը (LazyChart) հետաձգում է կոմպոնենտը մինչև այն ռենդեր լինի։ Nuxt-ն աջակցում է նաև lazy hydration ռազմավարություններ, ինչպես hydrate-on-visible-ը, որպեսզի էկրանից ներքև գտնվող ինտերակտիվ կոմպոնենտները բեռնման ժամանակ main thread-ի ժամանակ չծախսեն։ Երկար ցուցակների համար օգտագործեք virtual scrolling (vue-virtual-scroller կամ TanStack Virtual) և թանկ տողերի համար՝ v-memo։ Մեծ կոդային բազաներում Nuxt layer-ները թույլ են տալիս մի քանի հավելվածի կիսել կոմպոնենտներ, կոնֆիգ և composable-ներ բազային layer-ից, իսկ խիստ TypeScript-ը vue-tsc-ով բռնում է template-ների տիպերի սխալները։ Օպտիմալացնելուց առաջ պրոֆիլավորեք Vue DevTools-ի performance timeline-ով։
Իրական իրավիճակներ
SEO խնդիրներ Vue single-page խանութում
Խնդիր
Որպես միայն client-ի Vue SPA կառուցված առցանց խանութը վատ դիրքեր ունի։ Ապրանքների էջերը crawler-ներին ցույց են տալիս դատարկ կմախք, իսկ սոցիալական preview-ներում չկան վերնագրեր կամ նկարներ։
Ինչպես լուծել
Միգրացրեք Nuxt՝ նորից օգտագործելով գոյություն ունեցող կոմպոնենտները և Pinia store-երը։ Route-երը տեղափոխեք app/pages, client-ի բեռնումը փոխարինեք useFetch-ով, որպեսզի ապրանքների տվյալները ռենդեր լինեն սերվերում, և ավելացրեք useSeoMeta վերնագրերի, նկարագրությունների և Open Graph նկարների համար՝ յուրաքանչյուր ապրանքի համար։ Օգտագործեք routeRules՝ կատեգորիաների էջերը prerender անելու և ապրանքների էջերին swr քեշավորում կիրառելու համար, որպեսզի սերվերը չծանրաբեռնվի յուրաքանչյուր դիտման ժամանակ։ Ավելացրեք sitemap մոդուլ և canonical URL-ներ։ view-source-ով և rich results թեստով ստուգեք, որ բովանդակությունը նախնական HTML-ում է։
Dashboard-ը սառչում է 10,000 տող ֆիլտրելիս
Խնդիր
Vue-ով կառուցված ադմին աղյուսակը վայրկյաններով դանդաղում է, երբ օգտատերը ֆիլտրի դաշտում տեքստ է մուտքագրում։ Պրոֆիլավորումը ցույց է տալիս ծանր ռեակտիվության և ռենդերինգի աշխատանք յուրաքանչյուր ստեղնսեղմման ժամանակ։
Ինչպես լուծել
Հում տվյալները պահեք shallowRef-ում, որպեսզի Vue-ն խորությամբ proxy չանի 10,000 օբյեկտ։ Որոնման մուտքը debounce արեք VueUse-ի refDebounced-ով, իսկ ֆիլտրված արդյունքները հաշվարկեք computed-ով, որպեսզի դրանք վերահաշվարկվեն միայն մուտքերի փոփոխության դեպքում։ Ռենդեր արեք virtual scroller-ով, որպեսզի DOM-ում լինեն միայն տեսանելի տողերը։ Եթե տողերը ծանր կոմպոնենտներ են, օգտագործեք v-memo՝ տողի տվյալներով key-ով։ Սերվերի մասշտաբի տվյալների համար ֆիլտրումը և էջավորումը տեղափոխեք API։ Կրկին պրոֆիլավորեք DevTools-ում՝ հաստատելու, որ main thread-ը մնում է արձագանքող։
Օգտատիրոջ տվյալները արտահոսում են այցելուների միջև SSR-ից հետո
Խնդիր
SSR-ը միացնելուց հետո օգտատերը header-ում կարճ ժամանակով տեսավ մեկ այլ օգտատիրոջ անունը։ Հավելվածը ընթացիկ օգտատիրոջը պահում է composable-ում՝ մոդուլի մակարդակի ref-ով։
Ինչպես լուծել
Սերվերում մոդուլի մակարդակի state-ը կիսվում է բոլոր հարցումների միջև, ուստի մի հարցման օգտատերը արտահոսում է մյուսի render-ի մեջ։ Օգտատիրոջը տեղափոխեք Pinia store կամ Nuxt-ի useState, որոնք երկուսն էլ սերվերում state են ստեղծում յուրաքանչյուր հարցման համար և hydrate անում client-ում։ Բեռնեք այն session cookie-ից սերվերային plugin-ում կամ route middleware-ում, և երբեք մի քեշավորեք անհատականացված էջերը swr-ով կամ CDN կանոններով։ Ստուգեք մյուս composable-ները մոդուլի մակարդակի ref-երի համար և ավելացրեք թեստ, որը ռենդեր է անում երկու զուգահեռ հարցում տարբեր օգտատերերով։
Արագ ուղեցույց
- Նոր Vue հավելված (Vite)
npm create vue@latest- Նոր Nuxt հավելված
npx nuxi@latest init my-app- Երկկողմանի կապված prop
const model = defineModel<string>()- Template ref (3.5+)
const input = useTemplateRef<HTMLInputElement>("input")- Store-ի արժեքները ռեակտիվ պահել
const { items, total } = storeToRefs(useCartStore())- Nuxt SSR տվյալներ
const { data, status, refresh } = await useFetch("/api/items")- Միայն client-ի widget
<ClientOnly><MapView /></ClientOnly>- Քեշավորում ըստ route-ի
routeRules: { "/blog/**": { swr: 3600 } }- Template-ների տիպերի ստուգում
npx vue-tsc --noEmit- Nuxt-ի build Node-ի համար
npx nuxi build && node .output/server/index.mjs
Հարցեր և պատասխաններ
Q1Ինչո՞վ է Vue-ի ռեակտիվությունը տարբերվում React-ի մոդելից։
React-ը նորից աշխատեցնում է կոմպոնենտի ֆունկցիան, երբ նրա state-ը կամ props-ը փոխվում են, և համեմատում ստացված virtual DOM-ը. ավելորդ աշխատանքը վերահսկում եք memoization-ով և dependency array-երով։ Vue-ն ավտոմատ հետևում է կախվածություններին. ռեակտիվ օբյեկտները Proxy-ներ են, և render-ի ժամանակ Vue-ն գրանցում է, թե որ հատկություններն են կարդացվել։ Երբ դրանցից մեկը փոխվում է, նորից ռենդեր են լինում միայն այն կոմպոնենտները, որոնք օգտագործել են այն։ Setup կոդն աշխատում է մեկ անգամ, ոչ թե յուրաքանչյուր render-ի, ուստի stale closure-ներ չկան։ Արդյունքում Vue հավելվածներին հազվադեպ է պետք ձեռքով memoization։ React-ի մոդելն ավելի բացահայտ և ֆունկցիոնալ է. Vue-ինը՝ ավելի ավտոմատ և մոտ signal-ներին, որոնք այդ ժամանակից ի վեր ընդունել են նաև այլ ֆրեյմվորքներ։
Q2ref, թե՞ reactive. որն օգտագործել։
Vue թիմը խորհուրդ է տալիս ref-ը որպես հիմնական API։ ref-ն աշխատում է ցանկացած տիպի արժեքի հետ, ներառյալ պրիմիտիվները, և կարող եք փոխարինել ամբողջ արժեքը կամ այն փոխանցել՝ առանց ռեակտիվությունը կորցնելու։ reactive-ն աշխատում է միայն օբյեկտների հետ և կորցնում է ռեակտիվությունը, եթե այն destructure եք անում կամ փոփոխականը վերագրում, ինչը բագերի տարածված աղբյուր է։ Template-ներում ref-երը ավտոմատ «բացվում» են, ուստի .value-ի գինը երևում է միայն script-ում։ reactive-ը երբեմն օգտագործում եմ լոկալ ձևի օբյեկտի համար, որը երբեք չի վերագրվում, իսկ ref-ը՝ մնացած ամեն ինչի համար, գումարած shallowRef մեծ տվյալների համար, որոնք փոխարինվում են, ոչ թե մուտացիայի ենթարկվում։
Q3Ի՞նչ է Nuxt-ն ավելացնում Vue-ի վրա։
Vue-ն կոմպոնենտների գրադարանն է. Nuxt-ը՝ հավելվածի ֆրեյմվորքը։ Nuxt-ն ավելացնում է ֆայլերի վրա հիմնված routing և layout-ներ, server-side rendering hydration-ով, prerendering և ըստ route-ի քեշավորման կանոններ, տվյալների ստացման composable-ներ, որոնք սերվերի տվյալները փոխանցում են client-ին, Nitro սերվեր API route-երի և middleware-ի համար, SEO օգնականներ, ավտոմատ import-ներ, runtime կոնֆիգուրացիա և մոդուլների էկոհամակարգ նկարների, բովանդակության, i18n-ի և auth-ի համար։ Այն նաև preset-երի միջոցով նույն նախագիծը deploy է անում Node.js, serverless կամ edge պլատֆորմների վրա։ Այն համեմատելի է Next.js-ի հետ React-ի համար. այս մասերը կարող էիք ինքներդ հավաքել Vite-ով և Vue Router-ով, բայց Nuxt-ը դրանք դարձնում է համահունչ։
Q4Ի՞նչ է hydration mismatch-ը և ինչպե՞ս խուսափել դրանից։
SSR-ի դեպքում սերվերը ռենդեր է անում HTML, իսկ client-ը հետո hydrate է անում այն՝ Vue-ի ռեակտիվությունը կցելով գոյություն ունեցող DOM-ին։ Եթե client-ի առաջին render-ը տալիս է սերվերից տարբեր markup, Vue-ն զգուշացնում է mismatch-ի մասին և կարող է նորից ռենդեր անել էջի մասեր՝ առաջացնելով թարթում կամ բագեր։ Տիպիկ պատճառներն են setup-ի ժամանակ window-ի, localStorage-ի կամ ընթացիկ ժամանակի ընթերցումը, պատահական ID-ները և locale-ից կախված ֆորմատավորումը։ Լուծումներ. միայն բրաուզերի կոդը տեղափոխեք onMounted, միայն բրաուզերի widget-ները փաթաթեք ClientOnly-ով, կայուն ID-ների համար օգտագործեք useId, իսկ ժամանակը կամ locale-ը սերվերից փոխանցեք useState-ի կամ payload-ի միջոցով։
Q5Pinia, թե՞ composable-ներ ընդհանուր state-ի համար։
Composable-ը, որը ref-երը հայտարարում է ֆունկցիայի ներսում, յուրաքանչյուր կոմպոնենտի համար նոր state է ստեղծում. ref-երը մոդուլի մակարդակում հայտարարելը կիսում է state-ը, բայց սերվերում այդ state-ը SSR-ի ժամանակ արտահոսում է տարբեր օգտատերերի հարցումների միջև, ինչը անվտանգության խնդիր է։ Pinia-ն լուծում է սա. store-երը ստեղծվում են յուրաքանչյուր app instance-ի համար, ուստի SSR հարցումները մեկուսացված են, և ստանում եք DevTools-ի աջակցություն, plugin-ներ և store state-ի hydration։ Իմ կանոնը. լոկալ վերաօգտագործելի տրամաբանությունը՝ composable-ներում, գլոբալ client state-ը՝ Pinia store-երում, իսկ սերվերի տվյալները՝ useFetch-ում կամ query գրադարանում։ Nuxt-ում useState-ը թեթև, SSR-ի համար անվտանգ տարբերակ է փոքր ընդհանուր արժեքների համար։
Q6Ինչպե՞ս կմիգրացնեիք մեծ Vue 2 հավելվածը Vue 3։
Vue 2-ի աջակցությունն ավարտվեց 2023-ի վերջին, ուստի միգրացիան անվտանգության հարց է։ Նախ կթարմացնեի Vue 2.7-ի, որը backport է անում Composition API-ն և script setup-ը, և նոր կոդը կսկսեի գրել այդպես։ Հետո կփոխարինեի Vue 3-ը չաջակցող գրադարանները. Vuex-ը՝ Pinia-ով, հին router-ը՝ Vue Router 4-ով, իսկ UI kit-երը՝ դրանց Vue 3 տարբերակներով։ Migration build-ը (@vue/compat) կարող է հավելվածը գործարկել Vue 3-ի վրա Vue 2-ի վարքագծով և զգուշացումներով, ուստի deprecation-ները ուղղում եք աստիճանաբար։ Webpack-ից Vite անցումը սովորաբար կատարվում է միաժամանակ։ Լավ end-to-end թեստերն են, որ սա դարձնում են անվտանգ։
Սենիոր մակարդակի հարցեր
S1Ինչպե՞ս կկառուցեիք մեծ Nuxt հավելված, որը կիսում են մի քանի թիմեր։
Կօգտագործեի Nuxt layer-ներ. բազային layer՝ դիզայն համակարգով, ընդհանուր composable-ներով, auth-ով և API client-ով, և feature կամ պրոդուկտային layer-ներ, որոնք ընդլայնում են այն։ Յուրաքանչյուր թիմ տիրապետում է իր layer-ին monorepo-ում, որը կառավարվում է pnpm workspaces-ով և Turborepo-ով կամ Nx-ով, lint կանոններով պարտադրված խիստ սահմաններով, որպեսզի feature-ները չimport անեն միմյանց ներքին մասերը։ Տվյալների հասանելիությունն անցնում է OpenAPI-ից գեներացված տիպավորված API client-ներով, ոչ թե պատահական $fetch կանչերով։ Ընդհանուր state-ը նվազագույն է և ապրում է հստակ սեփականատեր ունեցող Pinia store-երում։ CI-ը յուրաքանչյուր ազդված layer-ի համար գործարկում է vue-tsc, unit թեստեր Vitest-ով և end-to-end թեստեր Playwright-ով։ Սա պահում է մեկ deploy արվող հավելված՝ հստակ սեփականությամբ, ինչը սովորաբար ավելի լավ է, քան անմիջապես micro-frontend-ների անցնելը։
S2Համեմատեք Nuxt-ը և Next.js-ը նոր պրոդուկտի համար։ Ի՞նչը կորոշի ընտրությունը։
Տեխնիկապես դրանք մոտ են. երկուսն էլ առաջարկում են ֆայլային routing, SSR, ստատիկ և հիբրիդ ռենդերինգ, սերվերային route-եր և edge deploy։ Որոշումը հիմնականում մարդկանց և էկոհամակարգի մասին է։ Next.js-ն ունի ավելի մեծ աշխատանքի շուկա, React Server Components՝ նուրբ սերվերային ռենդերինգի համար, և React Native՝ մոբայլի հետ կոդ կիսելու համար։ Nuxt-ն առաջարկում է Vue-ի ավելի պարզ ռեակտիվությունը, ավելի քիչ boilerplate ավտոմատ import-ների և կոնվենցիաների շնորհիվ, Nitro-ի տեղափոխելիությունը hosting-երի միջև՝ առանց vendor-ին հատուկ հնարավորությունների, և ուժեղ մոդուլների էկոհամակարգ։ Եթե թիմը գիտի React կամ պետք է կոդ կիսել մոբայլի հետ, ընտրում եմ Next.js։ Եթե թիմը Vue-ի վրա է, կամ պրոդուկտը բովանդակությամբ և SEO-ով ծանր է՝ փոքր թիմով, որը գնահատում է կոնվենցիաները, Nuxt-ը հիանալի ընտրություն է։ Ֆրեյմվորքը փոխելու համար վերագրելը հազվադեպ է արդարանում։
S3Ինչպե՞ս եք անվտանգ կազմակերպում authentication-ը Nuxt-ում SSR-ով։
Session-ը պահում եմ HttpOnly, Secure, SameSite=Lax cookie-ում, որը սահմանում է սերվերը, երբեք token localStorage-ում, որպեսզի այն հասանելի լինի SSR-ի ժամանակ և չկարդացվի script-երով։ Սերվերային route-երը և server middleware-ը վալիդացնում են session-ը յուրաքանչյուր հարցման ժամանակ. client-ի route middleware-ը միայն բարելավում է UX-ը՝ շուտ redirect անելով, քանի որ այն կարելի է շրջանցել։ SSR-ի ժամանակ ձեր սեփական API-ն կանչելիս փոխանցեք մուտքային cookie-ն՝ օգտագործելով useRequestFetch կամ useRequestHeaders։ Օգտատիրոջ state-ը գնում է useState կամ Pinia, որպեսզի լինի ըստ հարցման։ Անհատականացված էջերը բացառվում են swr և CDN քեշավորումից։ Երրորդ կողմի login-ի համար nuxt-auth-utils-ը կամ provider-ի SDK-ն մշակում են OAuth հոսքերը, իսկ cookie-ով authenticated փոփոխող հարցումների համար CSRF պաշտպանությունը պարտադիր է։
Բառարան
- Single-File Component
- .vue ֆայլ, որը մեկ տեղում միավորում է կոմպոնենտի template-ը, script-ը և ոճերը։
- Composition API
- Vue 3-ի ֆունկցիաների վրա հիմնված եղանակը կոմպոնենտի տրամաբանություն գրելու համար՝ ref-ով, computed-ով, watch-ով և lifecycle hook-երով։
- ref
- Ռեակտիվ կոնտեյներ ցանկացած արժեքի համար. script-ում այն կարդացվում և գրվում է .value-ի միջոցով։
- Composable
- Վերաօգտագործելի ֆունկցիա, որն օգտագործում է Vue-ի ռեակտիվության API-ները և ըստ կոնվենցիայի կոչվում է useSomething։
- Pinia
- Vue-ի պաշտոնական state management գրադարանը՝ type-safe, մոդուլային store-երով և SSR աջակցությամբ։
- Hydration
- Client-ի կողմից ինտերակտիվության կցումը HTML-ին, որը սերվերն արդեն ռենդեր է արել։
- Nitro
- Nuxt-ի սերվերային engine-ը, որը գործարկում է API route-երը և deploy անում Node, serverless կամ edge պլատֆորմների վրա։
- Route rules
- Nuxt կոնֆիգ, որը URL pattern-ները համապատասխանեցնում է ռենդերինգի, քեշավորման, redirect-ի և header-ների վարքագծին։
- Vapor mode
- Vue-ի առաջիկա կոմպիլյացիայի ռեժիմ, որը DOM-ը թարմացնում է ուղղակիորեն՝ առանց virtual DOM-ի։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։