Blitz.js হল একটি React ফ্রেমওয়ার্ক যা মূলত Next.js-র থেকে ফর্ক করা হয়েছিল। আজ আমরা একটি Blitz.js To-Do অ্যাপ্লিকেশন তৈরি করব যা টাস্কগুলো Upstash-এ সংরক্ষণ করে। আর দেরি না করে, শুরু করা যাক!
সেটআপ
শুরু করার জন্য আপনাকে আপনার কম্পিউটারে Blitz.js ইনস্টল করতে হবে।
NPM:
npm install -g blitz --legacy-peer-deps
Yarn:
yarn global add blitz
একটি নতুন Blitz.js অ্যাপ তৈরি করতে blitz new ব্যবহার করুন এবং ডিরেক্টরিতে cd করুন।
blitz new blitzjs-todo && cd blitzjs-todo
চমৎকার, এখন আমাদের ওয়েবসাইট স্টাইল করার জন্য TailwindCSS ইনস্টল করি।
blitz install tailwind
শেষে, Upstash JS SDK ইনস্টল করি যাতে Upstash API-তে কল করা সহজ হয়।
NPM:
npm i @upstash/redis
Yarn:
yarn i @upstash/redis
এই পয়েন্টে, আপনাকে blitz dev রান করা উচিত যাতে সবকিছু সঠিকভাবে কাজ করছে কিনা তা নিশ্চিত করা যায়। একটি অ্যাকাউন্ট তৈরি এবং সাইন ইন করার চেষ্টা করুন। যদি আপনি সবকিছু সঠিকভাবে করে থাকেন তবে এটি এরকম দেখাবে।

অতিরিক্তভাবে, আপনার ফাইল স্ট্রাকচার এরকম দেখাবে:

