रीमिक्स एक फुलस्टैक रिएक्ट फ्रेमवर्क होने का एक नया रूप है, जो मौजूदा वेब मानकों पर ध्यान केंद्रित करता है और फ्रंटएंड को बैकएंड के करीब से जोड़ता है। जब आप देखते हैं कि आपके रिएक्ट घटकों में डेटा लोड करना कितना आसान है या किसी फ़ॉर्म से सबमिट किए गए डेटा को कैसे संसाधित करना है, तो यह टाइट कपलिंग ताज़ी हवा का झोंका है।
इस लेख में हम डेटाबेस के रूप में Upstash Redis का उपयोग करके एक साधारण फ़ीचर फ़्लैग प्रबंधन प्रणाली बनाकर रीमिक्स की शक्ति को देखेंगे।
पूर्ण स्रोत कोड यहां पाया जा सकता है।
सेटअप
npx create-remix@latest
. चलाकर आपको एकदम नया रीमिक्स ऐप मिलेगा और अपना पसंदीदा परिनियोजन वातावरण चुनना। मैं वर्सेल के साथ गया लेकिन इस ट्यूटोरियल के लिए इससे कोई फर्क नहीं पड़ना चाहिए।
अपस्टैश रेडिस से आप दो तरीकों से जुड़ सकते हैं:पहला टीसीपी कनेक्शन के माध्यम से है जिसमें आप किसी भी मानक रेडिस क्लाइंट लाइब्रेरी का उपयोग कर सकते हैं जिसका आप उपयोग करते हैं। दूसरा Upstash के REST API के माध्यम से है। हम दूसरे विकल्प के साथ जा रहे हैं क्योंकि यह सभी सर्वर रहित वातावरण में उपलब्ध है, जैसे कि क्लाउडफ्लेयर वर्कर्स वातावरण जिसमें रीमिक्स को तैनात किया जा सकता है। Upstash में एक पैकेज है जो वास्तविक Redis कमांड की नकल करता है, जिससे यह जानना आसान हो जाता है कि किस फ़ंक्शन को कॉल करना है।
अब हमें अपने Upstash Redis डेटाबेस से जुड़ने के लिए आवश्यक दो पर्यावरण चरों को संग्रहीत करने के तरीके की आवश्यकता है। रीमिक्स डिवेलपमेंट env var सपोर्ट के साथ नहीं आता है, लेकिन इसे dotenv को डेवलपमेंट डिपेंडेंसी के रूप में जोड़कर पूरा किया जा सकता है।
npm add --save-dev dotenv
हमारे .env
. में फ़ाइल (जिसे .gitignore
में जोड़ा जाना चाहिए) ) हम Upstash Redis से जुड़ने के लिए आवश्यक दो env var सेट कर सकते हैं। @upstash/redis
पैकेज स्वचालित रूप से इनका पता लगाता है इसलिए हमारे कोड के भीतर जुड़ने की कोई आवश्यकता नहीं है। ये मान एक नया Redis डेटाबेस बनाने के बाद Upstash डैशबोर्ड में पाए जा सकते हैं।
UPSTASH_REDIS_REST_URL="https://..."
UPSTASH_REDIS_REST_TOKEN="..."
हमें अपना dev
अपडेट करना होगा dotenv env vars लेने के लिए स्क्रिप्ट। अन्य स्क्रिप्ट वही रह सकती हैं।
{
"scripts": {
"dev": "node -r dotenv/config node_modules/.bin/remix dev"
}
}
सुविधा डेटा संग्रहीत करना
फ़ीचर फ़्लैग अविश्वसनीय रूप से जटिल हो सकते हैं, आपके उपयोगकर्ता आधार के प्रतिशत के लिए रोलआउट योजनाओं के साथ, उपयोगकर्ताओं के विशिष्ट समूहों के लिए सक्षम किया गया है, लेकिन वे "चालू" और "बंद" के रूप में सरल भी हो सकते हैं। हम रेडिस द्वारा प्रदान किए जाने वाले हैश डेटा प्रकार का उपयोग करके अपने फीचर फ्लैग को स्टोर करेंगे। हमारा डेटा नीचे JSON जैसा दिखेगा, जहां "1" सक्षम/चालू और "0" अक्षम/बंद है"।
{
"chart": "1",
"graph": "0"
}
इस डेटा तक पहुंचने और उसमें हेरफेर करने के लिए हम रेडिस द्वारा प्रदान किए गए चार आदेशों/कार्यों का उपयोग करेंगे:
- सभी कुंजियों (सुविधाओं) और मानों (सक्षम/अक्षम) को पुनः प्राप्त करने के लिए hgetall।
- किसी विशिष्ट सुविधा ध्वज को सक्षम या अक्षम करने के लिए सेट करें।
- एक विशिष्ट सुविधा ध्वज को हटाने के लिए hdel।
- एक ही बार में कई लेकिन विशिष्ट फ़ीचर फ़्लैग मान प्राप्त करने के लिए।
प्रबंधन सुविधाएं
हम /features
. पर स्थित एक पेज का निर्माण करेंगे जो मौजूदा सुविधाओं को बनाने और प्रबंधित करने (सक्षम/अक्षम/हटाएं) का प्रभारी है। हम इस बारे में विस्तार से जानेंगे कि AddFeature
. क्या है और FeatureList
जब हम चर्चा करते हैं कि डेटा कैसे लोड किया जाए और फिर डेटा कैसे लिखा जाए।
// app/routes/features.tsx
export default function Features() {
return (
<div>
<h1>Features</h1>
<AddFeature />
<FeatureList />
</div>
);
}
डेटा लोडर
डेटा लोडर रीमिक्स में एक निर्यातित फ़ंक्शन है जिसका नाम loader
. है जो सर्वर पर चलता है और डेटा लौटाता है जो एक हुक के माध्यम से हमारे रिएक्ट घटक को उपलब्ध कराया जाता है।
हम फीचर फ्लैग बनाने और प्रबंधित करने के लिए एक पेज से शुरू कर रहे हैं, और इस मामले में हम सभी सुविधाओं को वापस करना चाहते हैं। उन्हें जोड़े की एक सरणी के रूप में लौटाया जाएगा:
[
["graph", true],
["chart", false]
]
टाइपस्क्रिप्ट प्रकार की परिभाषा से शुरू करते हुए, हम फिर loadAllFeatures
. नामक एक फ़ंक्शन देखेंगे जो hgetall
. का उपयोग करता है @upstash/redis
. से कार्य करें ।
import { Redis } from "@upstash/redis";
type LoaderData = {
features: Array<[string, boolean]>;
};
const loadAllFeatures = async () => {
const redis = Redis.fromEnv();
const data = await redis.hgetall("features");
const features: Array<[string, boolean]> = [];
for (let i = 0; i < data.length; i += 2) {
features.push([data[i], data[i + 1] === "1"]);
}
return features.sort((a, b) => {
if (a[0] > b[0]) return 1;
if (a[0] < b[0]) return -1;
return 0;
});
};
निर्यात किया गया loader
फ़ंक्शन स्वयं loadAllFeatures
. को कॉल करेगा फ़ंक्शन, रिएक्ट घटक में पारित होने वाली सुविधाओं को लौटाता है।
export const loader: LoaderFunction = async (): Promise<LoaderData> => {
// You would want to add authentication/authorization here
const features = await loadAllFeatures();
return { features };
};
हम इस रिएक्ट घटक के विवरण को बाद में कवर करेंगे, लेकिन यह दिखाने के लिए कि आप लोडर फ़ंक्शन से लौटाए गए डेटा तक कैसे पहुंचते हैं, आप useLoaderData
नामक रीमिक्स हुक का उपयोग करते हैं। ।
const FeatureList = () => {
const { features } = useLoaderData<LoaderData>();
return (
<ul>
{features.map(([feature, active]) => (
<li key={feature}>{/* coming soon */}</li>
))}
</ul>
);
};
फ़ॉर्म क्रियाएँ
हमने देखा है कि डेटा कैसे लोड किया जाता है, लेकिन इस स्तर पर हमारे फीचर फ्लैग डेटाबेस में वास्तव में कोई विशेषता नहीं है! यहां वह जगह है जहां फॉर्म क्रियाएं खेलती हैं। डेटा को रीमिक्स में action
. नाम के फंक्शन को एक्सपोर्ट करके प्रोसेस किया जाता है . बहुत कुछ loader
की तरह , यह सर्वर पर चलाया जाता है और यह आमतौर पर json
. देता है डेटा जिसे रिएक्ट घटक दूसरे हुक के माध्यम से एक्सेस कर सकता है, या यह ब्राउज़र को redirect
करने के लिए कह सकता है दूसरे पेज पर।
action
नीचे दिया गया फ़ंक्शन वास्तव में चार अलग-अलग प्रकार की क्रियाओं को संभालता है, एक सुविधा बनाता है, एक सुविधा को सक्षम / अक्षम करता है, और एक सुविधा को हटाता है। हम इसे एक switch
. के साथ संभालते हैं बयान जो तब उपयुक्त रेडिस फ़ंक्शन/कमांड को कॉल करता है।
export const action: ActionFunction = async ({ request }) => {
// You would want to add authentication/authorization here
const formData = await request.formData();
const feature = formData.get("feature") as string;
const action = formData.get("_action") as string;
if (!feature || feature.length === 0) {
// This isn't currently displayed in our component
return json({ error: "Please provide a feature" });
}
switch (action) {
case "create":
case "enable":
await redis.hset("features", { [feature]: 1 });
break;
case "disable":
await redis.hset("features", { [feature]: 0 });
break;
case "delete":
await redis.hdel("features", feature);
break;
}
return redirect("/features");
};
आप देखेंगे कि सफल होने पर, मैं उसी पृष्ठ पर रीडायरेक्ट करता हूं जिस पर उपयोगकर्ता वर्तमान में है। यह अनिवार्य रूप से loader
. को कॉल करते हुए एक पेज रीलोड को ट्रिगर करता है उपयोगकर्ता को जो प्रदर्शित किया जाता है उसे कार्य करना और अपडेट करना।
एक नया फीचर फ्लैग जोड़ने के लिए, AddFeature
घटक रीमिक्स Form
का उपयोग करेगा घटक जो हमने ऊपर देखे गए क्रिया समारोह में डेटा जमा करेगा। मैंने निर्दिष्ट किया है कि इसे post
. के माध्यम से सबमिट करना चाहिए विधि और replace
. भी प्रदान किया प्रॉप ताकि हर बार जब हम फीचर फ्लैग बनाते हैं तो यह ब्राउज़र के इतिहास में एक नया पेज नहीं जोड़ता।
const AddFeature = () => {
return (
<Form method="post" replace>
<input type="hidden" name="_action" value="create" />
<input type="text" name="feature" required placeholder="name" />
<button type="submit">Add</button>
</Form>
);
};
एक बार एक फीचर बन जाने के बाद, हम सभी मौजूदा फीचर फ्लैग दिखाना चाहेंगे ताकि उन्हें प्रबंधित किया जा सके। प्रत्येक फीचर फ्लैग वास्तव में दो रूपों को प्रदर्शित करता है:एक फीचर फ्लैग को सक्षम/अक्षम करने के लिए, और दूसरा इसे हटाने के लिए।
ध्यान दें कि दो छिपे हुए क्षेत्र हैं:_action
ताकि हमारी action
फ़ंक्शन जानता है कि हम सुविधा के लिए क्या करने का प्रयास कर रहे हैं, और feature
जो ध्वज का नाम भेजता है जिसे हम संशोधित करना चाहते हैं।
const FeatureList = () => {
const { features } = useLoaderData<LoaderData>();
return (
<ul>
{features.map(([feature, active]) => (
<li key={feature}>
<Form method="post" replace>
<input
type="hidden"
name="_action"
value={active ? "disable" : "enable"}
/>
<input type="hidden" name="feature" value={feature} />
<button type="submit" className="btn-naked">
{active ? "💪" : "🦾"}
</button>
</Form>
<span>{feature}</span>
<Form method="post" replace>
<input type="hidden" name="_action" value="delete" />
<input type="hidden" name="feature" value={feature} />
<button type="submit">Delete</button>
</Form>
</li>
))}
</ul>
);
};
सुविधाओं का उपयोग करना
हमारे Upstash Redis डेटाबेस में फीचर फ़्लैग्स हैं, लेकिन अच्छी बात यह है कि अगर हम इन फ़्लैग्स के आधार पर अपने ऐप में फंक्शनलिटी को चालू या बंद नहीं कर रहे हैं। हम hmget
. का उपयोग करके डेटाबेस से विशिष्ट सुविधाओं को लोड करने के लिए लोडर फ़ंक्शन का उपयोग करेंगे , और फिर इसे सही संरचना में लाने के लिए थोड़ा सा डेटा हेरफेर।
अगर हम लोड करना चाहते हैं ["chart", "graph", "fake"]
झंडे, रेडिस हमें लौटाएगा ["1", "0", null]
... ध्यान रखें कि यदि ध्वज मौजूद नहीं है, तो इसका मान null
होगा , जिसे मैं fake
. शामिल करके दिखाना चाहता था झंडा।
type LoaderData = {
features: Record<string, boolean>;
};
const loadFeatures = async (keys: Array<string>) => {
const data = await redis.hmget("features", ...keys);
const features = keys.reduce<Record<string, boolean>>((acc, key, index) => {
acc[key] = data[index] === "1";
return acc;
}, {});
return features;
};
export const loader: LoaderFunction = async (): Promise<LoaderData> => {
const features = await loadFeatures(["chart", "graph"]);
return { features };
};
अब हम रीमिक्स के useLoaderData
का उपयोग करके, फिर से अपने घटक में लोड किए गए डेटा तक पहुंच सकते हैं। अंकुश। फिर चुनें कि हमारी वेबसाइट की कार्यक्षमता कैसे बदलनी चाहिए, यह देखते हुए कि कोई फ़्लैग वर्तमान में सक्षम है या अक्षम है।
export default function Index() {
const { features } = useLoaderData<LoaderData>();
return (
<div>
<h1>Dashboard</h1>
{features.chart ? <h2>Chart</h2> : <h2>No Chart</h2>}
{features.graph ? <h2>Graph</h2> : <h2>No Graph</h2>}
</div>
);
}
निष्कर्ष
इस लेख में हमने देखा है कि रीमिक्स में एक साधारण फीचर फ्लैग सिस्टम बनाने के लिए अपस्टैश रेडिस का उपयोग कैसे करें, इसके डेटा लोडर का लाभ उठाकर और एक्शन सर्वर साइड फ़ंक्शंस बनाएं। ये हमें एक विशिष्ट पृष्ठ के बैकएंड और फ्रंटएंड को कसकर युग्मित रखने की अनुमति देते हैं, एक अलग ग्राफक्यूएल एपीआई स्थापित करने की आवश्यकता के बिना जल्दी से पुनरावृति करते हैं और फ्रंटएंड पर मानक फॉर्म सबमिशन इवेंट को ओवरराइड करते हैं। जैसा कि हमने देखा है कि रीमिक्स वेब मानकों पर निर्भर करता है कि फ़ॉर्म अपना डेटा कैसे सबमिट करते हैं।