برنامه نویسی

ارائه کامپوننت های Svelte به عنوان اجزای وب در Angular: راهنمای گام به گام

Svelte در حال رشد است و همانطور که در نظرسنجی قبلی State of JS نشان داده شده است، در سال های گذشته به سرعت مورد توجه قرار گرفته است:

حالت فوکوس Svelte JS 2022

با آموزش جامع آن، ممکن است وسوسه شوید که آن را یک قدم فراتر بردارید و از Svelte در برنامه واقعی استفاده کنید.

با این حال، انتقال یک برنامه کامل به سبک Big Bang ممکن است راه آسانی برای فرو رفتن در آن نباشد. یک راه حل ممکن است ایجاد مؤلفه Svelte جداگانه و مصرف آنها به عنوان مؤلفه های وب باشد.

وقتی برای اولین بار این آموزش را خواندم، روی این جمله متوقف شدم:

می توانید کل برنامه خود را با Svelte بسازید، یا می توانید آن را به صورت تدریجی به یک پایگاه کد موجود اضافه کنید. شما همچنین می توانید قطعات را به عنوان بسته های مستقل ارسال کنید که در هر جایی کار می کنند، بدون سربار وابستگی به یک چارچوب معمولی.

به‌عنوان یک توسعه‌دهنده آشنا با Angular، می‌خواستم روند ایجاد کامپوننت‌های Svelte، کامپایل کردن آنها در جاوا اسکریپت خام و ترکیب آن‌ها به عنوان عناصر بومی در یک برنامه Angular موجود را ببینم تا این فرآیند را طی کند.

در این مقاله، نحوه ادغام اجزای Svelte را در یک برنامه Angular موجود به عنوان کامپوننت های وب بررسی خواهیم کرد.

✋ توجه – Svelte 4 به تازگی منتشر شده است، اما این راهنما از Svelte 3 استفاده می کند: بسته های مورد استفاده در اینجا همچنان از Svelte 3 استفاده می کنند، بنابراین مهاجرت اکنون کمی زودرس خواهد بود.
اگر مایلید در مورد Svelte 4 اطلاعات بیشتری کسب کنید، من فقط در مورد آن وبلاگ نوشتم:

فهرست مطالب


کامپوننت های وب چیست؟

قبل از اینکه ابتدا به قابلیت همکاری Svelte و Angular بپردازیم، ابتدا ببینیم چسبی که آنها را به هم وصل می کند چیست: اجزای وب.

همانطور که توسط وب اسناد MDN بیان شده است:

Web Components مجموعه‌ای از فن‌آوری‌های مختلف است که به شما امکان می‌دهد عناصر سفارشی قابل استفاده مجدد را ایجاد کنید – با عملکرد آنها دور از بقیه کد شما – و از آنها در برنامه‌های وب خود استفاده کنید.

هسته اصلی این فناوری، ایده صادرات یک قطعه HTML با منطق آن، و امکان استفاده از آن در جای دیگری بدون ترس از هرگونه تداخل با کد موجود است.

اجزای وب در هسته خود سه فناوری دارند:

  • 🧪 عناصر سفارشی که توانایی ایجاد عناصر HTML خودمان با رفتار، سبک و/یا الگوهای خاص خود است
  • 🌑 سایه DOM که به عنوان یک DOM محلی برای کامپوننت عمل می کند و به آن امکان می دهد تمام عناصر خود را به صورت مجزا با DOM جهانی تعریف کند.
  • 🧩 قالب های HTML که راهی برای تعریف و استفاده مجدد از تکه های HTML با قرار دادن آنها در DOM فراهم می کند

در زمینه ما، به این معنی است که ما می خواهیم یک کامپوننت Svelte (با قالب، سبک و منطق آن) را صادر کنیم و آن را در برنامه Angular خود رها کنیم.

عالی! اکنون کمی واضح تر می بینیم که این به کجا می رود. پس بیایید به سراغ کد برویم!

پروژه Svelte ما

قبل از صادرات هر جزء Svelte، ابتدا باید کتابخانه کامپوننت را ایجاد کنیم.

برای انجام این کار، با استفاده از SvelteKit یک پروژه کتابخانه جدید را داربست خواهیم داشت.

راه اندازی یک پروژه جدید

از آنجایی که Svelte “فقط” یک کامپایلر است، ما یک پروژه جاوا اسکریپت خام ایجاد خواهیم کرد.

در یک جدید svelte-web-components پوشه، ایجاد یک package.json فایل حاوی پیکربندی زیر:

