uniky 1.0.17 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniky",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "uni-app 开发工具库,包含 hooks、http 请求和 vite 插件",
5
5
  "type": "module",
6
6
  "main": "./src/lib/index.ts",
@@ -0,0 +1,113 @@
1
+ # UniKy 插件系统
2
+
3
+ 该目录包含 UniKy 框架的自动代码生成插件。
4
+
5
+ ## 插件列表
6
+
7
+ ### 1. global.defined.ts - 全局定义插件
8
+
9
+ 自动收集 `src/_unikey/global` 文件夹下的所有导出内容,生成全局类型定义和安装文件。
10
+
11
+ ### 2. pages.defined.ts - 页面路由插件
12
+
13
+ 自动处理页面路由相关的代码生成。
14
+
15
+ ### 3. http.defined.ts - HTTP 请求代码生成插件
16
+
17
+ 基于 OpenAPI 规范自动生成类型安全的 HTTP 请求函数。
18
+
19
+ ## HTTP 插件使用说明
20
+
21
+ ### 工作原理
22
+
23
+ 1. 插件会读取项目中的 OpenAPI 规范文件(支持多个位置)
24
+ 2. 解析所有 API 路径和方法
25
+ 3. 自动生成对应的请求函数
26
+ 4. 生成的代码保存到 `src/_unikey/global/ky.ts`
27
+
28
+ ### OpenAPI 文件位置
29
+
30
+ 插件会按以下顺序查找 OpenAPI 规范文件:
31
+
32
+ 1. `.uniky/oas/openapi.json`(推荐)
33
+ 2. `openapi.json`
34
+ 3. `swagger.json`
35
+ 4. `api-docs.json`
36
+
37
+ ### 生成规则
38
+
39
+ **路径命名转换:**
40
+ - `/api/sys.account/login` → `apiSysAccountLogin()`
41
+ - `/api/util.tool/upload` → `apiUtilToolUpload()`
42
+
43
+ **请求方法:**
44
+ - GET/DELETE 请求:`functionName(params?: any)`
45
+ - POST/PUT/PATCH 请求:`functionName(data?: any, params?: any)`
46
+
47
+ ### 生成的代码结构
48
+
49
+ ```typescript
50
+ // 1. uniKy 实例配置
51
+ export const _ky = uniKy.create({
52
+ prefixUrl: baseUrl,
53
+ hooks: { ... },
54
+ timeout: 30000
55
+ });
56
+
57
+ // 2. useKyData Hook
58
+ export function useKyData<T, O extends object = {}>(...)
59
+
60
+ // 3. API 请求函数
61
+ export function apiSysAccountLogin(data?: any, params?: any) {
62
+ return _ky.post('/api/sys.account/login', { data, params })
63
+ .then(res => res.data);
64
+ }
65
+ ```
66
+
67
+ ### 使用示例
68
+
69
+ ```typescript
70
+ // 直接调用
71
+ import { apiSysAccountLogin } from '@/_unikey/global/ky';
72
+
73
+ await apiSysAccountLogin({ username: 'admin', password: '123456' });
74
+
75
+ // 使用 Hook
76
+ import { useKyData, apiPitfallIndexQuery } from '@/_unikey/global/ky';
77
+
78
+ const { data, run } = useKyData(apiPitfallIndexQuery, []);
79
+ ```
80
+
81
+ ### 重新生成代码
82
+
83
+ 插件会在以下情况自动重新生成代码:
84
+
85
+ 1. 项目启动时(如果文件不存在)
86
+ 2. OpenAPI 规范文件发生变化时
87
+
88
+ 如果需要手动触发重新生成,删除 `src/_unikey/global/ky.ts` 文件后重启开发服务器。
89
+
90
+ ### 配置选项
91
+
92
+ 在 `vite.config.ts` 中配置插件:
93
+
94
+ ```typescript
95
+ import { unikyPlugin } from './.uniky/index';
96
+
97
+ export default defineConfig({
98
+ plugins: [
99
+ uni(),
100
+ unikyPlugin({
101
+ enablePages: true, // 启用页面插件
102
+ enableGlobal: true, // 启用全局定义插件
103
+ enableHttp: true // 启用 HTTP 插件(默认启用)
104
+ })
105
+ ]
106
+ });
107
+ ```
108
+
109
+ ### 注意事项
110
+
111
+ 1. **文件保护**:如果 `ky.ts` 文件已存在,插件不会覆盖,需手动删除后才会重新生成
112
+ 2. **路径格式**:OpenAPI 中的路径需要符合 RESTful 规范
113
+ 3. **自动导入**:生成的函数可以通过全局定义系统自动导入使用
@@ -1,5 +1,5 @@
1
1
  // 该插件用于作为 vite.config.ts 中 作为插件;
