Dưới sự so sánh với những framework JavaScript lớn hơn, Remix không được nổi tiếng bằng những cái tên đó, tuy nhiên nó đã tạo được danh tiếng của riêng mình. Một số ý tưởng tốt được giới thiệu đầu tiên bởi Remix, đã được tích hợp vào các framework khác.

Ở mức độ cao nhất, Remix là một framework JavaScript full-stack theo phong cách của Next.js: nó hỗ trợ rendering phía server (SSR) của một ứng dụng JavaScript full-stack phản ứng. Ngoài sự tương đồng đó, Remix tiếp cận một cách khác biệt so với Next ở một số điểm sẽ được tìm hiểu trong bài viết này cùng với Cafedev ngay bên dưới đây.

1.Khái niệm

Remix là một framework JavaScript full-stack, hỗ trợ server-side rendering (SSR) và client-side rendering (CSR) của một ứng dụng web phản ứng. Nó được phát triển bởi công ty Snowpack, và được công bố dưới dạng mã nguồn mở vào năm 2021.

Remix cung cấp các tính năng đáng chú ý như:

  • Hỗ trợ SSR và CSR cho cùng một trang web
  • Tích hợp sẵn với các công nghệ web mới nhất như TypeScript, React, GraphQL, và npm
  • Cung cấp API mạnh mẽ để quản lý trạng thái ứng dụng và quản lý luồng dữ liệu
  • Thiết kế theo mô hình component và hỗ trợ tái sử dụng mã
  • Được tối ưu hóa để tải trang nhanh hơn và giảm thiểu thời gian phản hồi

Remix đã thu hút được sự quan tâm của cộng đồng lập trình viên và nhận được nhiều lời khen ngợi về khả năng xử lý dữ liệu, tốc độ tải trang và hiệu suất.

2. Đặc điểm của Remix

2.1.Remix không chỉ là React

Có thể nói điều khác biệt đáng kể nhất của Remix so với Next.js là nó được thiết kế để trừu tượng hóa cài đặt phía frontend. Nói cách khác, nó không phụ thuộc vào React. Mặc dù Remix với React là cách tiếp cận tiêu chuẩn hiện tại, nhưng bạn cũng có thể sử dụng các framework phía frontend khác như Svelte và Vue.

Remix có vẻ là framework JavaScript đầu tiên cố gắng trừu tượng hóa phần frontend. Cách tiếp cận này – làm cho framework phía frontend trở thành một phần kiến trúc có thể được cắm và sử dụng trong một framework ứng dụng lớn hơn – có thể trở nên phổ biến hơn trong tương lai.

2.2. Máy chủ và máy khách được đặt cùng vị trí

liệu vào cùng một nơi. Như bạn sẽ thấy, Remix bao gồm một thành phần <Form>, tương tự như một thẻ <form> nhưng với các chức năng siêu việt để tương tác với logic phía máy chủ. Điều này giúp dễ dàng đóng gói toàn bộ chu trình dữ liệu CRUD trong cùng một tệp.

2.3.Xây dựng trên các tiêu chuẩn của web

Nếu nhìn vào triết lý của Remix, một trong những nguyên tắc chính của nó là xây dựng trên các tiêu chuẩn web hiện có như HTTP và HTML và bổ sung thêm một lớp JavaScript mà không che giấu các công nghệ cơ bản. Tiếp cận gần gũi với các tiêu chuẩn web là một ý tưởng tốt vì chúng rất tốt trong việc cập nhật với sự thay đổi của cảnh phát triển. Các tiêu chuẩn web hiện đại cũng rất mạnh mẽ và có khả năng ấn tượng.

Một ví dụ tốt về Remix phụ thuộc vào tiêu chuẩn trong khi mở rộng chúng là sử dụng Fetch API. Fetch API là một phần của trình duyệt hiện đại và đã trở thành cơ chế tiêu chuẩn để gửi yêu cầu mạng. Nó đã phần lớn thay thế việc phụ thuộc vào thư viện bên thứ ba cho giao tiếp trong trình duyệt (nó hấp thụ hầu hết các ý tưởng tốt từ các thư viện đó). Remix sử dụng Fetch API trong trình duyệt. Sau đó, nó đi một bước xa hơn bằng cách thực hiện một HTTP client sử dụng Fetch API trên máy chủ. Kết quả là các nhà phát triển có thể sử dụng cùng một API quen thuộc trên toàn bộ cơ sở.

Một cách thú vị khác mà Remix tận dụng tiêu chuẩn là sử dụng <link rel=”prefetch”>. Sử dụng các thành phần <link rel=”prefetch”> cho phép Remix tiên đoán các trang khi liên kết tới chúng hiển thị, ngay cả khi trang đó là động. Thành phần <link> của Next chỉ có thể tiên đoán các trang được tạo tĩnh.

2.4.Progressive enhancement và biểu mẫu

Progressive enhancement là ý tưởng rằng JavaScript nên là một phần bổ sung tốt cho ứng dụng nhưng không phải là yếu tố cần thiết. Nếu JavaScript không có sẵn vì một lý do nào đó (điều này phổ biến hơn nhiều người nghĩ), trang web vẫn nên hoạt động. Một cách Remix tôn trọng ý tưởng này là chấp nhận và tích hợp biểu mẫu và dữ liệu biểu mẫu vào sự sắp xếp full-stack, trong khi triển khai một API viết trên phía back end. Nếu không có JavaScript, biểu mẫu vẫn hoạt động theo cách cũ: chỉ cần nộp và tải lại trang.

2.5.Giới hạn tải payload trong mạng

Giảm thiểu lượng dữ liệu – JavaScript, JSON, bạn đặt tên cho nó – đi qua mạng là một lĩnh vực lớn của nghiên cứu và phát triển trong cộng đồng JavaScript. Remix có một số ý tưởng ở đây, đặc biệt là liên quan đến việc giới hạn dữ liệu và JavaScript được gửi.

Ví dụ, Remix có thể làm các việc như tải các điểm cuối (endpoints) và lọc bộ dữ liệu của chúng trên máy chủ và bungkus JSON có thể tiêu thụ cùng với giao diện người dùng, thay vì tải và xử lý toàn bộ bộ dữ liệu trên máy khách. Điều này được thực hiện bằng cách định nghĩa một hàm loader() song song với thành phần React cần dữ liệu. Hàm loader chạy trên phía back end, giảm thiểu cả dữ liệu và cấu trúc giao diện người dùng phải được gửi và hiển thị hoặc hiển thị lại.

Các framework khác như Next và SvelteKit cũng có tính năng tương đồng. Việc sử dụng hàm loader đưa Remix về với các ý tưởng hiện tại về cách quản lý tải dữ liệu trên toàn stack.

2.6.Remix và BFF pattern

Remix hỗ trợ mẫu Backend For Your Frontend (BFF), cho phép bạn sử dụng mã phía trước và mã tiêu thụ API của nó với bất kỳ back end tương thích nào, không chỉ là back end JavaScript đi kèm với Remix. Sự ủng hộ của Remix cho mẫu BFF thể hiện rằng kiến trúc là phức tạp. Sử dụng một máy chủ back end để điều phối các dịch vụ khác nhau để tạo thành một ứng dụng hoạt động thường là cách tốt nhất để tiến tới.

3.Thực hành với Remix qua ví dụ

Tôi đã mô tả một số tính năng hấp dẫn nhất của Remix, bao gồm những lĩnh vực nơi nó là một mô hình cho những ý tưởng và khả năng mới cho phát triển JavaScript. Bây giờ, hãy tạo một ứng dụng đơn giản và có cái nhìn về cách Remix hoạt động.

Trong cửa sổ dòng lệnh, sử dụng npx để chạy trình tạo ứng dụng Remix được hiển thị trong danh sách 1. Bạn có thể điền thông tin của ứng dụng của mình bằng cách sử dụng đầu vào tương tự như ở đây.

Tạo một ứng dụng Remix mới

$ 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...

3.1 Stack được cấu hình sẵn

Nên đề cập đến khái niệm bộ xếp (stacks), mà bạn có thể thấy trong lựa chọn của mình cho bộ xếp “Indie” trong Listing 1. Các bộ xếp là các công nghệ được thiết lập trước với các cấu hình triển khai khác nhau. Bộ xếp “Indie” chúng ta đang sử dụng là một back end quen thuộc với Node kết hợp với SQLite (với Prisma). Ngoài ra, các bộ xếp không phải là các lựa chọn cứng nhắc; chúng chỉ là một cấu hình trước của các tùy chọn có thể thay đổi – ví dụ: bạn có thể chuyển bộ xếp Indie để sử dụng việc triển khai edge như Vercel. Xem tài liệu Remix để biết thêm về các bộ xếp.

Bây giờ, chúng ta có thể chạy ứng dụng bằng cách nhập: npm run dev. Sau khi máy chủ dev được kích hoạt, chúng ta có thể truy cập ứng dụng tại localhost: 3000. Bạn nên thấy trang đích được hiển thị như trong Hình 1.

Remix đã tạo ra một luồng đăng ký/đăng nhập đơn giản. Sau khi bạn tạo người dùng giả và đăng nhập, bạn có thể nhấp vào liên kết “Xem Ghi chú” để truy cập vào một ứng dụng TODO cổ điển.

Nếu bạn nhìn vào thư mục được tạo trên đĩa, bạn sẽ thấy một thư mục /app; đó là nơi chứa hầu hết mã. Bên cạnh /app là một vài thư mục khác: /prisma chứa các bản đồ cho framework ORM; /cypress chứa cấu hình kiểm tra; /public chứa các tài sản công khai như favicon; /build chứa đầu ra xây dựng sản xuất.

Nếu nhìn vào thư mục /app, bạn sẽ thấy một vài tệp tiện ích được sử dụng bởi framework và một vài thư mục:

  • /models chứa các mô hình dữ liệu JavaScript cho Prisma.
  • /routes chứa định nghĩa tuyến đường cho ứng dụng.
  • /styles là nơi bạn sẽ tìm thấy các kiểu ứng dụng (theo mặc định, Remix sử dụng Tailwind).

Trong số đó, tệp /routes là quan trọng nhất, vì nó xác định cả tuyến đường có sẵn và mã cài đặt chúng. Điều này tương tự như thư mục /app hoặc /pages của Next.js, trong đó cấu trúc thư mục mô hình các tuyến đường URL.

Ví dụ, trang chính chúng ta thấy trong Hình 1 được hiển thị bởi tệp /app/routes/index.jsx. Nếu nhìn vào nội dung, đó là React chuẩn chỉ có một chút mã cụ thể cho Remix dưới dạng thành phần <Link> được sử dụng để định tuyến giữa các trang Remix.

Nếu nhìn vào /notes, bạn sẽ thấy một tệp như /notes/’$noteId.jsx’. Đó là quy ước của Remix để xử lý tham số URL, mã thông báo $nodeId sẽ được thay thế bằng những gì xuất hiện trong URL mà người dùng đang truy cập và được cung cấp cho trang trong một đối tượng đặc biệt params dưới dạng params.nodeId (params có sẵn cho hàm loader() trên máy chủ)).

Nếu nhìn vào tệp /app/routes/notes/index.jsx, bạn có thể hiểu được cách ứng dụng xử lý tương tác dữ liệu máy khách/máy chủ, như được hiển thị như Code 2:

Code 2:

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>
  );
}

Code 2 nói về một thành phần React function thông thường có tên là NewNotePage, nó định nghĩa một số hàm JavaScript và trả về đánh dấu JSX cho mẫu. (Lưu ý rằng một số mã không liên quan đã bị xóa để đơn giản hóa vấn đề.)

Lưu ý rằng mẫu sử dụng thành phần <Form> đặc biệt của Remix, nó hoạt động chặt chẽ với chức năng Remix action(). Hàm này thực chất là một hàm server-side. Nó lấy một đối tượng yêu cầu, mô hình hóa thông tin yêu cầu được gửi bởi thành phần <Form>. Lưu ý rằng Remix sử dụng một đối tượng Request mô phỏng API trình duyệt ngay cả trong các chức năng server.

Phương thức action() sử dụng thông tin từ đối tượng Request để gọi hàm createNote() được nhập từ “~/models/note.server”, nơi mà Remix đã tạo ra mã Prisma back-end chia sẻ. Đây là mẫu tổng quát của việc truy cập mã server chia sẻ từ các chức năng server được xác định trong các tuyến đường. Lưu ý rằng useEffect hook được sử dụng để thiết lập nội dung và tiêu đề của tài liệu dựa trên hàm Remix useActionData().

4.Phần tóm tắt

Mặc dù Cafedev chỉ giúp bạn được tham quan nhanh về khả năng của Remix, chung tôi hy vọng ví dụ này đã giúp bạn hiểu thêm về những tính năng đặc trưng của Remix trong phát triển full stack. Remix có thể làm nhiều hơn những gì chúng ta đã đề cập ở đây. Đây là một framework đáng để theo dõi trong các phát triển tương lai của JavaScript

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Đăng ký kênh youtube cafedev để dễ dàng học lập trình học lập trình qua video một cách nhanh chóng và chính xác nhất.

Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!.

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!