在开发的过程中,需要与服务端对接,这个工作流程通常是前端-服务端协定协议,服务端根据协议开发接口,前端模拟协议进行开发内容。这个过程中前端需要模拟服务端数据,模拟服务端数据的过程就叫做Mock;常见的库是Mock Server Workder下面简称MSW;

补充知识:Next.js 使用React技术栈,支持服务端渲染(SSR)与前端渲染(CSR);

那么我们Mock数据的时候就要针对这2种情况进行mock;

MSW依然提供了2种平台下的mock方式,底层逻辑都是拦截对应平台http请求,然后模拟发送数据;

Handlers概念

Handlers 是模拟浏览器请求的返回值逻辑;类似于下面这样;

import { HttpResponse, http } from "msw"

const mocks = [
    http.get('http://api.example.com/user', () => { // 模拟获取用户数据
        return HttpResponse.json({
            id: '15d42a4d-1948-4de4-ba78-b8a893feaf45',
            firstName: 'John',
        })
    })
]

export default mocks;

浏览器

Mock数据

import { setupWorker } from 'msw/browser'; // 这是msw提供的浏览器端mock
import handlers from '../handlers'; 

export const setupMock = () => {
    setupWorker(...handlers).start();
 }

浏览器端mock记得要初始化一下 npx msw init <PUBLIC_DIR>; 由于浏览器端的原理是使用Server Worker来实现,所以要有一个Worker的执行文件,这个初始化动作就是配置了Worker的初始化文件。

在next.js入口启动mock

// app/layout.tsx
import { setupMock } from '../mock/setup';
...

setupMock(); // 启用mock
...

使用Mock数据

'use client' // 在next.js中使用到BOM、DOM等方法均要声明use client告知next.js这是使用在客户端的
import axios from 'axios'; // 选择使用axios是为了下面Node端的时候避免一个坑,下面介绍
import React from 'react';

async function getUser() {
  return (await axios.get('http://api.example.com/user')).data;
}

const Button:React.FC<{}> = ()=>{
	return <button onClick={getUser}>get user</button>; // 这里使用了onClick是浏览器事件,所以上面要声明use client
}

Node

mock数据

import { setupServer } from 'msw/node';
import handlers from '../handlers';

export const setupMock = () => {
    setupServer(...handlers).listen();
 }

在next.js入口启动mock

同浏览器中,不重复了

使用Mock数据

// app/page.tsx
import axios from 'axios'; 

async function getUser() {
  return (await axios.get('http://api.example.com/user')).data
}

export default async function Home() {
  const res = await getUser(); // Next.js 服务端渲染预先获取服务端数据
  const id = res.id;
  
  return <div>{id}</div>
}

注意,不要使用 Fetch API!mws 是通过拦截 Node 的 http/https module 实现 API Mocking 的,因此 Node 中原生支持的 fetch API 会 Mock 失败的。这里是借助axios解决这个问题


Next.js 方案总和

需要有一个中间文件来总和服务端于浏览器的情况,让业务开发不需要考虑环境的影响。

// 开发环境(development)下默认为 YES; 非开发环境下默认为 NO;
const { NODE_ENV, USE_MOCK = NODE_ENV === 'development' ? 'YES' : 'NO' } = process.env;

// 总和setupMock;判断当前的环境使用不同的mock方式
export async function setupMock() {
    if (USE_MOCK === 'YES') {
        const { setupMock } =
            typeof window !== 'undefined' ?
                await import('./setupBrower') : await await import('./setupNode');

        setupMock();
        console.log('MSW: OPEN')
    }
}

入口中使用

// app/layout.tsx
import { setupMock } from '../mock/setup';
...

await setupMock(); // 启用mock; 这里记得await 因为在上总和的部分使用了 import()按需加载所要的文件,所以要等待初始化结束
...

MSW的使用介绍与前端Mock数据的内容到此结束,谢谢观看;