Last active
January 17, 2022 03:29
-
-
Save Lxxyx/bfb354781e2e491bc65cab795c351519 to your computer and use it in GitHub Desktop.
Hooks 3.0 RFC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* [RFC] Hooks Http 客户端 | |
* | |
* @author Lxxyx | |
* @version 1.0.0 | |
* | |
* 特性说明: | |
* 1. 支持 `Decorate` 语法,自动生成 Query/Params/Headers 参数 | |
* 2. 新增请求中间件 | |
* 3. 新增 `setupHttpClient` 方法,用于自定义客户端 | |
* 4. 支持 `withCredentials` | |
* 5. 【TBD】支持文件上传 | |
*/ | |
/** | |
* ICE 自定义请求客户端 | |
*/ | |
// app.ts | |
import { setupHttpClient } from '@midwayjs/rpc' | |
import { request } from 'ice' | |
setupHttpClient({ | |
fetcher: request, | |
baseUrl: '<API_URL>', | |
withCredentials: true, | |
}) | |
/** | |
* 请求中间件 | |
*/ | |
// 错误处理 | |
import { setupHttpClient } from '@midwayjs/rpc' | |
import { request } from 'ice' | |
const onError = async (ctx, next) => { | |
try { | |
await next() | |
} catch (error) { | |
if (error.code === '401') { | |
location.href = '/login' | |
} else { | |
alert(error.message) | |
} | |
} | |
} | |
setupHttpClient({ | |
fetcher: request, | |
middlewares: [onError] | |
}) | |
/** | |
* 文件上传 | |
*/ | |
// Server | |
export default Decorate( | |
Post(), | |
File('files'), | |
async () => { | |
const ctx = useContext() | |
console.log(ctx.files) | |
} | |
) | |
// Client | |
import upload from './api/upload' | |
const form = new FormData() | |
form.append('files', file) | |
await upload({ formData: form }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Decorate, Post, Validate } from '@midwayjs/hooks-core' | |
import { z } from 'zod' | |
/** | |
* Server | |
*/ | |
// src/api/index.ts | |
const query = z.object({ | |
pageSize: z.string(), | |
pageNumber: z.string(), | |
}) | |
const params = z.object({ id: z.string() }) | |
const headers = z.object({ token: z.string() }) | |
const body = z.array(z.number()) | |
export const getMembers = Decorate( | |
Post<{ | |
query: z.infer<typeof query> | |
params: z.infer<typeof params> | |
headers: z.infer<typeof headers> | |
}>('/:id/members'), | |
Validate({ query, params, headers, body }), | |
async (type: number) => { | |
const { query, params, headers } = useContext() | |
const prisma = usePrisma() | |
const members = await prisma.members.findMany({ | |
data: { | |
id: params.id, | |
pageSize: query.pageSize, | |
pageNumber: query.pageNumber, | |
token: headers.token, | |
type, | |
}, | |
}) | |
return { code: 200, data: members } | |
} | |
) | |
export const getMembersV2 = Decorate( | |
Post(), | |
Params(z.object({ id: z.string() })), | |
async () => {} | |
) | |
/** | |
* Client | |
*/ | |
// pages/dashboard.tsx | |
import { Suspense } from 'React' | |
import Loading from './Loading' | |
export default function App() { | |
return ( | |
<Dashboard> | |
<Suspense fallback={<Loading />}> | |
<Members /> | |
</Suspense> | |
</Dashboard> | |
) | |
} | |
// components/members.tsx | |
import { getMembers } from './api' | |
import { useRPC } from '@midwayjs/rpc' | |
export default function Members() { | |
const members = useRPC(() => | |
getMembers(ADMIN, { | |
query: { | |
pageSize: '10', | |
pageNumber: '1', | |
}, | |
params: { id: '1' }, | |
headers: { token: '123' }, | |
}) | |
) | |
return ( | |
<div> | |
{members.map((member) => ( | |
<div key={member.id}>{member.name}</div> | |
))} | |
</div> | |
) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type GlobExpression = string | |
type IgnoreHandler = (req: { url: string; [key: string]: any }) => boolean | |
type MidwayBundlerOptions = { | |
plugins?: any[] | |
devServer: { | |
// 命中的请求将由后端服务器处理,filter 存在时 include 选项将被忽略 | |
include?: GlobExpression[] | |
// 命中的请求将由前端服务器处理,filter 存在时 exclude 选项将被忽略 | |
exclude?: GlobExpression[] | |
// 返回 True 则交由后端处理,返回 false 则前端 devServer 处理 | |
filter?: IgnoreHandler | |
} | |
} | |
import { plugin } from '@midwayjs/hooks-bundler' | |
// use include & exclude | |
plugin.webpack({ | |
devServer: { | |
// 后端 Server 处理 | |
include: ['**/*.js'], | |
// 前端 Server 处理 | |
exclude: ['_vite/*'] | |
} | |
}) | |
// use filter | |
plugin.webpack({ | |
devServer: { | |
filter: (req) => { | |
return req.includes('/api') === 0 | |
}, | |
// filter 存在时,include 会被忽略 | |
include: ['**/*.js'], | |
// filter 存在时,exclude 会被忽略 | |
exclude: ['_vite/*'] | |
} | |
}) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* [RFC] 一体化新路由机制 | |
* | |
* @author Lxxyx | |
* @version 1.0.0 | |
* | |
* 特性说明: | |
* 1. 缩短路由长度,由基于文件系统路径生成路由变为基于函数名生成路由,公共前缀 /api | |
* 2. 支持指定路径 | |
* 3. 只支持 Decorate 语法 | |
* | |
* 优势: | |
* 1. 避免文件系统路径长度过长 | |
* 2. 可以支持 Params 传参,自定义路径等特殊需求 | |
* 3. 支持在单文件中存在多种触发器的情况 | |
* 4. 更简洁,最简单情况下,整个后端目录只需要 1 个文件就可以写 API,方便内嵌到前端框架中 | |
* | |
* 注: | |
* 1. 原有文件路由模式保留 | |
*/ | |
/** | |
* 路径生成机制,基于函数名生成路由 | |
*/ | |
// URL: /api/getArticle | |
export const getArticle = Decorate( | |
Get(), | |
async () => {} | |
) | |
// URL: /api/createArticle | |
export const createArticle = Decorate( | |
Post(), | |
async () => {} | |
) | |
/** | |
* export default 情况下,取文件名作为函数名生成路径 | |
*/ | |
// FILE: /api/login.ts | |
// URL: /api/login | |
export default Decorate( | |
All(), | |
async () => {} | |
) | |
/** | |
* 2. 支持指定路径 | |
*/ | |
// URL: /* | |
export const render = Decorate( | |
Get('/*'), | |
async () => {} | |
) | |
// URL: /updateProfile/:id | |
export const updateProfile = Decorate( | |
Put('/updateProfile/:id'), | |
Param<{ id: string }>(), | |
async () => {} | |
) | |
/** | |
* 单文件 + 多触发器 | |
*/ | |
export const render = Decorate( | |
Get('/*'), | |
async () => {} | |
) | |
export const timer = Decorate( | |
Timer({ | |
type: 'cron', | |
expression: '0 0 0 * * *', | |
}), | |
async () => {} | |
) | |
export const like = Decorate( | |
Mtop(), | |
async (id: number) => {} | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* [RFC] 一体化单测机制 | |
* | |
* @author Lxxyx | |
* @version 1.0.0 | |
* | |
* ✨ 特性: | |
* 1. 支持 Hooks 单元测试 | |
* | |
* 💥 Breaking Changes: | |
* 1. 移除 @midwayjs/hooks-testing-library | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment