MSW אין SvelteKit

ווי צו ינסטרומענט MSW פֿאַר היגע אַנטוויקלונג אין SvelteKit

ניצן MSW אין SvelteKit

דאָס איז אַ טוטאָריאַל וואָס וועט ווייַזן איר ווי צו ינסטרומענט די "מאָקק סערוויס וואָרקער" ביבליאָטעק, גערופן MSW, אין דיין SvelteKit אַפּלאַקיישאַן. ביטע טאָן אַז דער פירער קען נישט ווייַזן ווי צו שטעלן MSW מיט Jest, אָבער ווי צו נוצן MSW בעשאַס לעבן אַנטוויקלונג.

די פולשטענדיק ימפּלאַמענטיישאַן איז בנימצא אין די ריפּאַזאַטאָרי פון spikze.club, לינק אויך אין די אַדענדום אין די סוף פון די בלאַט.

צי ניט זאָרג אויב דער פירער קען זיין אָוווערוועלמינג אין ערשטער, די ענדערונגען זענען גאַנץ פּשוט. ניצן MSW אין SvelteKit צו רייצנ ריקוועס בעשאַס היגע אַנטוויקלונג נאָר ריקווייערז אַ ביסל מער מי.

ינסטאָלינג דיפּענדאַנסיז

ערשטער, לאָזן אונדז ינסטאַלירן אַלע נייטיק דיפּענדאַנסיז.

npm i -D msw ts-node concurrently

מיר נוצן "ts-node" צו אָנהייבן די סערווער מאַקס. איידער מיר גיינ ווייַטער, ביטע רופן די פאלגענדע באַפֿעל אין דער וואָרצל פון דיין 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 און נישט צוגעלייגט צו גיט.

VITE_MSW_ENABLED=true

לויפן די אַפּלאַקיישאַן

אָלרייט, אַלץ זאָל זיין גרייט צו נוצן איצט! צו געבן מאַקינג אויף דעם קליענט, נאָר ענשור אַז די פאָן איז באַשטימט. לויפן די פּראָסט "דעוו"-קאָמאַנד און צו רייצנ קליענט-זייַט ריקוועס.

npm run dev

צו רייצנ די סערווער זייַט ריקוועס, פשוט לויפן די נייַע באַפֿעל מיר צוגעגעבן אין די אָנהייב.

npm run dev:msw-server

איצט איר זענט גרייט צו רייצנ ענדפּאָינץ בעשאַס היגע אַנטוויקלונג. ווי אנגעוויזן אין די קאָד בייַשפּיל, דעם דעמאָ בלאַט טוט נישט אַרייַננעמען מאַקס אויף די סערווער זייַט, כאָטש אַלץ איז צוגעגרייט פֿאַר אים. דעם מיטל אַז לאָוקאַלי, די MSW-רופן טריגערד בלויז אויב איר נאַוויגירן פון די אינדעקס בלאַט פון די דעמאָ פּלאַץ צו די פאַקטיש דעמאָ בלאַט דורך אַ קליק אויף די לינק.

צו סימולירן סערווער ריקוועס, איר וועט האָבן מער קאָמפּליצירט ענדפּאָינץ וואָס אויך ברענגען דאַטן פֿון דאַטאַבייסיז. די ריקוועס קענען דעריבער זיין מאַקט אין די סערווער האַנדלער. באַמערקונג אַז פֿאַר די סערווער-מאָקס, בלויז אַבסאָלוט URL ס זענען גילטיק.