Jelajahi Sumber

✨ feat(api): add swagger ui for api documentation
- 集成 @hono/swagger-ui 提供可视化 api 文档界面
- 添加 /ui 路由用于访问 swagger 文档
- 自定义 swagger ui 样式和脚本,设置文档地址为 /doc

♻️ refactor(server): optimize development environment api loading
- 使用 vite.ssrLoadModule 替代原生 import 加载开发环境 api
- 重构 api 路由导出方式,通过 Hono 实例组合路由

🔧 chore(dev): update development configuration
- 修改 dev 脚本使用 node 直接运行 server.js 替代 tsx
- 配置 react 插件支持 tsDecorators

⚡️ perf(react): enable ts decorators support
- 在 react 插件中开启 tsDecorators 选项提升类型检查性能

yourname 7 bulan lalu
induk
melakukan
beb16adead
4 mengubah file dengan 39 tambahan dan 11 penghapusan
  1. 1 1
      package.json
  2. 9 8
      server.js
  3. 26 1
      src/server/api.ts
  4. 3 1
      vite.config.ts

+ 1 - 1
package.json

@@ -4,7 +4,7 @@
   "version": "0.0.0",
   "type": "module",
   "scripts": {
-    "dev": "PORT=8080 tsx server",
+    "dev": "PORT=8080 node server",
     "build": "npm run build:client && npm run build:server",
     "build:client": "vite build --outDir dist/client --manifest",
     "build:server": "vite build --ssr src/server/index.tsx --outDir dist/server",

+ 9 - 8
server.js

@@ -35,14 +35,6 @@ const parentServer = serve({
 //   templateHtml = await fs.readFile('./dist/client/index.html', 'utf-8');
 // }
 
-if (!isProduction) {
-  const api = (await import('./src/server/api.ts')).default
-  app.route('/', api);
-}else{
-  const api = (await import('./dist/api/api.js')).default
-  app.route('/', api);
-}
-
 // 生产环境中间件
 let compressionMiddleware;
 let sirvMiddleware;
@@ -81,6 +73,15 @@ if (!isProduction) {
   });
 }
 
+if (!isProduction) {
+  // 使用 vite.ssrLoadModule 替代原生 import
+  const apiModule = await vite.ssrLoadModule('./src/server/api.ts');
+  app.route('/', apiModule.default);
+}else{
+  const api = (await import('./dist/api/api.js')).default
+  app.route('/', api);
+}
+
 // 将请求处理逻辑适配为 Hono 中间件
 app.use(async (c, next) => {
   try {

+ 26 - 1
src/server/api.ts

@@ -1,11 +1,14 @@
 import { OpenAPIHono } from '@hono/zod-openapi'
+import { swaggerUI } from '@hono/swagger-ui'
 import { errorHandler } from './utils/errorHandler'
 import usersRouter from './api/users/index'
 import authRoute from './api/auth/index'
 import rolesRoute from './api/roles/index'
 import { AuthContext } from './types/context'
 import { AppDataSource } from './data-source'
+import { Hono } from 'hono'
 
+const app = new Hono();
 const api = new OpenAPIHono<AuthContext>()
 
 api.onError(errorHandler)
@@ -46,6 +49,27 @@ if(!import.meta.env.PROD){
     }]
     // servers: [{ url: '/api/v1' }]
   })
+
+  app.get('/ui', swaggerUI({
+    url: '/doc',
+    persistAuthorization: true,
+    manuallySwaggerUIHtml: (asset) => `
+      <div>
+        <div id="swagger-ui"></div>
+        <link rel="stylesheet" href="https://ai-oss.d8d.fun/swagger-ui-dist/swagger-ui.css" />
+        <script src="https://ai-oss.d8d.fun/swagger-ui-dist/swagger-ui-bundle.js" crossorigin="anonymous"></script>
+        <script>
+          window.onload = () => {
+            window.ui = SwaggerUIBundle({
+              dom_id: '#swagger-ui',
+              url: '/doc',
+              persistAuthorization: true
+            })
+          }
+        </script>
+      </div>
+    `
+  }))
 }
 
 
@@ -58,4 +82,5 @@ export type AuthRoutes = typeof authRoutes
 export type UserRoutes = typeof userRoutes
 export type RoleRoutes = typeof roleRoutes
 
-export default api
+app.route('/', api)
+export default app

+ 3 - 1
vite.config.ts

@@ -5,7 +5,9 @@ import tailwindcss from '@tailwindcss/vite'
 // https://vite.dev/config/
 export default defineConfig({
   plugins: [
-    react(),
+    react({
+      tsDecorators: true,
+    }),
     tailwindcss(),
   ],
   server: {