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

Techboy

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

معرفی ریمیکس: یک رهبر در تکامل تمام پشته

Remix یک چارچوب جاوا اسکریپت تمام پشته به سبک Next.js است – و خیلی چیزهای دیگر. ببینید چه چیزی Remix را در میان چارچوب های جاوا اسکریپت متمایز می کند، سپس آن را با یک برنامه مثال سریع امتحان کنید.

Remix یک چارچوب جاوا اسکریپت تمام پشته به سبک Next.js است – و خیلی چیزهای دیگر. ببینید چه چیزی Remix را در میان چارچوب های جاوا اسکریپت متمایز می کند، سپس آن را با یک برنامه مثال سریع امتحان کنید.

در حالی که Remix به اندازه برخی از فریمورک های بزرگ جاوا اسکریپت شناخته شده نیست، اما Remix به عنوان یکی از فریمورک های برجسته شهرت پیدا کرده است. برخی از ایده‌های خوب معرفی‌شده توسط Remix که در سال ۲۰۲۱ منبع باز شد، در چارچوب‌های دیگر نیز جذب شده‌اند.

در بالاترین سطح، Remix یک چارچوب جاوا اسکریپت تمام پشته به سبک Next.js است: از رندر سمت سرور (SSR) یک برنامه جاوا اسکریپت واکنشی و تمام پشته پشتیبانی می کند. فراتر از این شباهت، Remix از چندین راه که در این مقاله بررسی خواهیم کرد، رویکرد متفاوتی از Next دارد.

نه فقط React

شاید مهم‌ترین انحراف از Next.js این است که Remix به گونه‌ای طراحی شده است که اجرای جلویی آن را انتزاعی کند. به عبارت دیگر، از React جدا شده است. اگرچه Remix با React رویکرد استاندارد در حال حاضر است، می‌توان از فریم‌ورک‌های front-end مختلفی مانند Svelte و Vue استفاده کرد.

به نظر می رسد Remix اولین فریم ورک جاوا اسکریپت باشد که سعی در انتزاع قسمت جلویی Reactive دارد. این رویکرد – ساختن فریم ورک front-end به یک قطعه معماری قابل اتصال در چارچوب برنامه کاربردی بزرگتر – می تواند در آینده به جریان اصلی تبدیل شود. (JHipster شبیه به این است که در حین استفاده از انتهای جاوا، قسمت جلویی جاوا اسکریپت را انتزاعی می کند.)

کد سرور و کلاینت هم‌کجا

ریمیکس مکان یابی کدی را که قسمت جلویی را در کنار کدی که داده های آن را ارائه می دهد، آسان می کند. همانطور که خواهید دید، Remix شامل یک جزء

است، که مانند یک عنصر

است اما دارای قدرت های فوق العاده برای تعامل با منطق سمت سرور است. این کار کپسوله کردن کل چرخه CRUD داده را در یک فایل آسان می کند.

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

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

یک مثال خوب از Remix که بر استانداردها تکیه می کند و در عین حال آنها را گسترش می دهد، استفاده از Fetch API است. Fetch API بخشی از مرورگرهای مدرن است و به استاندارد تبدیل شده است. مکانیزم برای صدور درخواست های شبکه تا حد زیادی نیاز به تکیه بر کتابخانه های شخص ثالث برای ارتباط در مرورگر را از بین برده است (بیشتر ایده های خوب آن کتابخانه ها را جذب کرد). Remix از Fetch API در مرورگر استفاده می کند. سپس با پیاده سازی یک کلاینت HTTP که از Fetch API در سرور استفاده می کند، یک قدم فراتر می رود. نتیجه خالص این است که توسعه دهندگان می توانند از همان API آشنا در سراسر پشته استفاده کنند.

یک راه جالب دیگر که Remix از استانداردها استفاده می کند، استفاده از است. با استفاده از مؤلفه‌های می‌توانید صفحات را زمانی که پیوند به آنها قابل مشاهده است، از قبل بارگذاری مجدد کنید، حتی اگر خود صفحه پویا باشد. مؤلفه Next فقط می تواند صفحاتی را که به صورت ایستا تولید شده اند از قبل واکشی کند.

بهبود پیشرونده و اشکال

بهبود پیشرونده این ایده است که جاوا اسکریپت باید افزودنی خوبی برای یک برنامه کاربردی باشد اما نه یک عنصر ضروری. اگر جاوا اسکریپت به دلایلی در دسترس نباشد (که رایج‌تر از آن چیزی است که بسیاری از مردم تصور می‌کنند)، وب‌سایت همچنان باید کار کند. یکی از راه‌هایی که Remix آن ایده را می‌پذیرد، پذیرش و ترکیب فرم‌ها و داده‌های فرم در آرایش کامل است، در حالی که یک API نوشتن در انتهای پشتی اجرا می‌کند. اگر جاوا اسکریپت در دسترس نباشد، فرم‌ها همچنان به روش قدیمی کار می‌کنند: فقط صفحه را ارسال کرده و دوباره بارگیری کنید.

محدود کردن بارهای شبکه

کاهش دادن حجم داده‌ها (جاوا اسکریپت، JSON، شما نام ببرید) یک حوزه بزرگ تحقیق و توسعه در جامعه جاوا اسکریپت است. Remix در اینجا ایده هایی دارد، به خصوص در مورد محدود کردن داده ها و جاوا اسکریپت ارسال شده.

برای مثال، Remix می‌تواند کارهایی مانند بارگیری نقاط پایانی و فیلتر کردن مجموعه داده‌های آن‌ها در سرور و بسته‌بندی مواد مصرفی انجام دهد. JSON به همراه رابط کاربری، به جای دانلود و پردازش کل مجموعه روی کلاینت. این کار با تعریف یک تابع loader() در کنار مؤلفه React که به داده نیاز دارد انجام می شود. تابع لودر در قسمت پشتی اجرا می شود، که هم داده ها و هم داربست رابط کاربری را که باید ارسال و رندر یا دوباره رندر شوند، کاهش می دهد.

سایر چارچوب‌ها مانند Next و SvelteKit دارای ویژگی‌های مشابه هستند. استفاده Remix از تابع لودر آن را با ایده های فعلی در مورد نحوه مدیریت بارگذاری داده در پشته مطابقت می دهد.

ریمیکس و الگوی BFF

ریمیکس از الگوی Backend For Your Frontend (BFF) پشتیبانی می کند. شما می توانید از فرانت اند و کد مصرف API آن با هر بک اند سازگاری استفاده کنید، نه فقط با جاوا اسکریپت که با Remix ارائه می شود. پذیرش الگوی BFF توسط ریمیکس به این نکته اذعان دارد که معماری ها پیچیده هستند. استفاده از یک سرور بک‌اند برای هماهنگ کردن سرویس‌های مختلفی که برای کارکرد یک برنامه کاربردی انجام می‌شود، اغلب بهترین راه است.

کاربردی با ریمیکس

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

در یک خط فرمان، از npx برای اجرای سازنده برنامه Remix که در فهرست ۱ نشان داده شده است استفاده کنید. می توانید برنامه خود را با استفاده از همان ورودی که در اینجا مشاهده می کنید پر کنید.


$ npx create-remix@latest
? Where would you like to create your app? ./my-remix-app
? What type of app do you want to create? A pre-configured stack ready for production
? Which Stack do you want? (Learn more about these stacks: 'https://remix.run/stacks') Indie
? TypeScript or JavaScript? JavaScript
? Do you want me to run `npm install`? Yes
⠙ Migrating template to JavaScript…Processing 10 files...

پشته های از پیش پیکربندی شده

لازم به ذکر است که مفهوم پشته‌ها، که می‌توانید در انتخاب من از پشته “Indie” در فهرست ۱ مشاهده کنید. پشته Indie که ما استفاده می کنیم، یک Node plus SQLite (با Prisma) آشنا است. همچنین، پشته ها انتخاب های سخت و سریعی نیستند. آنها فقط یک پیش پیکربندی از گزینه های قابل تغییر هستند – برای مثال می توانید پشته Indie را برای استفاده از یک استقرار لبه مانند Vercel منتقل کنید. برای اطلاعات بیشتر درباره پشته‌ها، به اسناد ریمیکس مراجعه کنید.

اکنون می‌توانیم برنامه را با وارد کردن: npm run dev اجرا کنیم. پس از چرخش سرور توسعه دهنده، می توانیم از برنامه در localhost:3000 بازدید کنیم. شما باید صفحه فرود نشان داده شده در شکل ۱ را ببینید.

عکسی از یک برنامه جاوا اسکریپت تمام پشته Remix.

شکل ۱. صفحه فرود برنامه Remix.

ریمیکس یک جریان ثبت نام/ورود ساده ایجاد کرده است. پس از ایجاد یک کاربر ساختگی و ورود به سیستم، می‌توانید روی پیوند «مشاهده یادداشت‌ها» کلیک کنید تا به یک برنامه کلاسیک TODO دسترسی پیدا کنید.

اگر به دایرکتوری ایجاد شده روی دیسک نگاه کنید، دایرکتوری /app را خواهید دید. این جایی است که بخش عمده ای از کدها زندگی می کنند. در کنار /app چند دایرکتوری دیگر وجود دارد: /prisma نگاشت‌ها را برای چارچوب ORM نگه می‌دارد. /cypress حاوی پیکربندی آزمایشی است. /public دارایی های عمومی مانند favicon را دارد. /build حاوی خروجی ساخت تولید است.

با نگاهی به دایرکتوری /app، چندین فایل ابزار مورد استفاده توسط فریمورک و تعدادی دایرکتوری را مشاهده خواهید کرد:

  • /models شامل مدل‌های داده جاوا اسکریپت برای Prisma است.
  • /routes حاوی تعاریف مسیر برای برنامه است.
  • /styles جایی است که سبک های برنامه را پیدا خواهید کرد (به طور پیش فرض، Remix از Tailwind استفاده می کند).

از این میان، فایل /routes مهمترین است، زیرا هم مسیرهای موجود و هم کدی را که آنها را پیاده‌سازی می‌کند تعریف می‌کند. این مشابه دایرکتوری /app یا /pages Next.js است، جایی که ساختار دایرکتوری مسیرهای URL را مدل می‌کند.

به عنوان مثال، صفحه اصلی که در شکل ۱ می بینیم توسط فایل /app/routes/index.jsx ارائه می شود. اگر به محتویات نگاه کنید، React استاندارد است تنها با لمس کد خاص Remix به شکل مؤلفه که برای مسیریابی بین صفحات Remix استفاده می‌شود.

اگر به /notes نگاه کنید، فایلی مانند /notes/'$noteId.jsx' را خواهید دید. این کنوانسیون Remix برای مدیریت پارامترهای URL است، نشانه $nodeId با آنچه در URL که کاربر به آن دسترسی دارد ظاهر می شود جایگزین می شود و در یک params شیء به عنوان params.nodeId (params برای تابع loader() سمت سرور موجود است)).

اگر به فایل /app/routes/notes/index.jsx نگاه کنید، می‌توانید درک کنید که برنامه چگونه تعاملات داده مشتری/سرور را مدیریت می‌کند، همانطور که در فهرست ۲ نشان داده شده است.< /p>


import { json, redirect } from "@remix-run/node";
import { Form, useActionData } from "@remix-run/react";
import * as React from "react";

import { createNote } from "~/models/note.server";
import { requireUserId } from "~/session.server";

export async function action({ request }) {
  const userId = await requireUserId(request);

  const formData = await request.formData();
  const title = formData.get("title");
  const body = formData.get("body");

  const note = await createNote({ title, body, userId });

  return redirect(`/notes/${note.id}`);
}

export default function NewNotePage() {
  const actionData = useActionData();
  const titleRef = React.useRef(null);
  const bodyRef = React.useRef(null);

  React.useEffect(() => {
    if (actionData?.errors?.title) {
      titleRef.current?.focus();
    } else if (actionData?.errors?.body) {
      bodyRef.current?.focus();
    }
  }, [actionData]);

  return (
    <Form
      method="post"
      style={{
        display: "flex", flexDirection: "column", gap: 8, width: "100%" }}>
      <div>
        <label className="flex w-full flex-col gap-1">
          <span>Title: </span>
          <input ref={titleRef} name="title"          className="flex-1 rounded-md border-2 border-blue-500 px-3 text-lg leading-loose" aria-invalid={actionData?.errors?.title ? true : undefined} aria-errormessage={ actionData?.errors?.title ? "title-error" : undefined } />
        </label>
        {actionData?.errors?.title && (
          <div className="pt-1 text-red-700" id="title-error">
            {actionData.errors.title}
          </div>
        )}
      </div>

      <div>
        <label className="flex w-full flex-col gap-1">
          <span>Body: </span>
          <textarea ref={bodyRef} name="body" rows={8}          className="w-full flex-1 rounded-md border-2 border-blue-500 py-2 px-3 text-lg leading-6" aria-invalid={actionData?.errors?.body ? true : undefined} aria-errormessage={ actionData?.errors?.body ? "body-error" : undefined }8 />
        </label>
        {actionData?.errors?.body && (
          <div className="pt-1 text-red-700" id="body-error">
            {actionData.errors.body}
          </div>
        )}
      </div>

      <div className="text-right">
        <button type="submit" className="rounded bg-blue-500 py-2 px-4 text-white hover:bg-blue-600 focus:bg-blue-400">Save</button>
      </div>
    </Form>
  );
}

فهرست ۲ یک جزء کاربردی React معمولی به نام NewNotePage است. برخی از توابع جاوا اسکریپت را تعریف می کند و نشانه گذاری JSX را برای قالب برمی گرداند. (توجه داشته باشید که من کدهای اضافی مانند اعتبار سنجی را برای ساده کردن کارها حذف کرده ام.)

توجه داشته باشید که این الگو از مؤلفه مخصوص Remix استفاده می‌کند که با تابع خاص Remix action() کار می‌کند. این تابع در واقع یک تابع سمت سرور است. یک شی درخواست می گیرد که اطلاعات درخواست ارسال شده توسط مؤلفه را مدل می کند. توجه داشته باشید که Remix از شیء درخواست استفاده می‌کند که حتی از API مرورگر تقلید می‌کند. در توابع سرور.

روش action() از اطلاعات شی Request برای برقراری تماس با تابع createNote() استفاده می کند که از "~/models وارد شده است. /note.server"، که در آن Remix کد Prisma را به اشتراک گذاشته است. این الگوی کلی دسترسی به کد سرور مشترک از توابع سرور تعریف شده در مسیرها است. توجه داشته باشید که قلاب useEffect برای تنظیم بدنه و عنوان سند بر اساس تابع useActionData() Remix مهار شده است.

نتیجه گیری

اگرچه شما فقط یک گشت و گذار سریع از قابلیت های Remix داشته اید، امیدوارم این مثال به شما حسی از طعم و مزه ای که Remix به توسعه فول استک واکنشی می دهد را به شما بدهد. ریمیکس می تواند بسیار بیشتر از آنچه که در اینجا توضیح داده ایم انجام دهد. این قطعاً چارچوبی برای تماشای پیشرفت‌های آتی در جاوا اسکریپت است.

برای درباره فلسفه Remix بیشتر بدانید، به مستندات Remix مراجعه کنید. همچنین به نگاهی به ریمیکس و تفاوت‌های Next.js مراجعه کنید. برای اطلاعات بیشتر درباره Remix در مقایسه با Next.js.