فصل نهم: تست و بهینهسازی
در این فصل، به بررسی تست و بهینهسازی اپلیکیشن مرکز اجاره کشتیهای کروز با استفاده از ابزارهای مدرن Nuxt 3 میپردازیم. تستها برای اطمینان از عملکرد صحیح کد و بهینهسازیها برای بهبود سرعت و تجربه کاربری حیاتی هستند. این فصل شامل پیادهسازی تستهای واحد (Unit Tests) با استفاده از Vitest و @nuxt/test-utils، بهینهسازی عملکرد با تکنیکهایی مانند هیدراتاسیون تنبل (Lazy Hydration)، و تقویت سئو با استفاده از متادیتای پویا است. هر بخش بهطور کامل توضیح داده شده و کدهای مربوطه شرح داده میشوند.
تستهای واحد (Unit Tests)
تستهای واحد برای بررسی صحت عملکرد بخشهای مختلف کد، مانند storeها، کامپوننتها و توابع، استفاده میشوند. در این پروژه، از Vitest (یک فریمورک تست سریع و مدرن) به همراه ماژول @nuxt/test-utils برای تست اپلیکیشن Nuxt استفاده میکنیم.
نصب وابستگیها:
npm install -D vitest @nuxt/test-utils
توضیحات:
-
دستور
npm install -D vitest @nuxt/test-utils: این دستور دو پکیج را نصب میکند: -
vitest: یک فریمورک تست که با Vite (موتور ساخت Nuxt 3) ادغام شده و تستهای سریع و قابل اعتمادی ارائه میدهد.
- @nuxt/test-utils: ابزارهای کمکی برای تست اپلیکیشنهای Nuxt، از جمله شبیهسازی محیط Nuxt و پشتیبانی از تستهای سمت سرور و کلاینت.
-
گامهای بعدی برای تنظیم:
-
فایل تنظیمات Vitest (مانند
vitest.config.ts) را ایجاد کنید:
// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config';
export default defineVitestConfig({
test: {
environment: 'nuxt',
},
});
- اسکریپت تست را به
package.jsonاضافه کنید:
"scripts": {
"test": "vitest"
}
نمونه تست برای useShipsStore:
// tests/shipsStore.test.ts
import { describe, it, expect } from 'vitest';
import { setActivePinia, createPinia } from 'pinia';
import { useShipsStore } from '~/stores/ships';
describe('Ships Store', () => {
setActivePinia(createPinia());
const store = useShipsStore();
it('filters ships by search', () => {
store.ships = [{ id: 1, name: 'Ocean Explorer', pricePerDay: 10000 }];
store.setSearch('Ocean');
expect(store.filteredShips.length).toBe(1);
});
});
توضیحات:
-
وارد کردن وابستگیها:
-
describe,it,expect: توابع اصلی Vitest برای تعریف گروه تستها، تستهای جداگانه و بررسی انتظارات. setActivePinia,createPinia: توابعی از Pinia برای تنظیم محیط تست storeها.-
useShipsStore: store کشتیها که میخواهیم تست کنیم. -
تنظیم محیط تست:
-
setActivePinia(createPinia()): یک نمونه Pinia ایجاد کرده و آن را بهعنوان محیط فعال تنظیم میکند. -
const store = useShipsStore(): نمونهای از store کشتیها برای تست ایجاد میشود. -
تست فیلتر جستجو:
-
تست با نام "filters ships by search" بررسی میکند که آیا store میتواند کشتیها را بر اساس جستجوی نام فیلتر کند.
- مراحل تست:
- یک کشتی نمونه با نام "Ocean Explorer" به آرایه
shipsاضافه میشود. - متد
setSearch('Ocean')فراخوانی میشود تا فیلتر جستجو اعمال شود. - با استفاده از
expect(store.filteredShips.length).toBe(1)بررسی میشود که آرایهfilteredShipsدقیقاً یک کشتی را برگرداند.
- یک کشتی نمونه با نام "Ocean Explorer" به آرایه
-
نتیجه: اگر تست موفق باشد، نشان میدهد که قابلیت فیلتر جستجو در store بهدرستی کار میکند.
-
کاربرد:
-
این تست اطمینان میدهد که منطق فیلتر کردن کشتیها در store بهدرستی عمل میکند.
-
میتوان تستهای بیشتری برای بررسی سایر getters (مانند
getShipById) یا actions (مانندfetchShips) اضافه کرد. -
مزایا:
-
اطمینان از صحت کد: تستهای واحد خطاها را زودتر شناسایی میکنند.
- توسعه پایدار: با افزودن قابلیتهای جدید، تستها تضمین میکنند که تغییرات کد قبلی را خراب نمیکنند.
-
ادغام با Nuxt:
@nuxt/test-utilsتستهای سمت سرور و کلاینت را ساده میکند. -
گسترش تستها:
-
میتوان تستهایی برای کامپوننتها (مانند
ShipCard.vue) یا مسیرهای سرور (/api/ships) با استفاده از@nuxt/test-utilsنوشت. - برای مثال، تست کامپوننت:
import { mount } from '@vue/test-utils';
import ShipCard from '~/components/ShipCard.vue';
it('renders ship name', () => {
const wrapper = mount(ShipCard, {
props: { ship: { id: 1, name: 'Ocean Explorer', capacity: 500, pricePerDay: 10000, amenities: [], image: '' } },
});
expect(wrapper.find('h2').text()).toBe('Ocean Explorer');
});
بهینهسازی عملکرد
بهینهسازی عملکرد برای ارائه تجربه کاربری سریع و روان حیاتی است. در این پروژه، از تکنیک هیدراتاسیون تنبل (Lazy Hydration) برای بهبود سرعت بارگذاری صفحات استفاده میکنیم.
توضیحات:
-
هیدراتاسیون تنبل (Lazy Hydration):
-
هیدراتاسیون فرآیند تبدیل HTML رندرشده سمت سرور به یک اپلیکیشن تعاملی Vue در سمت کلاینت است.
- برای کامپوننتهای سنگین (مانند گریدهای بزرگ یا کامپوننتهایی با منطق پیچیده)، میتوان هیدراتاسیون را به تأخیر انداخت تا فقط زمانی انجام شود که کامپوننت در viewport کاربر قرار گیرد.
- روشهای پیادهسازی:
- استفاده از تگ
<ClientOnly>: این تگ اطمینان میدهد که کامپوننت فقط در سمت کلاینت رندر میشود.
- استفاده از تگ
<ClientOnly>
<HeavyComponent />
</ClientOnly>
- استفاده از `v-if`: میتوان از یک شرط برای بارگذاری تنبل کامپوننت استفاده کرد:
<HeavyComponent v-if="isVisible" />
<script setup>
const isVisible = ref(false);
onMounted(() => {
isVisible.value = true; // یا منطق مبتنی بر IntersectionObserver
});
</script>
-
کاربرد در پروژه:
- در صفحه لیست کشتیها (
pages/ships/index.vue)، میتوان کامپوننتShipCardرا با<ClientOnly>یاv-ifلود کرد تا هیدراتاسیون فقط برای کارتهای قابل مشاهده انجام شود. - این کار باعث کاهش بار اولیه JavaScript و بهبود زمان بارگذاری صفحه میشود.
- در صفحه لیست کشتیها (
-
مزایا:
-
کاهش زمان بارگذاری: با به تأخیر انداختن هیدراتاسیون کامپوننتهای غیرضروری، منابع کمتری در بارگذاری اولیه مصرف میشود.
- تجربه کاربری بهتر: صفحات سریعتر رندر میشوند، بهویژه در دستگاههای با منابع محدود.
-
انعطافپذیری: میتوان هیدراتاسیون تنبل را بهصورت انتخابی برای کامپوننتهای خاص اعمال کرد.
-
یادداشت برای پروژه:
-
در این اپلیکیشن،
ShipCardدر گرید لیست کشتیها میتواند با<ClientOnly>یا یکIntersectionObserverلود شود تا فقط کارتهای داخل viewport هیدراته شوند. - برای مثال:
<ClientOnly>
<ShipCard v-for="ship in filteredShips" :key="ship.id" :ship="ship" />
</ClientOnly>
بهینهسازی سئو (SEO)
بهینهسازی برای موتورهای جستجو (SEO) در اپلیکیشنهای وب مدرن حیاتی است. Nuxt 3 ابزارهای قدرتمندی مانند useSeoMeta و useHead برای مدیریت متادیتای پویا ارائه میدهد، که در صفحات این پروژه (مانند صفحه اصلی، لیست کشتیها، و جزئیات کشتی) پیادهسازی شدهاند.
توضیحات:
-
استفاده از
useSeoMetaوuseHead: -
این توابع در صفحات پروژه برای تنظیم عنوان (title)، توضیحات (description)، و متادیتای Open Graph استفاده شدهاند. برای مثال:
- در
pages/index.vue:
- در
useSeoMeta({
title: 'Cruise Ship Rental Center | Luxury Cruises 2025',
description: 'Rent premium cruise ships for your next adventure. Explore our fleet and book today!',
ogImage: '/og-image.jpg',
});
- در `pages/ships/[id].vue`:
useSeoMeta({
title: () => ship.value ? `${ship.value.name} | Cruise Rental 2025` : 'Ship Details',
description: () => ship.value ? `Book ${ship.value.name} for your next adventure!` : 'View cruise ship details.',
});
- کاربرد:
useSeoMeta: متادیتای استاندارد مانندtitleوdescriptionرا تنظیم میکند که برای رتبهبندی در موتورهای جستجو مهم هستند.useHead: امکان تنظیم متادیتای پیشرفتهتر (مانند متا تگهای سفارشی یا اسکریپتها) را فراهم میکند.- متادیتای پویا (مانند استفاده از نام کشتی در عنوان) باعث میشود هر صفحه محتوای منحصربهفردی برای سئو داشته باشد.
-
مزایا:
- بهبود رتبهبندی: متادیتای دقیق و پویا شانس نمایش در نتایج جستجو را افزایش میدهد.
- شبکههای اجتماعی: متادیتای Open Graph (مانند
ogImage) باعث نمایش بهتر صفحات در پلتفرمهایی مانند فیسبوک یا توییتر میشود. - ادغام با SSR: متادیتا در سمت سرور رندر میشود، که برای خزندههای موتور جستجو ایدهآل است.
-
یادداشت برای پروژه:
-
متادیتا در تمام صفحات اصلی پروژه (صفحه اصلی، لیست کشتیها، جزئیات کشتی، و داشبورد رزروها) پیادهسازی شده است.
- برای بهبود بیشتر، میتوان متا تگهای اضافی مانند
keywordsیا ساختارهای Schema.org (مانند JSON-LD) اضافه کرد:
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: ship.value?.name,
description: ship.value?.description,
}),
},
],
});
جمعبندی فصل نهم
در این فصل، به جنبههای کلیدی تست و بهینهسازی اپلیکیشن مرکز اجاره کشتیهای کروز پرداختیم:
- تستهای واحد: با استفاده از Vitest و
@nuxt/test-utils، یک تست نمونه برای store کشتیها پیادهسازی کردیم که قابلیت فیلتر جستجو را بررسی میکند. - بهینهسازی عملکرد: با استفاده از هیدراتاسیون تنبل (
<ClientOnly>یاv-if)، بار اولیه JavaScript را کاهش دادیم. - بهینهسازی سئو: با استفاده از
useSeoMetaوuseHead، متادیتای پویا را برای بهبود رتبهبندی در موتورهای جستجو پیادهسازی کردیم.
این تکنیکها اپلیکیشن را پایدارتر، سریعتر و قابل کشفتر میکنند. در فصلهای بعدی، به استقرار و گسترش اپلیکیشن خواهیم پرداخت.