Skip to content

Commit 0b9795c

Browse files
Copilotsj817
andcommitted
Add token setup page, deployment docs, and fix linting issues
- Created token-setup.html for easy testing with Personal Access Token - Added comprehensive DEPLOYMENT.md documentation - Updated index.html with proper metadata - Fixed ESLint errors - Verified build and linting passes Co-authored-by: sj817 <74231782+sj817@users.noreply.github.com>
1 parent 4a293a1 commit 0b9795c

File tree

5 files changed

+561
-6
lines changed

5 files changed

+561
-6
lines changed

web/DEPLOYMENT.md

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
# Karin 插件市场 - Web 应用部署指南
2+
3+
本文档详细说明如何部署和配置 Karin 插件市场 Web 应用。
4+
5+
## 目录
6+
7+
- [架构概述](#架构概述)
8+
- [GitHub OAuth 配置](#github-oauth-配置)
9+
- [部署到 GitHub Pages](#部署到-github-pages)
10+
- [本地开发](#本地开发)
11+
- [测试方法](#测试方法)
12+
- [常见问题](#常见问题)
13+
14+
## 架构概述
15+
16+
这个 Web 应用是一个基于 React 的静态单页应用(SPA),用于简化插件提交流程。主要功能包括:
17+
18+
1. **GitHub OAuth 登录** - 让用户通过 GitHub 账号登录
19+
2. **仓库选择** - 自动获取并展示用户的 GitHub 仓库
20+
3. **智能检测** - 自动勾选已提交的插件(基于 package.json 的 name 字段)
21+
4. **npm 验证** - 对于 npm 类型插件,验证包是否存在于 npm registry
22+
5. **类型支持** - 支持 npm 包和单 JS 文件(app 类型)
23+
24+
## GitHub OAuth 配置
25+
26+
### 步骤 1: 创建 GitHub OAuth App
27+
28+
1. 访问 GitHub Settings → Developer settings → OAuth Apps
29+
2. 点击 "New OAuth App"
30+
3. 填写以下信息:
31+
- **Application name**: Karin Plugin Marketplace
32+
- **Homepage URL**: `https://karinjs.github.io/plugins-list/`
33+
- **Authorization callback URL**: `https://karinjs.github.io/plugins-list/`
34+
4. 点击 "Register application"
35+
5. 记录下 **Client ID**
36+
37+
### 步骤 2: 配置环境变量
38+
39+
由于这是纯前端应用,Client ID 可以公开(但 Client Secret 必须保密)。
40+
41+
对于 GitHub Actions 自动部署,需要在仓库 Settings 中配置:
42+
43+
1. 进入仓库的 Settings → Secrets and variables → Actions
44+
2. 添加 Repository secret:
45+
- Name: `VITE_GITHUB_CLIENT_ID`
46+
- Value: 你的 GitHub OAuth App Client ID
47+
48+
### 步骤 3: OAuth 回调处理
49+
50+
**重要**: GitHub OAuth 需要后端服务来安全地交换 authorization code 为 access token,因为这个过程需要 Client Secret,不能暴露在前端。
51+
52+
有两种解决方案:
53+
54+
#### 方案 A: 使用无服务器函数(推荐)
55+
56+
使用 Cloudflare Workers、Vercel Functions 或 GitHub Actions 来处理 OAuth 回调:
57+
58+
```javascript
59+
// 示例 Cloudflare Worker
60+
export default {
61+
async fetch(request) {
62+
const url = new URL(request.url);
63+
const code = url.searchParams.get('code');
64+
65+
if (!code) {
66+
return new Response('Missing code', { status: 400 });
67+
}
68+
69+
// 使用 code 和 client_secret 交换 token
70+
const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
71+
method: 'POST',
72+
headers: {
73+
'Content-Type': 'application/json',
74+
'Accept': 'application/json',
75+
},
76+
body: JSON.stringify({
77+
client_id: process.env.GITHUB_CLIENT_ID,
78+
client_secret: process.env.GITHUB_CLIENT_SECRET,
79+
code: code,
80+
}),
81+
});
82+
83+
const tokenData = await tokenResponse.json();
84+
85+
// 返回 token 或重定向回应用
86+
return Response.redirect(`https://karinjs.github.io/plugins-list/?token=${tokenData.access_token}`);
87+
}
88+
}
89+
```
90+
91+
#### 方案 B: 使用 Personal Access Token(开发/测试)
92+
93+
对于开发和测试,可以使用 Personal Access Token:
94+
95+
1. 访问 https://github.com/settings/tokens
96+
2. 生成新的 token(classic)
97+
3. 选择 `repo``read:user` 权限
98+
4. 使用 `web/token-setup.html` 页面设置 token
99+
100+
## 部署到 GitHub Pages
101+
102+
### 自动部署(推荐)
103+
104+
仓库已配置 GitHub Actions 自动部署:
105+
106+
1. 提交代码到 `main` 分支或 `copilot/implement-github-login-feature` 分支
107+
2. GitHub Actions 会自动构建并部署到 GitHub Pages
108+
3. 访问 `https://karinjs.github.io/plugins-list/`
109+
110+
### 手动部署
111+
112+
```bash
113+
cd web
114+
npm install
115+
npm run build
116+
117+
# 部署 dist 目录到 gh-pages 分支
118+
# 或使用 gh-pages 包
119+
npm install -g gh-pages
120+
gh-pages -d dist
121+
```
122+
123+
### 配置 GitHub Pages
124+
125+
1. 进入仓库 Settings → Pages
126+
2. Source: Deploy from a branch
127+
3. Branch: `gh-pages` / `(root)`
128+
4. 点击 Save
129+
130+
## 本地开发
131+
132+
### 安装依赖
133+
134+
```bash
135+
cd web
136+
npm install
137+
```
138+
139+
### 配置环境变量
140+
141+
```bash
142+
cp .env.example .env
143+
# 编辑 .env 文件,填入 GitHub OAuth Client ID
144+
```
145+
146+
### 启动开发服务器
147+
148+
```bash
149+
npm run dev
150+
```
151+
152+
应用会在 `http://localhost:5173/plugins-list/` 上运行。
153+
154+
### 构建生产版本
155+
156+
```bash
157+
npm run build
158+
```
159+
160+
构建产物在 `dist` 目录。
161+
162+
### 预览生产构建
163+
164+
```bash
165+
npm run preview
166+
```
167+
168+
## 测试方法
169+
170+
### 方法 1: 使用 Token Setup 页面
171+
172+
1. 访问 `http://localhost:5173/plugins-list/token-setup.html`
173+
2. 按照页面指引获取 Personal Access Token
174+
3. 输入 token 并保存
175+
4. 自动跳转到主应用
176+
177+
### 方法 2: 手动设置 Token
178+
179+
1. 获取 Personal Access Token
180+
2. 在浏览器控制台执行:
181+
```javascript
182+
localStorage.setItem('github_token', 'YOUR_TOKEN');
183+
```
184+
3. 刷新页面
185+
186+
### 方法 3: 完整 OAuth 流程(需要后端服务)
187+
188+
配置好 OAuth callback 处理后,直接点击登录按钮即可。
189+
190+
## 功能验证清单
191+
192+
- [ ] 登录页面正确显示
193+
- [ ] GitHub OAuth 跳转正常
194+
- [ ] Token 设置后能正常登录
195+
- [ ] 能够获取用户仓库列表
196+
- [ ] 只显示包含 package.json 的仓库
197+
- [ ] 已提交的插件自动勾选
198+
- [ ] 可以选择/取消选择仓库
199+
- [ ] npm 包验证正常工作
200+
- [ ] app 类型插件不验证 npm
201+
- [ ] 提交后显示正确的结果
202+
203+
## 常见问题
204+
205+
### Q: 为什么登录后看不到任何仓库?
206+
207+
A: 可能的原因:
208+
1. Token 权限不足 - 确保 token 有 `repo` 权限
209+
2. 仓库没有 package.json - 应用只显示包含 package.json 的仓库
210+
3. API 请求失败 - 检查浏览器控制台是否有错误
211+
212+
### Q: 如何判断插件类型(npm vs app)?
213+
214+
A: 目前的实现:
215+
- 如果 package.json 中有 `main``module` 字段,视为 npm 包
216+
- 否则视为 app 类型(单 JS 文件)
217+
218+
您可以根据实际需求调整判断逻辑。
219+
220+
### Q: 如何处理 CORS 错误?
221+
222+
A:
223+
- GitHub API 和 npm registry 都支持 CORS
224+
- 如果遇到 CORS 问题,可能是:
225+
1. Token 格式错误
226+
2. API endpoint 错误
227+
3. 网络问题
228+
229+
### Q: 部署后 404 错误?
230+
231+
A: 检查:
232+
1. GitHub Pages 是否启用
233+
2. base URL 配置是否正确(`vite.config.js` 中的 `base` 字段)
234+
3. 是否正确部署到 `gh-pages` 分支
235+
236+
### Q: 如何更新已部署的应用?
237+
238+
A:
239+
1. 提交代码更改
240+
2. GitHub Actions 会自动重新部署
241+
3. 或手动运行 `npm run build``gh-pages -d dist`
242+
243+
## 安全注意事项
244+
245+
1. **永远不要**在前端代码中暴露 Client Secret
246+
2. **永远不要**将 Personal Access Token 提交到代码仓库
247+
3. 使用环境变量来管理敏感配置
248+
4. 定期轮换 Personal Access Token
249+
5. 限制 Token 的权限范围
250+
251+
## 性能优化
252+
253+
1. 懒加载组件
254+
2. 实现虚拟滚动(如果仓库很多)
255+
3. 缓存 API 响应
256+
4. 压缩构建产物
257+
258+
## 后续改进建议
259+
260+
1. 添加搜索和过滤功能
261+
2. 支持批量操作
262+
3. 添加插件详情预览
263+
4. 实现拖拽排序
264+
5. 添加插件统计信息
265+
6. 支持离线模式
266+
7. 添加单元测试和 E2E 测试
267+
8. 实现国际化(i18n)
268+
269+
## 技术栈
270+
271+
- React 19
272+
- Vite 7
273+
- GitHub API v3
274+
- npm Registry API
275+
- GitHub Pages
276+
277+
## 联系方式
278+
279+
如有问题或建议,请在 GitHub 仓库提交 Issue。

web/index.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html lang="zh-CN">
33
<head>
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>web</title>
7+
<meta name="description" content="Karin 插件市场 - 提交您的插件到 Karin 生态系统" />
8+
<meta name="keywords" content="Karin,插件,Plugin,GitHub,React" />
9+
<title>Karin 插件市场 - 插件提交</title>
810
</head>
911
<body>
1012
<div id="root"></div>

web/src/components/LoginPage.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState } from 'react';
22
import './LoginPage.css';
33

4-
const LoginPage = ({ onLogin }) => {
4+
const LoginPage = () => {
55
const [isLoading, setIsLoading] = useState(false);
66

77
const handleGitHubLogin = () => {

web/src/components/SubmissionPage.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ const SubmissionPage = ({ accessToken, user, onLogout }) => {
1717
const data = await response.json();
1818
const pluginNames = new Set(data.plugins.map(p => p.name));
1919
setExistingPlugins(pluginNames);
20-
} catch (error) {
21-
console.error('Failed to load existing plugins:', error);
20+
} catch (err) {
21+
console.error('Failed to load existing plugins:', err);
2222
}
2323
};
2424
loadExistingPlugins();
@@ -64,7 +64,7 @@ const SubmissionPage = ({ accessToken, user, onLogout }) => {
6464
packageJson: content,
6565
};
6666
}
67-
} catch (error) {
67+
} catch {
6868
// Repository doesn't have package.json or error occurred
6969
}
7070
return null;

0 commit comments

Comments
 (0)