2
- // 该插件用于收集 src/.uniky/global文件夹下的ts文件 所有export 导出的内容, 并将其合并为一个全局定义文件 src/.uniky/global.d.ts 文件 同时,生成一个 /src/.uniky/global.install.ts 文件.
2
+ // 该插件用于收集 src/_unikey/global文件夹下的ts文件 所有export 导出的内容, 并将其合并为一个全局定义文件 src/_unikey/global.d.ts 文件 同时,生成一个 /src/_unikey/global.install.ts 文件.
3
3
  // 以便在项目中全局使用这些类型定义,避免了手动维护全局类型定义文件的麻烦。
4
4
 
5
5
  import type { Plugin } from 'vite';
@@ -14,9 +14,9 @@ interface ExportInfo {
14
14
  }
15
15
 
16
16
  export default function globalDefinedPlugin(): Plugin {
17
- const globalDir = 'src/.uniky/global';
18
- const globalDtsPath = 'src/.uniky/global.d.ts';
19
- const installTsPath = 'src/.uniky/global.install.ts';
17
+ const globalDir = 'src/_unikey/global';
18
+ const globalDtsPath = 'src/_unikey/global.d.ts';
19
+ const installTsPath = 'src/_unikey/global.install.ts';
20
20
 
21
21
  /**
22
22
  * 递归获取目录下所有 .ts 文件(排除 .d.ts 和 install.ts)
@@ -158,7 +158,7 @@ export default function globalDefinedPlugin(): Plugin {
158
158
 
159
159
  // 按文件分组导出
160
160
  for (const exp of allExports) {
161
- const relativePath = path.relative('src/.uniky', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '');
161
+ const relativePath = path.relative('src/_unikey', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '');
162
162
  if (!imports.has(relativePath)) {
163
163
  imports.set(relativePath, new Set());
164
164
  }
@@ -171,11 +171,11 @@ export default function globalDefinedPlugin(): Plugin {
171
171
  content += '// 请勿手动修改\n\n';
172
172
 
173
173
  // 生成 import 语句
174
- for (const [filePath, names] of imports) {
174
+ Array.from(imports.entries()).forEach(([filePath, names]) => {
175
175
  if (names.size > 0) {
176
176
  content += `import type { ${Array.from(names).join(', ')} } from './${filePath}';\n`;
177
177
  }
178
- }
178
+ });
179
179
 
180
180
  content += '\n';
181
181
 
@@ -187,11 +187,11 @@ export default function globalDefinedPlugin(): Plugin {
187
187
  if (globalItems.length > 0) {
188
188
  for (const exp of globalItems) {
189
189
  if (exp.type === 'function') {
190
- content += ` const ${exp.name}: typeof import('./${path.relative('src/.uniky', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '')}').${exp.name};\n`;
190
+ content += ` const ${exp.name}: typeof import('./${path.relative('src/_unikey', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '')}').${exp.name};\n`;
191
191
  } else if (exp.type === 'const') {
192
- content += ` const ${exp.name}: typeof import('./${path.relative('src/.uniky', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '')}').${exp.name};\n`;
192
+ content += ` const ${exp.name}: typeof import('./${path.relative('src/_unikey', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '')}').${exp.name};\n`;
193
193
  } else if (exp.type === 'class') {
194
- content += ` const ${exp.name}: typeof import('./${path.relative('src/.uniky', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '')}').${exp.name};\n`;
194
+ content += ` const ${exp.name}: typeof import('./${path.relative('src/_unikey', exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '')}').${exp.name};\n`;
195
195
  }
196
196
  }
197
197
  }
@@ -210,7 +210,7 @@ export default function globalDefinedPlugin(): Plugin {
210
210
 
211
211
  // 按文件分组导出
212
212
  for (const exp of allExports) {
213
- const relativePath = './global/' + path.relative(path.join('src', '.uniky', 'global'), exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '');
213
+ const relativePath = './global/' + path.relative(path.join('src', '_unikey', 'global'), exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, '');
214
214
  if (!imports.has(relativePath)) {
215
215
  imports.set(relativePath, { names: new Set(), hasDefault: false });
216
216
  }
@@ -227,7 +227,7 @@ export default function globalDefinedPlugin(): Plugin {
227
227
  content += '// 请勿手动修改\n\n';
228
228
 
229
229
  // 生成 import 语句
230
- for (const [filePath, info] of imports) {
230
+ Array.from(imports.entries()).forEach(([filePath, info]) => {
231
231
  if (info.hasDefault && info.names.size > 0) {
232
232
  content += `import ${info.defaultName}, { ${Array.from(info.names).join(', ')} } from '${filePath}';\n`;
233
233
  } else if (info.hasDefault) {
@@ -235,7 +235,7 @@ export default function globalDefinedPlugin(): Plugin {
235
235
  } else if (info.names.size > 0) {
236
236
  content += `import { ${Array.from(info.names).join(', ')} } from '${filePath}';\n`;
237
237
  }
238
- }
238
+ });
239
239
 
240
240
  content += '\n';
241
241
  content += '/**\n';
@@ -247,7 +247,7 @@ export default function globalDefinedPlugin(): Plugin {
247
247
  // 将导出的内容挂载到 globalThis
248
248
  const globalItems = allExports.filter(exp => exp.type !== 'interface' && exp.type !== 'type');
249
249
  for (const exp of globalItems) {
250
- const name = exp.isDefault ? (imports.get('./global/' + path.relative(path.join('src', '.uniky', 'global'), exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, ''))?.defaultName || exp.name) : exp.name;
250
+ const name = exp.isDefault ? (imports.get('./global/' + path.relative(path.join('src', '_unikey', 'global'), exp.filePath).replace(/\\/g, '/').replace(/\.ts$/, ''))?.defaultName || exp.name) : exp.name;
251
251
  content += ` (globalThis as any).${exp.name} = ${name};\n`;
252
252
  }
253
253
 
@@ -305,25 +305,25 @@ export default function globalDefinedPlugin(): Plugin {
305
305
  },
306
306
 
307
307
  configureServer(server) {
308
- // 监听 src/.uniky/global 目录下的文件变化
308
+ // 监听 src/_unikey/global 目录下的文件变化
309
309
  server.watcher.add(globalDir);
310
310
 
311
311
  server.watcher.on('change', (file) => {
312
- if (file.includes('src/.uniky/global') && file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.includes('global.install.ts')) {
312
+ if (file.includes('src/_unikey/global') && file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.includes('global.install.ts')) {
313
313
  console.log(`[globalDefined] 检测到文件变化: ${file}`);
314
314
  generate();
315
315
  }
316
316
  });
317
317
 
318
318
  server.watcher.on('add', (file) => {
319
- if (file.includes('src/.uniky/global') && file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.includes('global.install.ts')) {
319
+ if (file.includes('src/_unikey/global') && file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.includes('global.install.ts')) {
320
320
  console.log(`[globalDefined] 检测到新文件: ${file}`);
321
321
  generate();
322
322
  }
323
323
  });
324
324
 
325
325
  server.watcher.on('unlink', (file) => {
326
- if (file.includes('src/.uniky/global') && file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.includes('global.install.ts')) {
326
+ if (file.includes('src/_unikey/global') && file.endsWith('.ts') && !file.endsWith('.d.ts') && !file.includes('global.install.ts')) {
327
327
  console.log(`[globalDefined] 检测到文件删除: ${file}`);
328
328
  generate();
329
329
  }
@@ -0,0 +1,106 @@
1
+ // created by zhuxietong on 2026-01-30 23:22
2
+ // 该插件用于生成基础的 HTTP 请求配置
3
+ // 生成的代码将保存到 src/_unikey/global/ky.ts
4
+
5
+ import type { Plugin } from 'vite';
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+
9
+ export default function httpDefinedPlugin(): Plugin {
10
+ const outputPath = 'src/_unikey/global/ky.ts';
11
+
12
+ /**
13
+ * 生成基础请求配置代码
14
+ */
15
+ function generateCode(): string {
16
+ let code = `// created by zhuxietong on 2026-01-30 23:22\n`;
17
+ code += `import { uniKy, useMountedLoad } from "uniky";\n`;
18
+ code += `import { ref } from "vue";\n\n`;
19
+
20
+ code += `const baseUrl = import.meta.env.VITE_API_BASE_URL;\n\n`;
21
+
22
+ code += `export const _ky = uniKy.create({\n`;
23
+ code += ` prefixUrl: baseUrl,\n`;
24
+ code += ` hooks: {\n`;
25
+ code += ` beforeRequest: [\n`;
26
+ code += ` (request, options) => {\n`;
27
+ code += ` const headers = options.headers || {};\n`;
28
+ code += ` try {\n`;
29
+ code += ` const user = uni.getStorageSync('user') || '{}';\n`;
30
+ code += ` const { token } = JSON.parse(user);\n`;
31
+ code += ` if (token) {\n`;
32
+ code += ` headers['Authorization'] = 'Bearer ' + token;\n`;
33
+ code += ` }\n`;
34
+ code += ` options.headers = headers;\n`;
35
+ code += ` } catch (e) {}\n`;
36
+ code += ` },\n`;
37
+ code += ` ],\n`;
38
+ code += ` afterResponse: [\n`;
39
+ code += ` (resp: any, request, options) => {},\n`;
40
+ code += ` ],\n`;
41
+ code += ` },\n`;
42
+ code += ` timeout: 30000,\n`;
43
+ code += `});\n\n`;
44
+
45
+ code += `export function useKyData<T, O extends object = {}>(req: (option: O) => Promise<T>, defaultValue?: T) {\n`;
46
+ code += ` const data = ref<T | undefined>(defaultValue);\n`;
47
+ code += ` const option = ref<any>({});\n`;
48
+ code += ` const run = () => {\n`;
49
+ code += ` return new Promise((resolve, reject) => {\n`;
50
+ code += ` req(option.value)\n`;
51
+ code += ` .then((res: any) => {\n`;
52
+ code += ` data.value = res;\n`;
53
+ code += ` resolve(res);\n`;
54
+ code += ` })\n`;
55
+ code += ` .catch((err) => {\n`;
56
+ code += ` reject(err);\n`;
57
+ code += ` });\n`;
58
+ code += ` });\n`;
59
+ code += ` };\n\n`;
60
+ code += ` useMountedLoad(({ option:o, query, json }) => {\n`;
61
+ code += ` option.value = option;\n`;
62
+ code += ` run()\n`;
63
+ code += ` .then(() => {})\n`;
64
+ code += ` .catch(() => {});\n`;
65
+ code += ` });\n\n`;
66
+ code += ` return {\n`;
67
+ code += ` data,\n`;
68
+ code += ` run,\n`;
69
+ code += ` };\n`;
70
+ code += `}\n`;
71
+
72
+ return code;
73
+ }
74
+
75
+ /**
76
+ * 生成文件
77
+ */
78
+ function generate() {
79
+ try {
80
+ if (fs.existsSync(outputPath)) {
81
+ console.log(`[httpDefined] 文件已存在,跳过生成: ${outputPath}`);
82
+ return;
83
+ }
84
+
85
+ const code = generateCode();
86
+
87
+ const dir = path.dirname(outputPath);
88
+ if (!fs.existsSync(dir)) {
89
+ fs.mkdirSync(dir, { recursive: true });
90
+ }
91
+
92
+ fs.writeFileSync(outputPath, code, 'utf-8');
93
+ console.log(`[httpDefined] 已生成 ${outputPath}`);
94
+ } catch (error) {
95
+ console.error('[httpDefined] 生成失败:', error);
96
+ }
97
+ }
98
+
99
+ return {
100
+ name: 'vite-plugin-http-defined',
101
+
102
+ buildStart() {
103
+ generate();
104
+ }
105
+ };
106
+ }
@@ -3,30 +3,35 @@ import type { Plugin } from 'vite';
3
3
 
4
4
  import pagesDefinedPlugin from './pages.defined';
5
5
  import globalDefinedPlugin from './global.defined';
6
+ import httpDefinedPlugin from './http.defined';
6
7
 
7
8
 
8
9
 
9
10
  export interface UnikyPluginOptions {
10
11
  enablePages?: boolean;
11
12
  enableGlobal?: boolean;
13
+ enableHttp?: boolean;
12
14
  }
13
15
 
14
16
  export function unikyPlugin(options: UnikyPluginOptions = {}): Plugin[] {
15
- const { enablePages = true, enableGlobal = true } = options;
17
+ const { enablePages = true, enableGlobal = true, enableHttp = true } = options;
16
18
 
17
19
  const plugins: Plugin[] = [];
18
20
 
19
21
  if (enablePages) {
20
22
  plugins.push(pagesDefinedPlugin());
21
23
  }
22
-
24
+ if (enableHttp) {
25
+ plugins.push(httpDefinedPlugin());
26
+ }
23
27
  if (enableGlobal) {
24
28
  plugins.push(globalDefinedPlugin());
25
29
  }
26
30
 
31
+
27
32
  return plugins;
28
33
  }
29
34
 
30
- export { pagesDefinedPlugin, globalDefinedPlugin };
35
+ export { pagesDefinedPlugin, globalDefinedPlugin, httpDefinedPlugin };
31
36
 
32
37
  export default unikyPlugin;
@@ -248,7 +248,7 @@ export default function pagesDefinedPlugin(): Plugin {
248
248
  configResolved(config) {
249
249
  // 确定 src 目录和输出路径
250
250
  srcDir = path.resolve(config.root, 'src');
251
- outputPath = path.resolve(srcDir, '.uniky/global/pages.ts');
251
+ outputPath = path.resolve(srcDir, '_unikey/global/pages.ts');
252
252
  },
253
253
 
254
254
  buildStart() {