reactjs - Cum să folosești msw cu Nextjs 13.2.1 (Eroare: Nu se poate accesa worker.start pe server.)
Integrez un API simulant care practic trimite un obiect de răspuns cu un set de mesaje care ar trebui să fie afișate în interfața utilizatorului (Chatbox) împreună cu numele de utilizator, poza utilizatorului și așa mai departe.
Am unele probleme la configurarea msw 1.1.0 cu Next JS 13.2.1 (Directorul aplicației experimental cu layout-uri) din cauza modificărilor care provoacă incompatibilități. Totuși, acesta este codul meu.
Codul meu este setat așa până acum
src/app/(user)/live-view/page.tsx :
import React from "react";
import ThreadPostList from "../../components/threadList";
import { worker } from '../../../mocks/browser';
if (process.env.NODE_ENV === 'development') {
worker.start();
}
async function getMessages() {
const response = await fetch("http://localhost:3000/api/messages");
// const data = await response.json();
return response;
}
async function LiveViewPage() {
const messages = await getMessages();
const convertedMessages = Object.keys(messages);
// console.log(convertedMessages, "ConvertedMessages");
Object.values(messages).forEach(val => console.log(val));
return (
<div className="border-t border-gray-200 py-4 divide-y divede-gray-200">
<ThreadPostList />
</div>
);
}
export default LiveViewPage;
Și API-ul meu mock Msw este sub
src/mocks/handler.ts :
import { rest } from "msw";
import { UserWithMessages } from "./types";
const mockData: UserWithMessages[] = [
{
user: {
id: "user1",
name: "John Doe",
profilePic: "https://example.com/user1.jpg",
},
messages: [
{
id: "msg1",
senderId: "user1",
text: "Hey, how are you?",
createdAt: new Date("2022-01-01T12:00:00Z"),
},
{
id: "msg2",
senderId: "user1",
text: "Did you get my email?",
createdAt: new Date("2022-01-02T12:00:00Z"),
},
],
},
{
user: {
id: "admin",
name: "Admin",
profilePic: "https://example.com/admin.jpg",
},
messages: [],
},
];
export const handlers = [
rest.get<UserWithMessages[]>("/api/messages", (req, res, ctx) => {
return res(ctx.status(200), ctx.json(mockData));
}),
];
Și în sfârșit fișierul meu browser.ts este aici
src/mocks/browser.ts
"use client"
import { setupWorker } from 'msw';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);
când pornesc serverul, apare o eroare
Eroare: Nu se poate accesa worker.start pe server. Nu puteți utiliza punctul pentru un modul client dintr-un component de server. Puteți doar să transmiteți numele importat mai departe.
Unde și cum îmi pornesc worker-ul? Trebuie să creez un fișier în folderul mocks și să apelez serverul acolo și să import acel component în page.tsx-ul meu? Orice ajutor ar fi apreciat, mulțumesc
Răspuns #1
Am întâmpinat dificultăți în a face Mock Service Worker să ruleze constant cu NextJS în cadrul structurii de directoare a aplicației de când a devenit versiune stabilă. Am avut un anumit nivel de succes, dar bănuiesc că nu este soluția ideală. Încă așteptăm un exemplu legitim de implementare din partea echipei NextJS.
Nu putem apela lucrătorul pe un component redat de server din cauza exact a erorii pe care o vedeți. În schimb, mi-am mutat apelurile fetch într-un serviciu comun care este doar TypeScript:
./services/api-service.ts :
async function initMocks() {
if (typeof window === 'undefined') {
const { server } = await import('./src/mocks/server')
await server.listen({ onUnhandledRequest: 'bypass' })
} else {
const { worker } = await import('./src/mocks/browser')
await worker.start({ onUnhandledRequest: 'bypass' })
}
}
// Note the change in ENV var name here
// https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#bundling-environment-variables-for-the-browser
if (process.env.NEXT_PUBLIC_MOCK_APIS === 'enabled') {
initMocks()
}
export const makeApiRequest = async (path: string) => {
try {
const resp = await fetch(path)
if (resp.ok) {
const result = await resp.json()
return result
}
} catch (err: any) {
// handle errors
}
}
Nu știu de ce, dar implementarea MSW la un nivel mai jos astfel, și în afara unui component React propriu-zis, a avut mai mult succes pentru mine decât încercarea de a-l inițializa la nivel de pagină sau layout, așa cum este implementat în exemplele din directorul de pagini NextJS.
Acest lucru ar schimba componenta paginii tale să arate mai mult așa în partea de sus:
src/app/(user)/live-view/page.tsx :
import React from "react";
import ThreadPostList from "../../components/threadList";
import { makeApiRequest} from './services/api-service';
async function getMessages() {
const response = await makeApiRequest("http://localhost:3000/api/messages");
return response;
}
Un alt lucru pe care îl observ aici este că handler-ul tău prinde pe un path relativ, ceea ce ar putea să provoace probleme și pe partea serverului. Handler-ul serverului nu are contextul unui URL rădăcină și am avut mai mult succes fie cu path-uri complete, fie cu potrivirea path-ului. Deci fie:
export const handlers = [
rest.get<UserWithMessages[]>("http://localhost:3000/api/messages", (req, res, ctx) => {
return res(ctx.status(200), ctx.json(mockData));
}),
];
sau :
export const handlers = [
rest.get<UserWithMessages[]>("*/api/messages", (req, res, ctx) => {
return res(ctx.status(200), ctx.json(mockData));
}),
];
Ultimul ar putea fi util dacă vrei să folosești MSW pentru a rula teste Jest sau ceva într-un mediu implementat sau undeva altundeva decât pe mașina ta.
Din punct de vedere tehnic, în problema ta și în orice aplicație care urmează cele mai bune practici descrise în documentația NextJS, nu am avea deloc nevoie de implementarea MSW în browser, deoarece toate datele ar fi preluate în componentele serverului și folosite pentru a hidrata clientul. Totuși, am lăsat-o aici pentru a oferi un anumit grad de consistență atunci când se face comparația cu implementările anterioare.
În momentul în care am scris asta, lucrez cu [email și [email
