MSW használata a SvelteKitben
Ez egy oktatóanyag, amely megmutatja, hogyan kell megvalósítani a „Mock Service Worker” könyvtárat, az MSW-t a SvelteKit alkalmazásban. Kérjük, vegye figyelembe, hogy ez az útmutató nem azt mutatja be, hogyan kell beállítani az MSW-t a Jest-tel, hanem azt, hogyan kell használni az MSW-t élő fejlesztés során.
A teljes megvalósítás elérhető a spikze.club tárházában, link is az oldal végén található mellékletben.
Ne aggódjon, ha ez az útmutató elsőre elsöprőnek tűnik, a változtatások meglehetősen egyszerűek. Az MSW használata a SvelteKitben a kérések kigúnyolására a helyi fejlesztés során csak egy kis erőfeszítést igényel.
Függőségek telepítése
Először telepítsük az összes szükséges függőséget.
npm i -D msw ts-node concurrently
A „ts-node”-ot használjuk a szerver-mockok elindításához is. Mielőtt folytatnánk, kérjük, hívja a következő parancsot a SvelteKit-projekt gyökerében.
npx msw init ./static
Ez létrehoz egy Javascript-fájlt az MSW alapértelmezett service worker kezelőjével. A SvelteKit-alkalmazásunkhoz „static”-ot használunk, mivel ez a nyilvános könyvtár megfelelője. Végül frissítsük a package.json-fájlt, hogy az MSW tudja, hol keresse a fájlt.
{
"scripts": ...
...
"msw": {
"workerDirectory": "static"
}
}
Kényelmes szkriptként a következő parancsot is hozzáadtam a „scripts” konfigurációmhoz, amely akkor szükséges, ha az MSW-t kliensen és szerveren keresztül is el akarjuk indítani (szerveroldali mockokhoz).
{
"scripts": {
"dev": "svelte-kit dev",
"dev:msw-server": "concurrently \"cd msw && ts-node server.ts\" \"npm run dev\"",
...
},
}
MSW-modulok előkészítése
Mielőtt elkezdenénk írni a tényleges kódot, meg kell határoznunk az MSW új munkakönyvtárát a SvelteKit konfigurációjában, valamint a Typescript-configban. Kezdjük a Typescript-fájllal.
{
"compilerOptions": {
...,
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"],
"$msw": ["src/msw"],
"$msw/*": ["src/msw/*"]
}
}
}
Ezután frissítsük a SvelteKit-config-ot.
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")
}
}
}
}
A gúnyok és kezelők hozzáadása
Rendben, túljutott az útmutató első részén! Most hozzáadjuk a tényleges kódot, amely az MSW használatakor végrehajtódik. Kérjük, vegye figyelembe, hogy ez egy minimális példa, ezért hozzáadtam azt, ami szükséges ahhoz, hogy minden működjön, de nem többet.
Ahogy azt a SvelteKit-config módosításaiból sejthettük, minden kód egy új „msw” nevű könyvtárba kerül, amely közvetlenül az „src”-ben található.
|- app/
|-- src/
|--- pages/
|--- msw/
|---- fixtures/
...
Itt található a következő hozzáadandó modulok kódja. Egyszerűen másolni-beilleszteni kell őket, a fájlnév + a könyvtár elérési útja minden blokkban megjegyzésként fel van írva felül.
//
// 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 indítása
Az egyik kihívás az MSW használata során az élő fejlesztés során, hogy meg kell győződnünk arról, hogy nincs versenyfeltétel. Meg kell határoznunk a végrehajtási sorrendet, különben az MSW szervizmunkása akkor válhat aktívvá, ha már minden kérés megtörtént.
E cél elérése érdekében módosítjuk a gyökérelrendezési fájlunkat. Mivel ez a fájl minden oldalhoz fel van csatolva, jó hely a további végrehajtás blokkolására, amíg az MSW be nem fejeződik.
<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}
Demo oldal hozzáadása
A következő kódrészletek egyszerűen csak két bemutatóoldal és az ebben az oktatóanyagban használt végpont tartalmát jelenítik meg.
<!-- 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"]
}
});
Környezeti változó hozzáadása
majdnem készen vagyunk. Ami hiányzik, az az, hogy hozzáadjuk a „VITE_MSW_ENABLED” jelzőt a környezetünkhöz. A „.env.local” fájlt használjuk a zászló tárolására, mivel ezt a Vite felhasználja, és nem adja hozzá a git-hez.
VITE_MSW_ENABLED=true
Az alkalmazás futtatása
Rendben, most minden készen áll a használatra! Az ügyfél gúnyolásának engedélyezéséhez egyszerűen győződjön meg arról, hogy a zászló be van állítva. Futtassa a gyakori „dev” parancsot, majd a kliensoldali kérések kijátszásához.
npm run dev
A szerveroldali kérelmek megcsúfolásához egyszerűen futtassa az új parancsot, amelyet az elején hozzáadtunk.
npm run dev:msw-server
Most már készen áll arra, hogy kigúnyolja a végpontokat a helyi fejlesztés során. Amint azt a kódpéldában is megjegyeztük, ez a bemutató oldal nem tartalmaz szerveroldali modelleket, bár minden felkészült rá. Ez azt jelenti, hogy helyileg az MSW-hívás csak akkor indul el, ha a bemutató oldal indexoldaláról a hivatkozásra kattintva a tényleges bemutató oldalra navigál.
A kiszolgálókérések szimulálásához bonyolultabb végpontokkal kell rendelkeznie, amelyek szintén lekérik az adatokat az adatbázisokból. Ezeket a kéréseket ezután meg lehet gúnyolni a szerverkezelőben. Ne feledje, hogy a szerver-mockeknél csak az abszolút URL-ek érvényesek.