{
  "name": "svelte-web-components",
  "version": "1.0.0",
  "scripts": { },
  "devDependencies": {
    "svelte": "^3.59.1"
  },
  "type": "module"
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما برای رفتن آماده ایم!

ایجاد یک کامپوننت سفارشی Svelte

برای مثال، شمارنده‌ای را صادر می‌کنیم که با توجه به مقدار اولیه، می‌توان آن را افزایش، کاهش یا تنظیم مجدد کرد.

کد کامپوننت را به صورت جدید تعریف کنید components/Counter.svelte فایل:

<!-- components/Counter.svelte -->
<script>
  export let initialValue = 0;

  let count = initialValue;
  $: isInitialValue = count === initialValue;

  const increment = () => (count += 1);
  const decrement = () => (count -= 1);
  const reset = () => (count = initialValue);
</script>

<div>
  <span>{count}</span>

  <button type="button" on:click={decrement}>-</button>
  <button type="button" on:click={increment}>+</button>
  <button type="button" on:click={reset} disabled={isInitialValue}>Reset</button>
</div>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر می خواهید آن را امتحان کنید، Svelte یک REPL آنلاین دارد

شما باید چیزی مشابه ببینید:

شمارنده بدون استایل

از آنجایی که ما در حال ساخت یک کتابخانه هستیم، فراموش نکنیم که آن را در API عمومی خود نمایش دهیم:

// components/index.js
export { default as Counter } from './Counter.svelte';
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به منظور استفاده از قابلیت های Svelte، ما از یک فروشگاه برای مدیریت ارزش پیشخوان خود استفاده خواهیم کرد.

این در اینجا مطلقاً ضروری نیست، اما به ما این امکان را می‌دهد که ببینیم آیا می‌توانیم از چنین ویژگی‌هایی در زمانی که جزء ما صادر می‌شود استفاده کنیم یا خیر.

نسخه به روز شده فقط کمی متفاوت است:

<!-- components/Counter.svelte -->
<script>
  import { writable } from 'svelte/store';

  export let initialValue = 0;

  let count = writable(initialValue);
  $: isInitialValue = $count === initialValue;

  const increment = () => count.update((n) => (n += 1));
  const decrement = () => count.update((n) => (n -= 1));
  const reset = () => count.set(initialValue);
</script>

<div>
  <span>{$count}</span>

  <button type="button" on:click={decrement}>-</button>
  <button type="button" on:click={increment}>+</button>
  <button type="button" on:click={reset} disabled={isInitialValue}>Reset</button>
</div>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از آنجایی که از کامپوننت خود در جای دیگری استفاده خواهیم کرد، بیایید کمی آن را نیز سبک کنیم تا استفاده از آن لذت بخش تر باشد.

✨ CSS اضافی
<!-- components/Counter.svelte -->
<style>
  div {
    display: flex;
    align-items: center;
    gap: 5px;
    border: 1px solid #999;
    width: fit-content;
    padding: 5px;
    border-radius: 5px;
  }

  div span {
    font-size: 18px;
    font-weight: bold;
    margin: 0 10px;
  }

  div button {
    padding: 5px 10px;
    border: 1px solid #ccc;
    background-color: #f0f0f0;
    color: #333;
    font-size: 16px;
    transition: background-color 0.3s ease;
    border-radius: 5px;
  }

  div button:hover {
    background-color: #e0e0e0;
  }

  div button:active {
    background-color: #ccc;
  }

  div button:disabled {
    opacity: 40%;
  }
</style>

مؤلفه ما هنوز با استفاده از فروشگاه خود به خوبی کار می کند:

پیشخوان مدل دار

در واقع، آنقدر خوب کار می کند که ممکن است بخواهم از آن خارج از این کتابخانه استفاده کنم، بیایید این اتفاق بیفتد!

تبدیل کامپوننت Svelte به یک کامپوننت وب

همانطور که قبلا دیدیم، راهی برای اجرای کامپوننت ما در خارج از این محیط، تبدیل آن به یک کامپوننت وب است.

بیایید چک لیست را مرور کنیم و ببینیم که قبلاً چه چیزی را بررسی کرده ایم:

  • 🧪 عناصر سفارشی
  • ✅ 🌑 Shadow DOM
  • ✅ 🧩 قالب های HTML

ما تقریبا اینجا هستیم!

برای استفاده از عنصر HTML سفارشی خود، باید یکی را برای کامپوننت خود تعریف کنیم.

برای این کار می توانیم از ویژه استفاده کنیم <svelte:options> عنصری برای تعیین اینکه از کدام برچسب استفاده شود:

<!-- components/Counter.svelte -->
<svelte:options tag="svelte-counter" />

<!-- Counter component code here -->
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما اکنون خود را داریم Counter مؤلفه ای که هر سه الزامات یک مؤلفه وب را برآورده می کند.

کامپایل کامپوننت Svelte به جاوا اسکریپت خالص

در حالی که جزء ما آماده صادرات است، اکنون می‌توانیم این کار را با کامپایل کردن آن در جاوا اسکریپت خالص انجام دهیم.

برای این کار، از esbuild به باندل یا کامپوننت استفاده می کنیم. ما باید دو وابستگی دیگر را بگیریم: esbuild و esbuild-svelte:

npm i -D esbuild esbuild-svelte
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس می توانیم یک اسکریپت اضافه کنیم که نقطه ورودی کتابخانه ما را بخواند و نتیجه JS را خروجی کند:

// esbuild-bundle.js
import esbuild from "esbuild";
import sveltePlugin from "esbuild-svelte";

esbuild
  .build({
    entryPoints: ["./components"],
    bundle: true,
    outfile: "dist/web-components.js",
    plugins: [
      sveltePlugin(),
    ],
    logLevel: "info",
  })
  .catch(() => process.exit(1));
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این حال، ما باید به eslint بگوییم که ما در حال ساخت اجزای وب هستیم، نه اینکه برنامه خود را صرفاً بسته بندی کنیم:

esbuild
  .build({
    entryPoints: ["./components"],
    bundle: true,
    outfile: "dist/web-components.js",
    plugins: [
      sveltePlugin({
+       compilerOptions: {
+         customElement: true,
+       },
      }),
    ],
    logLevel: "info",
  })
  .catch(() => process.exit(1));
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت، برای اینکه اجرای آن کمی آسان‌تر شود، می‌توانیم یک ورودی به آن اضافه کنیم scripts از ما package.json:

{
  "name": "svelte-web-components",
  "version": "1.0.0",
  "scripts": {
+   "build": "node esbuild-bundle.js"
  },
  "devDependencies": {
    "esbuild": "^0.18.2",
    "esbuild-svelte": "^0.7.3",
    "svelte": "^3.59.1"
  },
  "type": "module"
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانیم اجرا کنیم npm run build و خروجی را ببینید:

خروجی ESBuild

ما باید خروجی کتابخانه خود را در زیر داشته باشیم dist/web-components.js حاوی کامپوننت وب ما 📦

ادغام Svelte Web Components در Angular

با آماده بودن بسته ما، فقط مصرف آن باقی می ماند.

راه اندازی یک Angular Application

برای بوت استرپ اپلیکیشن Angular دستور زیر را اجرا کنید:

ng new angular-wrapper --standalone --defaults
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و تولید شده را جایگزین کنید app.component.ts با کد زیر:

import { Component } from "@angular/core";

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h1>Svelte in Angular!</h1>
  `,
})
export class AppComponent {}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون که برنامه Angular ما آماده است و کامپوننت وب Svelte ما نیز آماده است، بیایید این را سیم کشی کنیم!

مصرف کامپوننت های وب Svelte در Angular

برای اینکه Angular از بسته JS خارجی خود آگاه شود، باید آن را به عنوان وابستگی پروژه خود اضافه کنیم.

برای آن، از قبل تولید شده را بگیرید web-components.js فایل و آن را در یک پوشه جدید در ریشه پروژه Angular خود، در زیر رها کنید src/scripts:

ساختار پوشه زاویه ای

و ارجاع به آن در angular.json فایل در scripts آرایه واقع در angular.json > projects > angular-wrapper > architect > build > options > scripts:

"styles": [
  "src/styles.css"
],
"scripts": [
+ "src/scripts/web-components.js"
]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Angular با همراه کردن کامپوننت وب خود در کنار برنامه خود، اکنون می توانیم از شمارنده خود استفاده کنیم!

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h1>Svelte in Angular!</h1>
+   <svelte-counter />
  `,
})
export class AppComponent {}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

