استخدام MSW في SvelteKit
هذا برنامج تعليمي سيوضح لك كيفية تنفيذ مكتبة "Mock Service Worker" ، caleld MSW ، في تطبيق SvelteKit الخاص بك. يرجى ملاحظة أن هذا الدليل لا يوضح كيفية إعداد MSW مع Jest ، بل يوضح كيفية استخدام MSW أثناء التطوير المباشر.
التطبيق الكامل متاح في مستودع spikze.club ، الرابط أيضًا في الملحق في نهاية الصفحة.
لا تقلق إذا كان هذا الدليل قد يبدو ساحقًا في البداية ، فإن التغييرات بسيطة للغاية. يتطلب استخدام MSW في SvelteKit لمحاكاة الطلبات أثناء التطوير المحلي مزيدًا من الجهد.
تثبيت التبعيات
أولاً ، دعنا نثبت جميع التبعيات الضرورية.
npm i -D msw ts-node concurrently
نحن نستخدم "ts-node" أيضًا لبدء خادم mocks. قبل المتابعة ، يرجى الاتصال بالأمر التالي في جذر مشروع SvelteKit الخاص بك.
npx msw init ./static
سيؤدي هذا إلى إنشاء ملف جافا سكريبت باستخدام معالج عامل الخدمة الافتراضي بواسطة MSW. نحن نستخدم "ثابت" لتطبيق SvelteKit الخاص بنا ، لأنه مكافئ للدليل العام. أخيرًا ، دعنا نحدِّث ملف package.json-file بحيث يعرف MSW مكان البحث عن الملف.
{
"scripts": ...
...
"msw": {
"workerDirectory": "static"
}
}
كبرنامج نصي مناسب ، أضفت أيضًا الأمر التالي إلى "البرامج النصية" الخاصة بي - التكوين المطلوب إذا كنت ترغب في بدء تشغيل MSW عبر كل من العميل والخادم (للنسخ من جانب الخادم).
{
"scripts": {
"dev": "svelte-kit dev",
"dev:msw-server": "concurrently \"cd msw && ts-node server.ts\" \"npm run dev\"",
...
},
}
تحضير وحدات MSW
قبل أن نبدأ في كتابة التعليمات البرمجية الفعلية ، نحتاج إلى تحديد دليل العمل الجديد الخاص بنا لـ MSW في تكوين SvelteKit وكذلك Typescript-config. سنبدأ بملف Typescript.
{
"compilerOptions": {
...,
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"],
"$msw": ["src/msw"],
"$msw/*": ["src/msw/*"]
}
}
}
بعد ذلك ، لنقم بتحديث ملف SvelteKit-config.
import adapter from "@sveltejs/adapter-auto";
import preprocess from "svelte-preprocess";
import path from "path";
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),
kit: {
adapter: adapter(),
vite: {
...,
resolve: {
alias: {
$msw: path.resolve("./src/msw"),
$lib: path.resolve("./src/lib")
}
}
}
}
إضافة المراكب والمعالجات
حسنًا ، لقد انتهيت من الجزء الأول من الدليل! سنضيف الآن الكود الفعلي الذي يتم تنفيذه عند استخدام MSW. الرجاء ملاحظة أن هذا مثال بسيط ، لذلك أضفت ما هو ضروري لإنجاح كل شيء ، ولكن ليس أكثر.
كما قد تكون خمنت من التغييرات التي أجريناها على SvelteKit-config ، سيتم وضع جميع التعليمات البرمجية في دليل جديد يسمى "msw" ، والذي يوجد مباشرة في "src".
|- app/
|-- src/
|--- pages/
|--- msw/
|---- fixtures/
...
إليك رمز الوحدات التالية التي يجب إضافتها. يجب أن تكون قادرًا على نسخها ولصقها ببساطة ، يتم كتابة اسم الملف + مسار الدليل كتعليق في كل كتلة في الأعلى.
//
// app/src/msw/handlers.server.ts
//
import { rest } from "msw";
import { values } from "./fixtures/msw-demo";
export const handlers = [
// Here, you can mock absolute URL requests,
// e.g. to a database. For the current implementation,
// no data is mocked in this place.
//
// Note: This is also the place to mock absolute
// SSR-imports. Everything in 'handlers.workers.ts'
// is mocked client-side.
];
//
// app/src/msw/handlers.worker.ts
//
import { rest } from "msw";
import { values } from "./fixtures/msw-demo";
// Mock relative URLs that map to your
// routes' data endpoints. This mock only
// happens for client-side requests.
//
// Note that if you use shadow endpoints, this still works
// as the endpoint gets created by SvelteKit.
export const handlers = [
rest.get("/msw/demo/__data.json", (req, res, ctx) => {
return res(ctx.status(200), ctx.json({ values }));
})
];
//
// app/src/msw/server.ts
//
import { setupServer } from "msw/node";
import { handlers } from "./handlers.server";
export const server = setupServer(...handlers);
//
// app/src/msw/worker.ts
//
import { setupWorker } from "msw";
import { handlers } from "./handlers.worker";
export const worker = setupWorker(...handlers);
//
// app/src/msw/fixtures/msw-demo.ts
//
export const values = ["foo", "bar"];
//
// app/src/msw/index.ts
//
import { browser, dev } from "$app/env";
/**
* Lazy-inject the MSW handler
* so that no errors happen during
* build/runtime due to invalid
* imports from server/client.
*/
export async function inject() {
if (dev && browser) {
const { worker } = await import("../msw/worker");
// For live development, I disabled all warnings
// for requests that are not mocked. Change how
// you think it best fits your project.
return worker.start({ onUnhandledRequest: "bypass" }).catch(console.warn);
}
if (dev && !browser) {
const { server } = await import("../msw/server");
// Same as in worker-mock above.
return server.listen({ onUnhandledRequest: "bypass" });
}
}
بدء تشغيل MSW
يتمثل أحد التحديات عند استخدام MSW أثناء التطوير المباشر في أنه يتعين علينا التأكد من عدم وجود حالة سباق. يتعين علينا تحديد أمر التنفيذ ، وإلا فقد يصبح عامل الخدمة من MSW نشطًا بعد تقديم جميع الطلبات بالفعل.
لتحقيق هذا الهدف ، نقوم بتعديل ملف تخطيط الجذر الخاص بنا. نظرًا لأنه يتم تحميل هذا الملف لكل صفحة ، فإنه يعد مكانًا جيدًا لمنع أي عمليات تنفيذ أخرى حتى انتهاء MSW.
<script>
import "../app.css";
import { dev } from "$app/env";
// Loaded from .env.local, guide covers this
// step in a moment.
const isMswEnabled = dev && import.meta.env.VITE_MSW_ENABLED === "true";
// Flag to defer rendering of components
// until certain criteria are met on dev,
// e.g. MSW init.
let isReady = !isMswEnabled;
if (isMswEnabled) {
import("$msw")
.then((res) => res.inject())
.then(() => (isReady = true));
}
</script>
{#if isReady}
<slot />
{/if}
إضافة صفحة تجريبية
تعرض مقتطفات التعليمات البرمجية التالية محتويات لصفحتين تجريبيتين ونقطة النهاية المستخدمة في هذا البرنامج التعليمي.
<!-- app/src/routes/msw/index.svelte -->
<script>
import DisplayProse from "$lib/display/views/DisplayProse.svelte";
import ProminentDisplayTitle from "$lib/display/views/ProminentDisplayTitle.svelte";
import PageLayout from "$lib/layout/views/PageLayout.svelte";
import SectionLayout from "$lib/layout/views/SectionLayout.svelte";
</script>
<PageLayout>
<SectionLayout withContentTopSpacing withHeaderSpacing>
<ProminentDisplayTitle slot="header" color="primary">MSW Landing Page</ProminentDisplayTitle>
<DisplayProse>
<p>
This compoonent has no purpose other than being part of an MSW demo implementation. See <a
href="https://flaming.codes"
alt="Link to flaming.codes with blog posts">flaming.codes</a
> for more details.
</p>
<p>
This page doesn't fetch any data for shows how client-side fetches are mocked with MSW in
SvelteKit.
</p>
<p>Simply click the link below to access the page with data.</p>
<p>
<a href="/msw/demo" alt="Link to demo page with data">msw/demo</a>
</p>
</DisplayProse>
</SectionLayout>
</PageLayout>
<!-- app/src/routes/msw/demo.svelte -->
<script lang="ts">
import ProminentDisplayTitle from "$lib/display/views/ProminentDisplayTitle.svelte";
import PageLayout from "$lib/layout/views/PageLayout.svelte";
import SectionLayout from "$lib/layout/views/SectionLayout.svelte";
export let values: string[];
</script>
<PageLayout>
<SectionLayout withHeaderSpacing withContentTopSpacing>
<ProminentDisplayTitle slot="header" color="primary">MSW Demo</ProminentDisplayTitle>
<p>
This compoonent has no purpose other than being part of an MSW demo implementation. See <a
href="https://flaming.codes"
alt="Link to flaming.codes with blog posts">flaming.codes</a
> for more details.
</p>
<p>
Values: {values}
</p>
</SectionLayout>
</PageLayout>
//
// app/src/routes/msw/demo.ts
//
import type { RequestHandler } from "@sveltejs/kit";
// Just for demo purposes.
export const get: RequestHandler = async () => ({
status: 200,
body: {
values: ["production", "data", "not", "msw"]
}
});
إضافة متغير البيئة
نحن على وشك الانتهاء. ما هو مفقود هو إضافة علامة "VITE_MSW_ENABLED" إلى بيئتنا. نحن نستخدم ".env.local" كملفنا للاحتفاظ بالعلامة ، حيث سيستهلك Vite هذا ولن تتم إضافته إلى git.
VITE_MSW_ENABLED=true
تشغيل التطبيق
حسنًا ، كل شيء يجب أن يكون جاهزًا للاستخدام الآن! لتمكين السخرية من العميل ، ما عليك سوى التأكد من تعيين العلم. قم بتشغيل الأمر "dev" المشترك ثم لعمل محاكاة لطلبات العميل.
npm run dev
للسخرية أيضًا من الطلبات من جانب الخادم ، ما عليك سوى تشغيل الأمر الجديد الذي أضفناه في البداية.
npm run dev:msw-server
أنت الآن جاهز للسخرية من نقاط النهاية أثناء التطوير المحلي. كما هو مذكور في مثال الكود ، لا تتضمن هذه الصفحة التجريبية نماذج من جانب الخادم ، وإن كان كل شيء مُعدًا لها. هذا يعني أنه محليًا ، لا يتم تشغيل مكالمة MSW إلا إذا انتقلت من صفحة الفهرس الخاصة بالموقع التجريبي إلى الصفحة التجريبية الفعلية من خلال نقرة على الرابط.
لمحاكاة طلبات الخادم ، سيكون لديك نقاط نهاية أكثر تعقيدًا تجلب أيضًا البيانات من قواعد البيانات. يمكن بعد ذلك الاستهزاء بهذه الطلبات في معالج الخادم. لاحظ أنه بالنسبة لخوادم mocks ، تكون عناوين URL المطلقة فقط هي الصالحة.