404 Not Found

404 Not Found


nginx

تطوير الوحدات

اكتشف Charlie أن منطق التتبع والإبلاغ عن الأخطاء ومراقبة الأداء في MegaShop مبعثر في أماكن مختلفة. مشروعات Alice وBob الأخرى تحتاج أيضًا إلى نفس القدرات. بتغليف هذه الميزات الشائعة في وحدات Nuxt، يمكن تطويرها مرة واحدة وإعادة استخدامها في كل مكان، وحتى نشرها على npm لاستخدامها من قبل المجتمع.

1. ما ستتعلمه


2. قصة حقيقية لمهندس معماري

(1) نقطة الألم: تطوير مكرر للميزات العامة

يحتاج MegaShop الخاص بـ Charlie إلى تتبع—كل مشاهدة صفحة، وكل عنصر مضاف إلى السلة، وكل نقرة يجب تسجيلها. يستدعي API يدويًا في خمسة مكونات. مشروع Alice الآخر يحتاج أيضًا إلى تتبع، لذا أعاد Bob كتابة الكود من الصفر. الكود مكرر وغير متسق.

(2) حل وحدات Nuxt

بمجرد تغليفها كوحدة، تصبح جاهزة للاستخدام فورًا—مع حقن تلقائي لـ Composable وواجهة API للخادم:

TYPESCRIPT
// nuxt.config.ts
modules: ['@megashop/analytics']

(3) الفوائد: طوّر مرة واحدة، أعد الاستخدام في كل مكان

جميع المشروعات تحصل على قدرات التتبع بمجرد تثبيت الوحدة. مع Alice، يمكنك تفعيل التتبع في أي مشروع باستدعاء useAnalytics()—بدون أي تكوين.


3. بنية الوحدات

(1) دورة حياة وحدة Nuxt

100%
graph TB
    A[defineNuxtModule] --> B[دالة Setup]
    B --> C[installModule - التبعيات]
    B --> D[addPlugin - تسجيل الإضافات]
    B --> E[addComposable - حقن Composables]
    B --> F[addServerHandler - مسارات API]
    B --> G[addLayout - تخطيطات مخصصة]
    B --> H[addComponent - مكونات تلقائية]
    B --> I[extendConfig - تعديل التكوين]
    
    J[خطافات Nuxt] --> K[modules:before]
    J --> L[modules:done]
    J --> M[build:before]
    J --> N[build:done]

(1) ▶ مثال: هيكل وحدة بسيط

TYPESCRIPT
// src/module.ts
import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    name: '@megashop/analytics',
    configKey: 'analytics',
    compatibility: {
      nuxt: '^3.0.0'
    }
  },

  defaults: {
    enabled: true,
    endpoint: '/api/analytics',
    debug: false
  },

  setup(options, nuxt) {
    const { resolve } = createResolver(import.meta.url)

    // تسجيل إضافة
    addPlugin(resolve('./runtime/plugin'))

    // كشف الخيارات لوقت التشغيل
    nuxt.options.runtimeConfig.public.analytics = {
      enabled: options.enabled,
      endpoint: options.endpoint,
      debug: options.debug
    }
  }
})

الناتج:

TEXT
// التنفيذ ناجح

(2) مرجع سريع لقدرات الوحدات

القدرة API الوصف
تسجيل إضافة addPlugin() تنفيذ منطق التهيئة تلقائيًا
حقن مكون addComponent() استيراد مكونات Vue تلقائيًا
حقن Composable addImports() استيراد الدوال تلقائيًا
إضافة مسار API addServerHandler() تسجيل مسارات الخادم تلقائيًا
إضافة تخطيط addLayout() تسجيل تخطيط مخصص
إضافة وسيط addRouteMiddleware() تسجيل وسيط المسار
تعديل التكوين extendConfig() تعديل تكوين Nuxt
تثبيت وحدة تبعية installModule() تثبيت وحدات أخرى

4. وحدة عملية: @megashop/analytics

(1) ▶ مثال: نقطة دخول الوحدة

TYPESCRIPT
// src/module.ts
import { defineNuxtModule, addPlugin, addImports, addServerHandler, createResolver } from '@nuxt/kit'

export interface ModuleOptions {
  enabled: boolean
  endpoint: string
  debug: boolean
  trackPageViews: boolean
  trackClicks: boolean
}

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name: '@megashop/analytics',
    configKey: 'analytics',
    compatibility: { nuxt: '^3.0.0' }
  },

  defaults: {
    enabled: true,
    endpoint: '/api/analytics',
    debug: false,
    trackPageViews: true,
    trackClicks: true
  },

  setup(options, nuxt) {
    const { resolve } = createResolver(import.meta.url)

    // 1. تسجيل إضافة العميل للتتبع التلقائي
    if (options.trackPageViews || options.trackClicks) {
      addPlugin(resolve('./runtime/plugin.client'))
    }

    // 2. استيراد تلقائي لـ useAnalytics composable
    addImports({
      name: 'useAnalytics',
      from: resolve('./runtime/composables/useAnalytics')
    })

    // 3. إضافة واجهة API للخادم لاستقبال الأحداث
    addServerHandler({
      method: 'post',
      route: options.endpoint,
      handler: resolve('./runtime/server/api/analytics')
    })

    // 4. كشف التكوين لوقت التشغيل
    nuxt.options.runtimeConfig.public.analytics = {
      enabled: options.enabled,
      endpoint: options.endpoint,
      debug: options.debug
    }
  }
})

الناتج:

TEXT
// التنفيذ ناجح

(2) ▶ مثال: إضافة وقت التشغيل

TYPESCRIPT
// src/runtime/plugin.client.ts
import { defineNuxtPlugin } from '#app'

export default defineNuxtPlugin((nuxtApp) => {
  const config = useRuntimeConfig().public.analytics
  if (!config.enabled) return

  // تتبع تلقائي لمشاهدات الصفحات
  if (config.trackPageViews) {
    nuxtApp.hook('page:finish', () => {
      useAnalytics().trackPageView(window.location.pathname)
    })
  }

  // تتبع تلقائي للنقرات على عناصر data-track
  if (config.trackClicks) {
    document.addEventListener('click', (e) => {
      const target = (e.target as HTMLElement).closest('[data-track]')
      if (target) {
        const event = target.getAttribute('data-track') || 'click'
        useAnalytics().track(event, { element: target.tagName })
      }
    })
  }
})

الناتج:

TEXT
// التنفيذ ناجح

(3) ▶ مثال: Composable وقت التشغيل

TYPESCRIPT
// src/runtime/composables/useAnalytics.ts
export function useAnalytics() {
  const config = useRuntimeConfig().public.analytics

  async function track(event: string, data?: Record<string, any>) {
    if (!config.enabled) return
    if (config.debug) console.log('[Analytics]', event, data)

    await $fetch(config.endpoint, {
      method: 'POST',
      body: { event, data, timestamp: Date.now(), url: import.meta.client ? window.location.href : '' }
    })
  }

  function trackPageView(path: string) {
    track('page_view', { path })
  }

  function trackAddToCart(productId: number, productName: string, price: number) {
    track('add_to_cart', { productId, productName, price, currency: 'USD' })
  }

  function trackPurchase(orderId: string, total: number) {
    track('purchase', { orderId, total, currency: 'USD' })
  }

  return { track, trackPageView, trackAddToCart, trackPurchase }
}

الناتج:

TEXT
// التنفيذ ناجح

(4) ▶ مثال: واجهة API للخادم وقت التشغيل

TYPESCRIPT
// src/runtime/server/api/analytics.ts
import { defineEventHandler, readBody, setHeader } from 'h3'

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  // التحقق من الحقول المطلوبة
  if (!body.event) {
    throw createError({ statusCode: 400, message: 'Event name required' })
  }

  // تخزين الحدث (في الإنتاج: إرسال إلى خدمة التحليلات)
  const storage = useStorage('analytics')
  const key = `event:${Date.now()}:${Math.random().toString(36).slice(2)}`
  await storage.setItem(key, {
    event: body.event,
    data: body.data || {},
    timestamp: body.timestamp || Date.now(),
    url: body.url,
    userAgent: getHeader(event, 'user-agent')
  })

  setHeader(event, 'cache-control', 'no-store')
  return { success: true }
})

الناتج:

TEXT
// التنفيذ ناجح

5. نشر الوحدات

(1) ▶ مثال: تكوين package.json

JSON
{
  "name": "@megashop/analytics",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/module.mjs",
  "types": "./dist/types.d.ts",
  "exports": {
    ".": {
      "import": "./dist/module.mjs",
      "require": "./dist/module.cjs",
      "types": "./dist/types.d.ts"
    },
    "./runtime/*": "./dist/runtime/*"
  },
  "files": ["dist"],
  "scripts": {
    "build": "nuxt-module-build",
    "dev": "nuxt-module-build --stub",
    "test": "vitest run",
    "prepublishOnly": "npm run build"
  },
  "peerDependencies": {
    "nuxt": "^3.0.0"
  },
  "devDependencies": {
    "@nuxt/module-builder": "^0.6.0",
    "@nuxt/test-utils": "^3.0.0",
    "nuxt": "^3.12.0"
  }
}

الناتج:

JSON
{
  "name": "@megashop/analytics",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/module.mjs",
  "types": "./dist/types.d.ts",
  "exports": {
    ".": {
      "import": "./dist/module.mjs",
      "require": "./dist/module.cjs",
      "types": "./dist/types.d.ts"
    },
    "./runtime/*": "./dist/runtime/*"
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "nuxt-module-build",
    "dev": "nuxt-module-build --stub",
    "test": "vitest run",
    "prepublishOnly": "npm run 

(2) ▶ مثال: الاستخدام في مشروع

TYPESCRIPT
// nuxt.config.ts لـ MegaShop
export default defineNuxtConfig({
  modules: [
    // وحدة محلية أثناء التطوير
    '~/modules/analytics',
    // وحدة منشورة في الإنتاج
    // '@megashop/analytics'
  ],

  analytics: {
    enabled: true,
    endpoint: '/api/analytics',
    debug: process.env.NODE_ENV === 'development',
    trackPageViews: true,
    trackClicks: true
  }
})

الناتج:

TEXT
// التنفيذ ناجح

6. اختبار الوحدات

(1) ▶ مثال: Fixture اختبار الوحدة

TYPESCRIPT
// test/module.test.ts
import { setupTest } from '@nuxt/test-utils'

describe('@megashop/analytics module', () => {
  setupTest({
    fixture: './test/fixtures/basic',
    build: true
  })

  test('يسجل إضافة التحليلات', () => {
    // الإضافة تسجل تلقائيًا، تحقق من إضافات Nuxt
    const nuxt = useNuxt()
    const hasPlugin = nuxt.options.plugins.some(p => p.src?.includes('analytics'))
    expect(hasPlugin).toBe(true)
  })

  test('يكشف عن useAnalytics composable', async () => {
    // الاستيراد التلقائي متاح
    const { data } = await useFetch('/api/analytics', {
      method: 'POST',
      body: { event: 'test', data: {} }
    })
    expect(data.value).toBeDefined()
  })

  test('نقطة نهاية التحليلات تقبل الأحداث', async () => {
    const response = await $fetch('/api/analytics', {
      method: 'POST',
      body: { event: 'page_view', data: { path: '/' } }
    })
    expect(response.success).toBe(true)
  })
})

الناتج:

TEXT
// التنفيذ ناجح

7. مثال شامل: استخدام @megashop/analytics

VUE
<!-- pages/products/[id].vue - استخدام وحدة التحليلات -->
<template>
  <div v-if="product">
    <h1>{{ product.name }}</h1>
    <button
      @click="handleAddToCart"
      data-track="add_to_cart"
    >
      أضف إلى السلة
    </button>
  </div>
</template>

<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// useAnalytics مستورد تلقائيًا بواسطة الوحدة
const { trackAddToCart, trackPageView } = useAnalytics()

// تتبع يدوي
onMounted(() => {
  trackPageView(`/products/${route.params.id}`)
})

async function handleAddToCart() {
  if (!product.value) return
  trackAddToCart(product.value.id, product.value.name, product.value.price)
  // ... منطق الإضافة إلى السلة
}
</script>

❓ أسئلة شائعة

س ما الفرق بين الوحدات والإضافات؟
ج الوحدات تُنفذ خلال مرحلة البناء (مرحلة التكوين) ويمكنها حقن إضافات ومكونات وComposables ومسارات. الإضافات تُنفذ في وقت التشغيل (عند بدء التطبيق) وتتعامل مع منطق التهيئة. الوحدات يمكن أن تحتوي على إضافات.
س ما هو دليل runtime في الوحدة؟
ج runtime يحتوي على كود وقت التشغيل—كود يُنفذ فقط عند تشغيل التطبيق ولا يُضمّن في تكوين البناء. الإضافات وComposables ومعالجات الخادم توضع جميعها تحت runtime/ ولا تُعالج بواسطة Nuxt Kit.
س كيف أطور وأ debugging وحدات محلية؟
ج أنشئ وحدة في دليل modules/ الخاص بالمشروع وأشر إليها في nuxt.config.ts كـ ~/modules/xxx. أثناء التطوير، استخدم nuxt-module-build --stub لتوليد روابط رمزية؛ تغييرات الكود ستدخل حيز التنفيذ في الوقت الفعلي.
س هل يمكن لوحدة أن تعتمد على وحدات أخرى؟
ج نعم. استخدم installModule('@pinia/nuxt') في setup لتثبيت الوحدات التابعة. ستزيل Nuxt التكرارات تلقائيًا.
س ماذا أحتاج لنشر على npm؟
ج كوّن exports وtypes في package.json، ابنِ باستخدام @nuxt/module-builder، وشغّل npm publish. نوصي باستخدام GitHub Actions للنشر المؤتمت.
س كيف أصدّر أنواع TypeScript لوحدة؟
ج @nuxt/module-builder يولّد إعلانات الأنواع تلقائيًا. عيّن exports.types في package.json ليشير إلى dist/types.d.ts، وسيحصل المستخدمون تلقائيًا على تلميحات الأنواع بعد التثبيت.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (الصعوبة: ⭐): إنشاء هيكل وحدة بسيط، تسجيل إضافة، وطباعة "تم تحميل الوحدة"
  2. تمرين متقدم (الصعوبة: ⭐⭐): تطوير وحدة @megashop/analytics لتنفيذ useAnalytics Composable وواجهة API للخادم
  3. تحدي (الصعوبة: ⭐⭐⭐): إضافة تتبع تلقائي لمشاهدات الصفحات وتتبع نقرات data-track، ثم كتابة اختبارات وحدة للتحقق من الوظائف

---|

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%