UPSTASH_REDIS_REST_URL এবং UPSTASH_REDIS_REST_TOKEN Upstash Console- থেকে কপি করে .env ফাইলে পেস্ট করুন। এটি এরকম দেখাবে:
# This env file should be checked into source control # This is the place for default values for all environments # Values in `.env.local` and `.env.production` will override these values UPSTASH_REDIS_REST_URL=YOUR_URL_HERE UPSTASH_REDIS_REST_TOKEN=YOUR_TOKEN_HERE
আমরা আমাদের Blitz.js অ্যাপ্লিকেশন সম্পূর্ণ সেট আপ করেছি! এখন আমাদের To-Do লিস্ট ইমপ্লিমেন্ট করা শুরু করি।
ইমপ্লিমেন্টেশন
Blitz.js বিল্ট-ইন ইউজার অথেন্টিকেশন নিয়ে আসে! আমরা এটি লিভারেজ করব প্রতিটি ব্যবহারকারীর জন্য প্রাইভেট to-do লিস্ট बनाने জন্য।
প্রথম, /lib/redis.ts-এ Upstash JS SDK ইনিশিয়ালাইজ করি।
import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv(); export default redis;
আমাদের To-Do লিস্ট অ্যাক্সেস করার জন্য ৩টি ভিন্ন API Route তৈরি করতে হবে।
app/api-এ নেভিগেট করুন এবং getall.ts নামে একটি ফাইল তৈরি করুন। একবার করলে, নিচের কোডটি পেস্ট করুন:
import { BlitzApiRequest, BlitzApiResponse, getSession } from "blitz"; import redis from "../../lib/redis"; export const handler = async (req: BlitzApiRequest, res: BlitzApiResponse) => { const session = await getSession(req, res); if (!session.userId) { res.status(401).json({ error: `Do not tamper with this route!` }); } else { await redis .lrange(String(session.userId), 0, 100) .then((data) => res.status(200).json({ data: data, success: true })) .catch((error) => res.status(500).json({ error: error })); } }; export default handler;
এই API Route কীভাবে কাজ করে তা ধাপে ধাপে দেখি। প্রথমে, আমরা রুটে একটি রিকোয়েস্ট করি। রুটটিতে, আমরা যাচাই করি যে ব্যবহারকারী লগ ইন করা আছে কিনা। যদি কোনো ব্যবহারকারী না থাকে, আমরা "Not Authorized" রেসপন্স রিটার্ন করি। যদি একজন ব্যবহারকারী থাকে, তাহলে আমরা আমাদের Upstash Redis ডাটাবেস ফেচ করি বর্তমানে লিস্টে থাকা সব To-Do খুঁজে বের করার জন্য। এটি প্রায় ১০০টি To-Do ফেচ করবে।
Q: অপেক্ষা করুন, আমরা প্রথমে To-Do কীভাবে যোগ করব? A: ভালো প্রশ্ন! এখন সেটি করি!
আবার, নিচের কোডটি app/api-এ add.ts নামে একটি নতুন ফাইলে পেস্ট করুন।
import { BlitzApiRequest, BlitzApiResponse, getSession } from "blitz"; import redis from "../../lib/redis"; const handler = async (req: BlitzApiRequest, res: BlitzApiResponse) => { const session = await getSession(req, res); if (req.method !== "POST" || !req.body.data || !session.userId) { res.status(401).json({ error: `Do not tamper with this route!` }); } else { let todo = encodeURI(req.body.data); await redis .lpush(String(session.userId), todo) .then(() => res.status(200).json({ success: true })) .catch(() => res.status(500).json({ error: "Error adding data." })); } }; export default handler;
এই API route之前のとほぼ同じ, কিন্তু পঞ্চম লাইনে আমরা আরও চেক যোগ করেছি। সেটি কারণ এই রিকোয়েস্ট একটি GET রিকোয়েস্ট নন, বরং একটি POST রিকোয়েস্ট। লক্ষ্য করুন আমরা তিন জিনিস চেক করছি। প্রথমে, আমরা নিশ্চিত করি যে রিকোয়েস্টটি আসলে একটি POST রিকোয়েস্ট। এরপর, আমরা নিশ্চিত করি যে req.body.data-এ JSON বা টেক্সট আছে। অবশেষে, আমরা নিশ্চিত করি ব্যবহারকারী লগ ইন করা আছে। এই ছোট ছোট চেকগুলো পাস হলে, আমরা আমাদের To-Do Upstash-এ Redis লিস্টে পুশ করতে পারি। যদি ফেচ করার সময় যেকোনো এরর হয়, আমরা .catch ব্যবহার করে 500 রিটার্ন করতে পারি।
আমাদের যোগ করার শেষ রুটটি হবে আমাদের To-Do রিমুভ করার জন্য। একবার কিছু ফিনিশ করলে, আপনাকে অবশ্যই সেটি ক্রস আউট করতে হবে! আমাদের শেষ API Route app/api/remove.ts-এ যোগ করুন। নিচের কোডটি ফাইলে কপি করুন:
import { BlitzApiRequest, BlitzApiResponse, getSession } from "blitz"; import redis from "../../lib/redis"; const handler = async (req: BlitzApiRequest, res: BlitzApiResponse) => { const session = await getSession(req, res); if (req.method !== "POST" || !req.body.data || !session.userId) { res.status(401).json({ error: `Do not tamper with this route!` }); } else { let todo = encodeURI(req.body.data); await redis .lrem(String(session.userId), 1, todo) .then(() => res.status(200).json({ success: true })) .catch(() => res.status(500).json({ error: "Error removing data." })); } }; export default handler;
কিছু সাদৃশ্য লক্ষ্য করলেন? সেটি কারণ এই route تقريبا add API Route-এর মতো। এখানে প্রধান পার্থক্য হলো, আমরা Redis-এ থেকে একটি আইটেম রিমুভ করার জন্য LPUSH নয় LREM ব্যবহার করছি।
ফ্রন্টএন্ড বিল্ড করা
শুরু করতে, app/pages/index.js-এ সবকিছু ডিলিট করুন এবং আমাদের To-Do লিস্ট ধাপে ধাপে লিখুন।
ফাইলের টপে এই ইম্পোর্টগুলো পেস্ট করুন।
import { Link, BlitzPage, useMutation, Routes, getAntiCSRFToken } from "blitz"; import { useRef, useEffect, useState, Suspense } from "react"; import Layout from "app/core/layouts/Layout"; import { useCurrentUser } from "app/core/hooks/useCurrentUser"; import logout from "app/auth/mutations/logout";
আমরা React Hooks ব্যবহার করব আমাদের To-Do লিস্টের কোর ফাংশনালিটি বিল্ড করতে। কোর ফিচার কিছু ইমপ্লিমেন্ট করি।
const Main = () => { const todoRef = useRef(null) const [todos, setTodos] = useState([]) const currentUser = useCurrentUser() const [logoutMutation] = useMutation(logout) const handleAddTodo = async (e) => { e.preventDefault() const antiCSRFToken = await getAntiCSRFToken() const response = await fetch("/api/add", { method: "POST", headers: { "Content-Type": "application/json", "anti-csrf": antiCSRFToken, }, body: JSON.stringify({ data: todoRef.current?.value }), }) const data = await response.json() if (data.success) { todoRef.current!.value = "" fetchTodos() } } const handleRemoveTodo = async (id) => { const antiCSRFToken = await getAntiCSRFToken() const response = await fetch("/api/remove", { method: "POST", headers: { "Content-Type": "application/json", "anti-csrf": antiCSRFToken, }, body: JSON.stringify({ data: id }), }) const data = await response.json() if (data.success) { fetchTodos() } } const fetchTodos = async () => { const antiCSRFToken = await getAntiCSRFToken() const response = await fetch("/api/getall", { method: "GET", headers: { "anti-csrf": antiCSRFToken, }, }) const res = await response.json() setTodos(res.data) } useEffect(() => { fetchTodos() }, []) if (currentUser) { return ( <> User id: {currentUser.id}
User email: {currentUser.email} {(todos as string[]).map((todo: string, index: number) => ( {todo} ))} > ) } else { return ( ) } }
<Main/> কম্পোনেন্টটি আমাদের অ্যাপ্লিকেশনের কোর। এর কোডে একটি নজর দিলে আমরা কীভাবে এটি ব্যবহার করি সেটি বোঝা যায়। কম্পোনেন্টের টপে, আমরা আমাদের অ্যাপ্লিকেশনের জন্য স্টেট ইনিশিয়ালাইজ করি। আমরা পরবর্তীতে "New To-Do" ইনপুটে ব্যবহার করার জন্য একটি ref ডিক্লেয়ার করি। আপনি antiCSRFToken-এর ব্যবহারও লক্ষ্য করতে পারেন! Blitz.js API Routes ফেচ করার সময় এই টোকেনগুলোর ব্যবহার আবশ্যক করে যাতে কোনো ম্যালিশিয়াস এক্টর আপনার সাইটকে হানি করতে না পারে। আমার মতে এটি খুব ভালো!
আমরা তিনটি প্রধান ফাংশন ব্যবহার করি আমাদের ডেটা ওয়েবসাইটে হ্যান্ডেল করার জন্য। এ তিনটি হলো:
handleAddTodohandleRemoveTodofetchTodos
আমরা fetchTodos কল করি পেজ লোড হওয়ার সাথে সাথে, যাতে ব্যবহারকারীর পূরণ করতে বাকি থাকা সব To-Do লোড হয়। যখন একজন ব্যবহারকারী একটি To-Do যোগ বা রিমুভ করে, আমরা আবার fetchTodos কল করি যাতে ওয়েবসাইটে সেই পরিবর্তনটি প্রতিফলিত হয়!
যদি একজন ব্যবহারকারী লগ ইন না থাকে, ব্যবহারকারীকে এই পেজ দেখার আগে ওয়েবসাইটে লগ ইন করার জন্য প্রম্পট করা হবে।
আপনি সাইন আপ বা লগ ইন করতে পারেন যদি আপনার ওয়েবসাইটে ইতিমধ্যে সেশন না থাকে। মনে রাখবেন, আপনি অ্যাকাউন্ট ছাড়া আপনার To-Do সংরক্ষণ করতে পারবেন না, এবং সব API Routes আপনাকে একটি AntiCSRFToken-এর সাথে অথেন্টিকেটেড থাকতে বাধ্য করে!
রুকুন, একটি আরো গুরুত্বপূর্ণ ধাপ! আমাদের পেজটি এক্সপোর্ট করতে হবে!
const Home: BlitzPage = () => { return ( ); }; Home.suppressFirstRenderFlicker = true; Home.getLayout = (page) => {page} ; export default Home;
আপনি উপরে দেখতে পাচ্ছেন, Blitz.js একটি কিছুটা আলাদা পদ্ধতি ব্যবহার করে Next-এর থেকে, কিন্তু বর্তমানে এর কোরে পদ্ধতিটি একই। আমরা আগে ইম্পোর্ট করা Suspense ব্যবহার করি যাতে ব্যবহারকারীকে দেখানো যায় অ্যাপটি লোড হচ্ছে, এবং তারপর লোডিং ফিনিশ হলে আমাদের </Main> কম্পোনেন্টটি দেখাই!।
আপনার কনসোলে একবার আরো এটি রান করুন পরিবর্তনগুলো ইফেক্টে देखने জন্য, এবং ব্রাউজারে আপনার অ্যাপে নেভিগেট করুন।
blitz dev
যদি আপনি ডিরেকশনগুলো ফলো করেছেন, আপনার অ্যাপ্লিকেশনটি একবার লগ ইন করে এবং কিছু To-Do যোগ করলে এরকম দেখাবে:

আপনি একটি To-Do রিমুভ করতে পারেন এর পাশের বক্সে ক্লিক করে, সেটি removeTodo ফাংশনের জন্য 😉।
অভিনন্দন!
আশা করি এই ব্লগ পোস্ট পড়ে আপনি কিছু নতুন শিখেছেন, এবং যদি না শিখেন, মনে রাখবেন আপনার স্কিল ব্রাশ আপ করতে কোনো ক্ষতি নেই! Blitz.js ফোকাস Next.js-র থেকে দূরে নiyor, তাই ভবিষ্যতে এটি সম্পূর্ণ ভিন্ন একটি ফ্রেমওয়ার্ক হতে পারে, কিন্তু তাদের ওয়েবসাইট এখানে থেকে আপডেট থাকুন!
Project Source: GitHub Link
Working Demo: Demo Link
ফিডব্যাক আছে? নিশ্চিত করুন @upstash-কে Twitter-এ ফলো করেছেন, এবং Discord server-এ যোগ দিন!