1. 创建react项目
使用 create-react-app 创建项目
npx create-react-app react-mock
执行 eject 命令
npm run eject
删除 package.json 文件中的 eslintconfig 选项
2. 安装依赖包
npm i path-to-regexp fast-glob chokidar axios
3. 创建中间件
在 config 文件夹中创建 webpackmiddlewaremock.js 文件
让webpack-dev-server加载中间件,把mock配置文件的请求地址和响应数据映射到dev server的路由上
const { pathtoregexp } = require("path-to-regexp"); const fg = require("fast-glob"); const path = require("path"); const chokidar = require("chokidar"); const valid_methods = [ "get", "post", "put", "delete", "patch", "head", "options", ]; const default_method = "get"; const mock_file_pattern = "mock/**/*.{js,ts}"; const default_options = { rootdir: "", exclude: [], }; class webpackmiddlewaremock { constructor(options = {}) { this.options = { ...default_options, ...options }; const { rootdir, exclude } = this.options; this.mockconfigs = this.getconfigs(rootdir, exclude); } parsemockkey(key) { const keyitems = key.split(/\s+/); if (keyitems.length === 1) { return { method: default_method, path: keyitems[0], }; } else { const [method, path] = keyitems; const uppercasemethod = method.tolocaleuppercase(); if (!valid_methods.includes(uppercasemethod)) { console.error(`method ${method} is not supported`); } if (!path) { console.error(`${key} path is not defined`); } return { method, path, }; } } getconfigs(rootdir, exclude) { const ignore = exclude.map( (ele) => `mock${ele.startswith("/") ? "" : "/"}${ele}` ); const mockfiles = fg .sync(mock_file_pattern, { cwd: rootdir, ignore, }) .map((file) => path.join(rootdir, file)); const mockconfigs = []; mockfiles.foreach((mockfile) => { // disable require cache delete require.cache[mockfile]; let mockmodule; try { mockmodule = require(mockfile); } catch (error) { console.error(`failed to parse mock file ${mockfile}`); console.error(error); return; } const config = mockmodule.default || mockmodule || {}; for (const key of object.keys(config)) { const { method, path } = this.parsemockkey(key); const handler = config[key]; if ( !( typeof handler === "function" || typeof handler === "object" || typeof handler === "string" ) ) { console.error( `mock value of ${key} should be function or object or string, but got ${typeof handler}` ); } mockconfigs.push({ method, path, handler, }); } }); return mockconfigs; } matchpath(req, mockconfigs) { for (const mockconfig of mockconfigs) { const keys = []; if (req.method.tolocaleuppercase() === mockconfig.method) { const re = pathtoregexp(mockconfig.path, keys); const match = re.exec(req.path); if (re.exec(req.path)) { return { keys, match, mockconfig, }; } } } } decodeparam(val) { if (typeof val !== "string" || val.length === 0) { return val; } try { return decodeuricomponent(val); } catch (error) { if (error instanceof urierror) { error.message = `failed to decode param ' ${val} '`; error.status = 400; error.statuscode = 400; } throw error; } } createwatch() { const watchdir = this.options.rootdir; const watcher = chokidar .watch(watchdir, { ignoreinitial: true, ignored: [/node_modules/], }) .on("all", () => { const { rootdir, exclude } = this.options; this.mockconfigs = this.getconfigs(rootdir, exclude); }); return watcher; } createmiddleware() { const middleware = (req, res, next) => { const matchresult = this.matchpath(req, this.mockconfigs); if (matchresult) { const { match, mockconfig, keys } = matchresult; const { handler } = mockconfig; if (typeof handler === "function") { const params = {}; for (let i = 1; i < match.length; i += 1) { const key = keys[i - 1]; const prop = key.name; const val = this.decodeparam(match[i]); if (val !== undefined) { params[prop] = val; } } req.params = params; handler(req, res, next); return; } else { return res.status(200).json(handler); } } else { next(); } }; this.createwatch(); return { name: "mock", middleware: middleware, }; } static use(options) { const instance = new webpackmiddlewaremock(options); const middleware = instance.createmiddleware(); return middleware; } } module.exports = webpackmiddlewaremock;
4. 修改webpackdevserver
修改 config/webpackdevserver.config.js 文件
引入 webpackmiddlewaremock 中间件
const webpackmiddlewaremock = require("./webpackmiddlewaremock");
删除 onbeforesetupmiddleware 和 onaftersetupmiddleware 选项,替换 setupmiddlewares 选项
setupmiddlewares: (middlewares, devserver) => { const mockmiddleware = webpackmiddlewaremock.use({ rootdir: paths.apppath, }); middlewares.unshift(mockmiddleware); return middlewares; },
在项目根目录创建 mock 文件夹,并创建 user.js 文件
module.exports = { // 返回值是 string 类型 "get /api/name": "tom", // 返回值 array 类型 "post /api/users": [ { name: "foo", id: 0 }, { name: "bar", id: 1 }, ], "get /api/users/:id": (req, res) => { res.send({ params: req.params, }); }, // 返回值是 object 类型 "delete /api/users/1": { name: "bar", id: 1 }, };
5. 测试mock请求
修改 app.js 文件
import { usestate } from "react"; import axios from "axios"; function app() { const [resultget, setresultget] = usestate(""); const [resultpost, setresultpost] = usestate(""); const [resultparams, setresultparams] = usestate(""); const [resultdelete, setresultdelete] = usestate(""); const handleget = async () => { const res = await axios.get("/api/name"); setresultget(res.data); }; const handlepost = async () => { const res = await axios.post("/api/users"); setresultpost(json.stringify(res.data)); }; const handleparams = async () => { const res = await axios.get("/api/users/100"); setresultparams(json.stringify(res.data)); }; const handledelete = async () => { const res = await axios.delete("/api/users/1"); setresultdelete(json.stringify(res.data)); }; return ( <div classname="app"> <button onclick={handleget}>"get /api/name"</button> <h2>{resultget}</h2> <hr /> <button onclick={handlepost}>"post /api/users"</button> <h2>{resultpost}</h2> <hr /> <button onclick={handleparams}>"get /api/users/:id"</button> <h2>{resultparams}</h2> <hr /> <button onclick={handledelete}>"delete /api/users/1"</button> <h2>{resultdelete}</h2> <hr /> </div> ); } export default app;
启动项目测试
到此这篇关于在react项目中让webpack使用mock数据的文章就介绍到这了,更多相关react项目webpack使用mock数据内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论