… یا می توانیم؟

خطای طرحواره عناصر سفارشی زاویه ای

در تلاشی برای جلوگیری از انجام اشتباهات، Angular عناصر HTML مورد استفاده ما را اسکن می کند و می بیند که آیا آنها یک عنصر HTML بومی هستند یا یک جزء Angular قابل حل.

با این حال، در مورد ما، این هیچ کدام نیست.

امیدواریم که Angular راه حلی برای موارد استفاده ما ارائه دهد:

اگر «svelte-counter» یک مؤلفه وب است، «CUSTOM_ELEMENTS_SCHEMA» را به «Component.schemas@» این مؤلفه اضافه کنید تا این پیام سرکوب شود.

+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";

@Component({
  selector: "app-root",
  standalone: true,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <h1>Svelte in Angular!</h1>
    <svelte-counter />
  `,
})
export class AppComponent {}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانید Svelte Web Component را در حال اجرا در برنامه Angular ما مشاهده کنید!

شمارنده Svelte در Angular

غذای آماده

در این مقاله دیدیم که Web Components چیست، چگونه یک کامپوننت Svelte را به یک Web Component تبدیل کنیم و چگونه آن را از یک برنامه Angular مصرف کنیم.

این فرآیند به لطف بسته‌های جامعه و ماهیت خود Svelte بسیار ساده است: کامپایلر بودن، ایجاد تکه‌هایی از JS که می‌توانند در هر جایی اجرا شوند، در ماهیت خودش است.

اگر می خواهید کد به دست آمده را بررسی کنید، می توانید به مخزن GitHub مرتبط بروید


امیدوارم در آنجا چیز مفیدی یاد بگیرید!

تصویر pbouillon

عکس از Didssph در Unsplash

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا