কম্পিউটার টিউটোরিয়াল

Remix এবং সার্ভারলেস রেডিস দিয়ে স্কেলেবল TODO অ্যাপ তৈরি করুন

এই পোস্টে আমরা Remix এবং সার্ভারলেস রেডিস (Upstash) ব্যবহার করে একটি সাধারণ TODO অ্যাপ্লিকেশন তৈরি করব।

Remix হল একটি ফুল-স্ট্যাক ওয়েব ফ্রেমওয়ার্ক যা আপনাকে ইউজার ইন্টারফেসে ফোকাস করতে দেয় এবং ওয়েব ফান্ডামেন্টালসের মাধ্যমে দ্রুত, slik এবং টেকসহ্যভাবে ইউজার অভিজ্ঞতা দেয়।

Remix প্রোজেক্ট তৈরি করুন

নিচের কমান্ডটি চালান:

npx create-remix@latest

Remix এবং সার্ভারলেস রেডিস দিয়ে স্কেলেবল TODO অ্যাপ তৈরি করুন

প্রোজেক্টটি প্রস্তুত। এখন ডিপেন্ডেন্সি ইনস্টল করুন এবং চালান:

npm install
npm run dev

Remix এবং সার্ভারলেস রেডিস দিয়ে স্কেলেবল TODO অ্যাপ তৈরি করুন

ইউজার ইন্টারফেস

আমরা TODO আইটেমের জন্য একটি সাধারণ ফর্ম এবং লিস্ট তৈরি করব:

// app/routes/index.tsx
import type { ActionFunction, LoaderFunction } from "remix";
import { Form, useLoaderData, useTransition, redirect } from "remix";
import { useEffect, useRef } from "react";
import type { Todo } from "~/components/todo-item";
import TodoItem from "~/components/todo-item";

export const loader: LoaderFunction = async () => {
  // উদাহরণ ডেটা
  return [
    { id: 1, text: "Task 1", status: false },
    { id: 2, text: "Task 2", status: true },
  ];
};

export const action: ActionFunction = async ({ request }) => {
  // এটি তৈরি, আপডেট এবং ডিলিট অপারেশনের জন্য ব্যবহার হবে
};

export default function Index() {
  // লোডিং এবং ফর্ম অ্যাকশনের জন্য
  const transition = useTransition();
  // পেজে লোড করা ডেটা ব্যবহার করার জন্য
  const todos: Todo[] = useLoaderData();
  
  const isCreating = transition.submission?.method === "POST";
  const isAdding = transition.state === "submitting" && isCreating;
  
  // সম্পন্ন এবং অসম্পন্ন টাস্ক ভাগ করুন
  const uncheckedTodos = todos.filter((todo) => !todo.status);
  const checkedTodos = todos.filter((todo) => todo.status);
  
  const formRef = useRef<HTMLFormElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  
  useEffect(() => {
    // তৈরি করার পর ফর্ম রিসেট করুন
    if (isAdding) return;
    formRef.current?.reset();
    inputRef.current?.focus();
  }, [isAdding]);
  
  return (
    <main className="container">
      {/* তৈরি ফর্ম */}
      <Form ref={formRef} method="post">
        <input
          ref={inputRef}
          type="text"
          name="text"
          autoComplete="off"
          className="input"
          placeholder="কী করতে হবে?"
          disabled={isCreating}
        />
      </Form>
      
      {/* অসম্পন্ন টাস্ক */}
      <div className="todos">
        {uncheckedTodos.map((todo) => (
          <TodoItem key={todo.id} {...todo} />
        ))}
      </div>
      
      {/* সম্পন্ন টাস্ক */}
      {checkedTodos.length > 0 && (
        <div className="todos todos-done">
          {checkedTodos.map((todo) => (
            <TodoItem key={todo.id} {...todo} />
          ))}
        </div>
      )}
    </main>
  );
}

এখানে আমাদের TODO কম্পোনেন্ট:

// app/components/todo-item.tsx
import { Form } from "remix";

export type Todo = { id: string; text: string; status: boolean };

export default function TodoItem({ id, text, status }: Todo) {
  return (
    <div className="todo">
      <Form method="put">
        {/* এই হিডেন ইনপুট আমাদের TODO আইটেমের ডেটা রাখবে */}
        <input
          type="hidden"
          name="todo"
          defaultValue={JSON.stringify({ id, text, status })}
        />
        {/* Remix ফর্মগুলো ঠিক ট্রেডিশনাল ওয়েব ফর্মের মতো। আমি এটা পছন্দ করি। */}
        <button type="submit" className="checkbox">
          {status && "✓"}
        </button>
      </Form>
      <span className="text">{text}</span>
    </div>
  );
}

এখন আমাদের CSS ফাইল যোগ করুন। app/styles/app.css ফাইলটি তৈরি করুন:

:root {
  --rounded: 0.25rem;
  --rounded-md: 0.375rem;
  --gray-50: rgb(249, 250, 251);
  --gray-100: rgb(243, 244, 246);
  --gray-200: rgb(229, 231, 235);
  --gray-300: rgb(209, 213, 219);
  --gray-400: rgb(156, 163, 175);
  --gray-500: rgb(107, 114, 128);
  --gray-600: rgb(75, 85, 99);
  --gray-700: rgb(55, 65, 81);
  --gray-800: rgb(31, 41, 55);
  --gray-900: rgb(17, 24, 39);
}

*, ::before, ::after {
  box-sizing: border-box;
  border: 0;
  padding: 0;
}

button, input, optgroup, select, textarea {
  font-family: inherit;
  font-size: 100%;
  line-height: inherit;
  color: inherit;
  margin: 0;
  padding: 0;
}

button {
  cursor: pointer;
  background-color: white;
}

html {
  font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: var(--gray-800);
}

.container {
  padding: 8rem 1rem 0;
  margin: 0 auto;
  max-width: 28rem;
}

.input {
  width: 100%;
  padding: 0.75rem 1rem;
  background-color: var(--gray-100);
  border-radius: var(--rounded-md);
}

.input::placeholder {
  color: var(--gray-400);
}

.input:disabled {
  color: var(--gray-600);
  background-color: var(--gray-200);
}

.todos {
  margin-top: 1.5rem;
}

.todos.todos-done {
  background-color: var(--gray-100);
  color: var(--gray-500);
  border-radius: var(--rounded-md);
}

.todo {
  display: flex;
  align-items: center;
  padding: 0.75rem;
  border-radius: var(--rounded-md);
}

.todo + .todo {
  border-top: 1px solid var(--gray-100);
}

.todo .checkbox {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--rounded);
  border: 1px solid var(--gray-300);
  box-shadow: 0 1px 1px 0 rgb(0 0 0 / 10%);
}

.todo .text {
  margin-left: 0.75rem;
}

root.tsx এর নিচে CSS ইমপোর্ট করুন:

import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from "remix";
import type { MetaFunction } from "remix";
import styles from "./styles/app.css";

export function links() {
  return [{ rel: "stylesheet", href: styles }];
}

export const meta: MetaFunction = () => {
  return { title: "Remix Todo App with Redis" };
}

export default function App() {
  // ...
}

এখন আপনাকে নিচের মতো দেখাবে:

Remix এবং সার্ভারলেস রেডিস দিয়ে স্কেলেবল TODO অ্যাপ তৈরি করুন

ডেটাবেস প্রস্তুত করুন

আমরা আমাদের ডেটা Upstash রেডিসে রাখব। তাই Upstash ডেটাবেস তৈরি করুন। আমরা HTTP-ভিত্তিক Upstash ক্লায়েন্ট ব্যবহার করব। ইনস্টল করুন:

npm install @upstash/redis

:::note Upstash রেডিস API-এর সাথে কম্প্যাটিবল, তাই আপনি যেকোনো রেডিস ক্লায়েন্ট ব্যবহার করতে পারেন তবে নিচের কোড পরিবর্তন করতে হবে। :::

আমরা শুধু ফর্ম সাবমিট করে নতুন TODO আইটেম যোগ করতে পারি। আমরা নতুন আইটেমগুলো রেডিস হ্যাশে সেভ করব।

Upstash কনসোল থেকে UPSTASH_REDIS_REST_URL এবং UPSTASH_REDIS_REST_TOKEN কপি/পেস্ট করুন।

// app/routes/index.tsx
// ...
import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: "UPSTASH_REDIS_REST_URL",
  token: "UPSTASH_REDIS_REST_TOKEN",
});

export const action: ActionFunction = async ({ request }) => {
  const form = await request.formData();
  
  if (request.method === "POST") {
    const text = form.get("text");
    if (!text) return redirect("/");
    
    await redis.hset("remix-todo-example", {
      [Date.now().toString()]: {
        text,
        status: false,
      },
    });
  }
  
  // প্রতিটি অপারেশনের পর লিস্ট ফেচ করার জন্য
  return redirect("/");
};

এখন আইটেমগুলো লিস্ট করি:

// app/routes/index.tsx
export const loader: LoaderFunction = async () => {
  const res = await redis.hgetall<Record<string, object>>(DATABASE_KEY);
  
  const todos = Object.entries(res ?? {}).map(([key, value]) => ({
    id: key,
    ...value,
  }));
  
  // তারিখ অনুযায়ী সর্ট (id=টাইমস্ট্যাম্প)
  return todos.sort((a, b) => parseInt(b.id) - parseInt(a.id));
};

আমাদের 'তৈরি' এবং 'লিস্ট' ফাংশনালিটি আছে। এখন ব্যবহারকারী TODO আইটেমকে ডান হিসেবে চিহ্নিত করার পার্ট ইমপ্লিমেন্ট করব।

// app/routes/index.tsx
export const action: ActionFunction = async ({ request }) => {
  const form = await request.formData();
  
  // তৈরি
  if (request.method === "POST") {
    // ...
  }
  
  // আপডেট
  if (request.method === "PUT") {
    const todo = form.get("todo");
    const { id, text, status } = JSON.parse(todo as string);
    
    await redis.hset("remix-todo-example", {
      [id]: {
        text,
        status: !status,
      },
    });
  }
  
  return redirect("/");
};

সবকিছু প্রস্তুত! আমি একই TODO অ্যাপ্লিকেশন Next.js এবং SvelteKit দিয়ে ইমপ্লিমেন্ট করার পরিকল্পনা করছি। তারপর এই ফ্রেমওয়ার্কগুলোর সাথে আমার অভিজ্ঞতা তুলনা করব।

আপডেট পেতে টুইটার এবং ডিসকোর্ডে ফলো করুন।

প্রোজেক্ট সোর্স কোড

https://github.com/upstash/redis-examples/tree/master/remix-todo-app-with-redis

প্রোজেক্ট ডেমো পেজ

https://remix-todo-app-with-redis.vercel.app/

  1. ফ্লাটার, সার্ভারলেস ফ্রেমওয়ার্ক এবং আপস্ট্যাশ রেডিস দিয়ে ফুল-স্ট্যাক সার্ভারলেস ফ্লাটার অ্যাপ বানান – পার্ট ১

  2. এজ ক্যাশিংয়ে Redis-র মাধ্যমে ৫ মিলিসেকেন্ড গ্লোবাল লেটেন্সি অর্জন

  3. Cloudflare Workers-এ Redis ব্যবহার করে এজ কম্পিউটিং-এর শক্তি ব্যবহার করুন

  4. রেডিস GEORADIUSBYMEMBER ব্যবহার: উদাহরণসহ ব্যাবহারিক গাইড