۳۰ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

توسعه وب تمام پشته با HTMX و Bun، قسمت ۲: قالب پاگ

پشته وب HTMX و Bun را با افزودن Pug، یک موتور قالب محبوب جاوا اسکریپت که تعاملات DOM را سریع می کند، کامل کنید.

پشته وب HTMX و Bun را با افزودن Pug، یک موتور قالب محبوب جاوا اسکریپت که تعاملات DOM را سریع می کند، کامل کنید.

در نیمه اول این مقاله، یک پشته توسعه وب راه‌اندازی کردیم و یک نمونه برنامه کاربردی ساده با استفاده از Bun، HTMX، Elysia و MongoDB ایجاد کردیم. در اینجا، همزمان با پاکسازی و انتزاع لایه دسترسی به داده برنامه نمونه و افزودن تعاملات پیچیده‌تر HTMX، به کاوش پشته جدید خود ادامه می‌دهیم. ما همچنین مؤلفه دیگری را به پشته فناوری اضافه خواهیم کرد: Pug، یک موتور قالب محبوب جاوا اسکریپت که به خوبی با HTMX کار می کند و به پیکربندی تعاملات DOM کمک می کند.

نمونه برنامه

برنامه مثال ما در حال حاضر از یک فرم و یک جدول تشکیل شده است. این فرم به کاربران امکان می دهد نقل قول ها را به همراه نویسندگان خود وارد کنند، که سپس می توانند با استفاده از رابط کاربری برنامه جستجو و نمایش داده شوند. من کمی CSS به رابط اضافه کرده ام تا مدرن تر از آنچه در قسمت ۱ کنار گذاشته ایم به نظر برسد:

واسط HTMX جدید با CSS

کد جلویی رابط به روز شده در اینجا آمده است:


<script src="https://unpkg.com/htmx.org@1.9.10"></script>
  <form hx-post="/add-quote" hx-swap-oop="beforeend:#data-list" hx-trigger="every time">
    <input type="text" name="quote" placeholder="Enter quote">
    <input type="text" name="author" placeholder="Enter author">
    <button type="submit">Add Quote</button>
</form>
  <ul id="data-list"></ul>
  <button hx-get="/quotes" hx-target="#data-list">Load Data</button>

ما از HTMX برای هدایت فرآیند ارسال فرم و بارگیری داده ها در جدول استفاده می کنیم. من همچنین قسمت پشتی برنامه را پاکسازی کرده ام بنابراین اتصال پایگاه داده اکنون به اشتراک گذاشته شده است. این قسمت از src/index.ts است:


import { Elysia } from "elysia";
import { staticPlugin } from '@elysiajs/static';
const { MongoClient } = require('mongodb');

// Database connection details
const url = "mongodb://127.0.0.1:27017/quote?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.8.0";
const dbName = "quote";
const collectionName = "quotes";
let client = new MongoClient(url, { useUnifiedTopology: true });

// Connect to the database (called only once)
async function connectToDatabase() {
  try {
    await client.connect();
  } catch (error) {
    console.error(error);
    throw error; // Re-throw the error to indicate connection failure
  }
  return { client, collection:  client.db(dbName).collection(collectionName) };
}

// Close the database connection
async function closeDatabaseConnection(client) {
  await client.close();
}

کاری که ما در اینجا انجام می دهیم این است که URL پایگاه داده را به عنوان آدرس محلی میزبانی پیش فرض MongoDB به همراه یک پایگاه داده و نام مجموعه تعریف می کنیم. سپس، از یک تابع async، connectToDatabase() برای اتصال کلاینت و برگرداندن آن متصل به مجموعه استفاده می کنیم. کد ما می‌تواند هر زمان که نیاز به دسترسی به پایگاه داده داشته باشد، این متد را فراخوانی می‌کند و پس از پایان کار می‌تواند client.close() را فراخوانی کند.

سرعت جستجو را با استفاده از SearchValues ​​در NET افزایش دهید

استفاده از اتصال پایگاه داده

بیایید ببینیم که نقاط پایانی سرور ما چگونه از این پشتیبانی پایگاه داده استفاده می کنند. برای اختصار، من فقط نقطه پایانی /quotes را نشان می دهم که جدول را هدایت می کند:


// Close the database connection
async function closeDatabaseConnection(client) {
  await client.close();
}

async function getAllQuotes(collection) {
  try {
    const quotes = await collection.find().toArray();

    // Build the HTML table structure
    let html = '<table border="1">';
    html += '<tr><th>Quote</th><th>Author</th></tr>';
    for (const quote of quotes) {
      html += `<tr><td>${quote.quote}</td><td>${quote.author}</td></tr>`;
    }
    html += '</table>';

    return html;
  } catch (error) {
    console.error("Error fetching quotes", error);
    throw error; // Re-throw the error for proper handling
  }
}

// Main application logic
const app = new Elysia()
  .get("/", () => "Hello Elysia")
  .get("/quotes", async () => {
    try {
      const { client, collection } = await connectToDatabase();
      const quotes = await getAllQuotes(collection);
      await closeDatabaseConnection(client);
      return quotes;
    } catch (error) {
      console.error(error);
      return "Error fetching quotes";
    }
  })
  .use(staticPlugin())
  .listen(3000);

console.log(
  ` Elysia is running at ${app.server?.hostname}:${app.server?.port}`
);

این به ما یک نقطه پایانی /quotes GET می‌دهد که می‌توانیم آن را برای دریافت داده‌های نقل قول صدا کنیم. نقطه پایانی متد getAllQuotes() را فراخوانی می کند که از مجموعه connectToDatabase() برای دریافت آرایه نقل قول ها و نویسندگان استفاده می کند. سپس HTMX را برای ردیف ها تولید می کند.

در نهایت، ما پاسخی را ارسال می‌کنیم که ردیف‌ها را به‌عنوان HTMX نگه می‌دارد، و ردیف‌ها در جدول درج می‌شوند.

موتور قالب پاگ را اضافه کنید

ایجاد دستی ردیف HTMX می تواند باعث ناامیدی و خطا شود. یک موتور قالب به ما امکان می دهد ساختار HTMX را در یک فایل ابدی با یک نحو تمیز تعریف کنیم.

محبوب ترین موتور قالب HTML برای جاوا اسکریپت Pug است. استفاده از آن، ایجاد نماها در سرور را بسیار آسان‌تر و مقیاس‌پذیرتر از درون‌نویسی در کد جاوا اسکریپت می‌کند. ایده اصلی این است که اشیاء داده خود را برداریم و آنها را به قالب منتقل کنیم، که داده ها را اعمال می کند و HTML را خروجی می کند. تفاوت در اینجا این است که ما HTMX را به جای HTML تولید می کنیم. ما می توانیم این کار را انجام دهیم زیرا HTMX اساساً HTML با پسوندها است.

برای شروع، کتابخانه Pug را با استفاده از: $ bun add pug به پروژه اضافه کنید.

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

پس از تکمیل، یک دایرکتوری جدید در ریشه پروژه به نام /views ایجاد کنید: ($ mkdir views)، سپس یک فایل جدید به نام quotes.pug اضافه کنید. :


doctype html
h1 Quotes
table
  thead
    tr
      th Quote
      th Author
      th Actions
  tbody
    each quote in quotes
      tr(id=`quote-${quote._id}`)
        td #{quote.quote}
        td #{quote.author}
        td
          button(hx-delete=`/quotes/${quote._id}` hx-trigger="click" hx-swap="closest tr" hx-confirm="Are you sure?") Delete
          #{quote._id}

Pug از تورفتگی برای مدیریت عناصر تو در تو استفاده می کند. ویژگی ها در داخل پرانتز نگهداری می شوند. متن ساده مانند کلمه Delete همانطور که هست ارائه شده است. همه اینها راهی فشرده برای توصیف HTML و/یا HTMX به ما می دهد. صفحه اصلی Pug را ببینید تا درباره نحو آن بیشتر بدانید.

توجه کنید که در داخل یک رشته، باید از ${} استفاده کنیم. نحو #{} به شما امکان می‌دهد به هر شیء داده‌ای که به الگو تزریق شده است ارجاع دهید. این شبیه به درونیابی توکن در چارچوبی مانند React است. ایده اصلی این است که ساختار کلی HTML/HTMX را تعریف کنیم، سپس متغیرهایی را به الگو ارائه کنیم که با #{} و ${} ارجاع داده می‌شوند.

ما متغیرها را در نقطه پایانی سرور /quotes ارائه می‌دهیم که از getAllQuotes() استفاده می‌کند:


import pug from 'pug';
//...
async function getAllQuotes(collection) {
  try {
    const quotes = await collection.find().toArray();

    // Render the Pug template with the fetched quotes
    const html = pug.compileFile('views/quotes.pug')({ quotes });

    return html;
  } catch (error) {
    console.error("Error fetching quotes", error);
    throw error; // Re-throw the error for proper handling
  }
}

بنابراین، نقل‌قول‌ها را از پایگاه داده دریافت می‌کنیم، سپس قالب Pug را کامپایل می‌کنیم و نقل قول‌ها را وارد می‌کنیم. سپس Pug کار تا کردن HTML و داده‌ها را انجام می‌دهد. جریان کلی این است:

  • درخواست به GET /quotes می رسد.
  • نقل‌ها از MongoDB بازیابی شده‌اند.
  • الگوی Pug نقل قول ها را دریافت می کند.
  • الگوی Pug نقل قول ها را به صورت HTML و/یا HTMX ارائه می کند.
  • HTML و/یا HTMX پر شده به عنوان پاسخ ارسال می شود.

صفحه نمایش به نظر چیزی شبیه به این است:

رابط HTMX با قالب Pug

تعاملات DOM: حذف یک ردیف

اکنون باید دکمه Delete خود را فعال کنیم. صرفاً ارسال یک درخواست delete و رسیدگی به آن در سرور و پایگاه داده با آنچه قبلاً دیده‌ایم آسان است، اما در مورد به‌روزرسانی جدول برای منعکس کردن تغییر چه می‌شود؟

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

Google JAX چیست؟ NumPy در شتاب دهنده ها

در قالب views/quotes.pug ما، می‌توانیم از HTMX خالص برای حذف ردیف استفاده کنیم:


  tbody(hx-target="closest tr" hx-swap="outerHTML")
    each quote in quotes
      tr(id=`quote-${quote._id}`)
        td #{quote.quote}
        td #{quote.author}
        td
          button(hx-delete=`/quotes/${quote._id}` hx-trigger="click" hx-confirm="Are you sure?") Delete

قطعات ضروری در اینجا عبارتند از hx-target=”closest tr” و hx-swap=”outerHTML” در tbody. (hx-confirm به شما امکان می‌دهد یک گفتگوی تأیید ارائه دهید.) hx-target می‌گوید که نزدیک‌ترین tr به عنصر ماشه (دکمه) با پاسخ. outHTML در hx-swap تضمین می‌کند که کل عنصر ردیف جدول، نه فقط محتویات آن را حذف می‌کنیم. در سمت سرور، یک موفقیت آمیز (HTTP 200) با بدنه خالی برمی گردانیم، بنابراین HTMX به سادگی ردیف را حذف می کند:


async function deleteQuote(collection, quoteId) {
  try {
    const result = await collection.deleteOne({ _id: new ObjectId(quoteId) });
    if (result.deletedCount === 1) {
      return "";
    } else {
      throw new Error( "Quote not found");
    }
  } catch (error) {
    console.error("Error deleting quote", error);
    throw error; // Re-throw the error for proper handling
  }
}

در اینجا، ما تازه شروع به ورود به تعاملات DOM درگیرتر کرده ایم. HTMX همچنین می‌تواند افکت‌های انتقال ساده را در یک سناریوی حذف ردیف مانند ما به مبادله‌ها اضافه کند. می‌توانید نمونه‌ای را در صفحه اصلی HTMX ببینید.

نتیجه گیری

اگرچه این آموزش دو قسمتی از فناوری های جدیدتری مانند Bun و Elysia استفاده می کند، اما قابل توجه ترین مؤلفه HTMX است. این واقعاً نحوه عملکرد یک برنامه را در مقایسه با APIهای JSON معمولی تغییر می دهد.

هنگامی که با یک موتور قالب مانند Pug و پایگاه داده ای مانند MongoDB ترکیب می شود، کار ایجاد UI و رسیدگی به درخواست ها روان است. با افزایش حجم یک برنامه، ویژگی‌های Pug مانند ارث بری قالب نیز مفید است.

برای فعل و انفعالات DOM، HTMX از طریق hx-swap و hx-target عملکرد انعطاف‌پذیری را ارائه می‌کند. برای موارد استفاده بیشتر درگیر، همیشه می توانید از جاوا اسکریپت استفاده کنید.

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

می‌توانید کد این آموزش را در مخزن GitHub من پیدا کنید.