@liujitcn/kratos-uni-app-cli 0.0.1

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/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @liujitcn/kratos-uni-app-cli
2
+
3
+ `@liujitcn/kratos-uni-app-cli` 提供 `kratos-uni-app` 命令,用于创建独立 pnpm workspace、uni-app 宿主和可选本地业务模块。
4
+
5
+ ## 目录结构
6
+
7
+ ```text
8
+ packages/cli
9
+ ├── bin/kratos-uni-app.mjs # 命令行参数解析与可执行入口
10
+ ├── src/index.mjs # workspace 文件生成逻辑
11
+ ├── test/scaffold.test.mjs # 脚手架结构和参数测试
12
+ ├── README.md # CLI 包职责、参数和生成约束
13
+ └── package.json
14
+ ```
15
+
16
+ CLI 直接由 `src/index.mjs` 生成文件,不依赖外部模板目录。
17
+
18
+ ## 功能
19
+
20
+ - 创建包含 `apps/uni-app` 的独立 pnpm workspace。
21
+ - 默认接入 core 和 system 包。
22
+ - 使用 `--module` 创建 workspace 内本地模块。
23
+ - 使用 `--with` 安装额外的已发布模块。
24
+ - 校验模块名和包名,目标目录已存在时拒绝覆盖。
25
+ - core、system 和本地模块的 core 依赖版本统一跟随当前 CLI 包版本。
26
+ - 生成的宿主在登录、退出和静默退出后重新加载当前身份的导航配置。
27
+ - 为 workspace 根目录、`apps/uni-app` 和每个本地模块生成同级 `README.md`;每个包含
28
+ `package.json` 的生成目录都有对应的结构与职责说明。
29
+
30
+ ## 使用
31
+
32
+ ```bash
33
+ pnpm dlx @liujitcn/kratos-uni-app-cli create my-app
34
+ pnpm dlx @liujitcn/kratos-uni-app-cli create my-app --module orders
35
+ pnpm dlx @liujitcn/kratos-uni-app-cli create my-app --with @acme/pay
36
+ ```
37
+
38
+ 包构建和脚手架验证命令见 [workspace 文档](../../README.md)。
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { scaffoldKratosApp } from '../src/index.mjs'
3
+
4
+ const args = process.argv.slice(2)
5
+ if (args[0] !== 'create' || !args[1]) {
6
+ console.error('用法: kratos-uni-app create <目录> [--module <名称>] [--with <包名>]')
7
+ process.exitCode = 1
8
+ } else {
9
+ const modules = []
10
+ const packages = []
11
+ for (let index = 2; index < args.length; index += 1) {
12
+ if (args[index] === '--module' && args[index + 1]) modules.push(args[++index])
13
+ else if (args[index] === '--with' && args[index + 1]) packages.push(args[++index])
14
+ else throw new Error(`未知参数:${args[index]}`)
15
+ }
16
+ scaffoldKratosApp(args[1], { modules, packages })
17
+ }
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@liujitcn/kratos-uni-app-cli",
3
+ "description": "CLI for scaffolding modular Kratos uni-app workspaces.",
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "files": [
7
+ "bin",
8
+ "src",
9
+ "README.md"
10
+ ],
11
+ "bin": {
12
+ "kratos-uni-app": "./bin/kratos-uni-app.mjs"
13
+ },
14
+ "exports": {
15
+ ".": "./src/index.mjs",
16
+ "./package.json": "./package.json"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "scripts": {
22
+ "build": "pnpm pack --pack-destination ../../dist/npm"
23
+ }
24
+ }
package/src/index.mjs ADDED
@@ -0,0 +1,361 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { basename, resolve } from 'node:path'
3
+
4
+ const cliPackage = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
5
+ const publicPackageVersion = cliPackage.version
6
+ if (typeof publicPackageVersion !== 'string' || !publicPackageVersion) {
7
+ throw new Error('CLI package.json 缺少有效版本')
8
+ }
9
+
10
+ /** 创建独立 Kratos uni-app workspace。 */
11
+ export function scaffoldKratosApp(targetPath, options = {}) {
12
+ const target = resolve(targetPath)
13
+ if (existsSync(target)) throw new Error(`目标目录已存在:${target}`)
14
+ const projectName = basename(target)
15
+ const modules = [...new Set(options.modules ?? [])]
16
+ const packages = [...new Set(options.packages ?? [])]
17
+ modules.forEach(validateModuleName)
18
+ packages.forEach(validatePackageName)
19
+ mkdirSync(resolve(target, 'apps/uni-app/src/pages/bootstrap'), { recursive: true })
20
+ modules.forEach((name) =>
21
+ mkdirSync(resolve(target, `packages/modules/${name}/src/views`), { recursive: true }),
22
+ )
23
+
24
+ write(target, 'pnpm-workspace.yaml', 'packages:\n - apps/*\n - packages/modules/*\n')
25
+ write(
26
+ target,
27
+ 'package.json',
28
+ json({
29
+ name: projectName,
30
+ description: `Independent pnpm workspace for ${projectName}.`,
31
+ private: true,
32
+ scripts: {
33
+ 'dev:h5': 'pnpm --filter @liujitcn/kratos-uni-app dev:h5',
34
+ 'dev:mp-weixin': 'pnpm --filter @liujitcn/kratos-uni-app dev:mp-weixin',
35
+ 'build:h5': 'pnpm --filter @liujitcn/kratos-uni-app build:h5',
36
+ 'build:mp-weixin': 'pnpm --filter @liujitcn/kratos-uni-app build:mp-weixin',
37
+ },
38
+ devDependencies: {
39
+ '@dcloudio/types': 'latest',
40
+ '@vue/compiler-sfc': '^3.4.21',
41
+ '@vue/tsconfig': 'latest',
42
+ 'miniprogram-api-typings': 'latest',
43
+ typescript: 'latest',
44
+ 'vue-tsc': 'latest',
45
+ },
46
+ }),
47
+ )
48
+ write(
49
+ target,
50
+ 'README.md',
51
+ `# ${projectName}
52
+
53
+ \`${projectName}\` 是由 \`@liujitcn/kratos-uni-app-cli\` 创建的独立 pnpm workspace,支持 H5 和微信小程序。
54
+
55
+ ## 目录结构
56
+
57
+ \`\`\`text
58
+ ${projectName}
59
+ ├── apps/uni-app # 私有 uni-app 宿主
60
+ ├── packages/modules # workspace 内本地业务模块
61
+ ├── package.json # 公共命令和开发依赖
62
+ ├── pnpm-workspace.yaml # workspace 包范围
63
+ └── tsconfig.json # 共享 TypeScript 配置
64
+ \`\`\`
65
+
66
+ 宿主只负责入口、manifest、模块清单和启动;底座能力由 \`@liujitcn/kratos-uni-app-core\` 提供,默认业务页面由 \`@liujitcn/kratos-uni-app-system\` 提供。本地模块通过各自公开入口接入,不跨包相对引用源码。
67
+
68
+ ## 开发
69
+
70
+ \`\`\`bash
71
+ pnpm install
72
+ pnpm dev:h5
73
+ pnpm dev:mp-weixin
74
+ pnpm build:h5
75
+ pnpm build:mp-weixin
76
+ \`\`\`
77
+
78
+ 模块装配入口是 \`apps/uni-app/src/module-manifest.ts\`。新增、删除或调整模块时同步维护该清单,并在模块自己的 README 中记录页面和接口职责。
79
+ `,
80
+ )
81
+ const dependencies = {
82
+ '@liujitcn/kratos-uni-app-core': `^${publicPackageVersion}`,
83
+ '@liujitcn/kratos-uni-app-system': `^${publicPackageVersion}`,
84
+ '@dcloudio/uni-app': 'latest',
85
+ '@dcloudio/uni-components': 'latest',
86
+ '@dcloudio/uni-h5': 'latest',
87
+ '@dcloudio/uni-mp-weixin': 'latest',
88
+ '@dcloudio/uni-ui': 'latest',
89
+ '@dcloudio/vite-plugin-uni': 'latest',
90
+ pinia: '^2.0.27',
91
+ sass: '^1.77.8',
92
+ vite: '^5.2.8',
93
+ vue: '^3.4.21',
94
+ ...Object.fromEntries(modules.map((name) => [`@local/${name}`, 'workspace:*'])),
95
+ ...Object.fromEntries(packages.map((name) => [name, 'latest'])),
96
+ }
97
+ write(
98
+ target,
99
+ 'apps/uni-app/package.json',
100
+ json({
101
+ name: '@liujitcn/kratos-uni-app',
102
+ description: `Private uni-app host for ${projectName}.`,
103
+ version: '0.0.1',
104
+ private: true,
105
+ type: 'module',
106
+ scripts: {
107
+ 'dev:h5': 'uni --mode development',
108
+ 'dev:mp-weixin': 'uni -p mp-weixin',
109
+ 'build:h5': 'uni build --mode production',
110
+ 'build:mp-weixin': 'uni build -p mp-weixin --mode production',
111
+ tsc: 'vue-tsc --noEmit',
112
+ },
113
+ dependencies,
114
+ }),
115
+ )
116
+ write(
117
+ target,
118
+ 'apps/uni-app/README.md',
119
+ `# @liujitcn/kratos-uni-app
120
+
121
+ \`apps/uni-app\` 是 \`${projectName}\` 的私有 uni-app 宿主,负责组合模块并提供 H5、微信小程序的构建入口,不承载可复用业务实现。
122
+
123
+ ## 目录结构
124
+
125
+ \`\`\`text
126
+ apps/uni-app
127
+ ├── src
128
+ │ ├── pages/bootstrap # 固定启动页面
129
+ │ ├── App.vue # 应用根组件和全局样式入口
130
+ │ ├── main.ts # Vue 与 Kratos uni-app 启动入口
131
+ │ ├── manifest.json # uni-app 平台配置
132
+ │ ├── module-manifest.ts # 唯一模块清单
133
+ │ └── pages.json # 固定 bootstrap 路由
134
+ ├── index.html # H5 HTML 入口
135
+ ├── package.json # 宿主命令和运行依赖
136
+ └── vite.config.ts # 模块页面装配与 uni-app 插件
137
+ \`\`\`
138
+
139
+ ## 模块装配
140
+
141
+ \`src/module-manifest.ts\` 默认注册 core 和 system,并按声明顺序加载本地模块与已发布模块。业务页面、API 和状态应放在所属模块,宿主仅维护组合关系和平台配置。
142
+
143
+ ## 命令
144
+
145
+ 在 workspace 根目录执行:
146
+
147
+ \`\`\`bash
148
+ pnpm dev:h5
149
+ pnpm dev:mp-weixin
150
+ pnpm build:h5
151
+ pnpm build:mp-weixin
152
+ \`\`\`
153
+ `,
154
+ )
155
+ const imports = [
156
+ "import { coreModule } from '@liujitcn/kratos-uni-app-core/module'",
157
+ "import systemModule from '@liujitcn/kratos-uni-app-system'",
158
+ ...modules.map((name, index) => `import localModule${index} from '@local/${name}'`),
159
+ ...packages.map((name, index) => `import packageModule${index} from '${name}'`),
160
+ ]
161
+ const members = [
162
+ 'coreModule',
163
+ 'systemModule',
164
+ ...modules.map((_, index) => `localModule${index}`),
165
+ ...packages.map((_, index) => `packageModule${index}`),
166
+ ]
167
+ write(
168
+ target,
169
+ 'apps/uni-app/src/module-manifest.ts',
170
+ `${imports.join('\n')}\n\nexport const moduleManifest = [${members.join(', ')}]\n`,
171
+ )
172
+ write(
173
+ target,
174
+ 'apps/uni-app/src/pages.json',
175
+ json({
176
+ pages: [
177
+ {
178
+ path: 'pages/bootstrap/index',
179
+ style: { navigationStyle: 'custom' },
180
+ },
181
+ ],
182
+ }),
183
+ )
184
+ write(
185
+ target,
186
+ 'apps/uni-app/src/pages/bootstrap/index.vue',
187
+ `<script setup lang="ts">
188
+ import { onLoad } from '@dcloudio/uni-app'
189
+ import { resolveStaticView } from '@liujitcn/kratos-uni-app-core'
190
+ onLoad((options) => {
191
+ const route = resolveStaticView('BOOTSTRAP_LOADING') ?? 'pages/status/index'
192
+ const target = options?.route ? decodeURIComponent(options.route) : 'app/home'
193
+ uni.reLaunch({ url: \`/\${route}?state=BOOTSTRAP_LOADING&bootstrap=1&route=\${encodeURIComponent(target)}\` })
194
+ })
195
+ </script>
196
+ <template><view /></template>
197
+ `,
198
+ )
199
+ write(
200
+ target,
201
+ 'apps/uni-app/src/main.ts',
202
+ `import {
203
+ bootstrapKratosApp,
204
+ initializeAppNavigation,
205
+ pinia,
206
+ registerKratosAppModules,
207
+ registerUserStoreExtension,
208
+ } from '@liujitcn/kratos-uni-app-core'
209
+ import { createSSRApp } from 'vue'
210
+ import App from './App.vue'
211
+ import { moduleManifest } from './module-manifest'
212
+
213
+ registerKratosAppModules(moduleManifest)
214
+ registerUserStoreExtension({
215
+ onLogin: initializeAppNavigation,
216
+ onLogout: initializeAppNavigation,
217
+ onSilentLogout: initializeAppNavigation,
218
+ })
219
+
220
+ export function createApp() {
221
+ return bootstrapKratosApp({ app: App, createSSRApp, pinia, modules: moduleManifest })
222
+ }
223
+ `,
224
+ )
225
+ write(
226
+ target,
227
+ 'apps/uni-app/src/App.vue',
228
+ `<script setup lang="ts"></script>
229
+ <style lang="scss">@use '@liujitcn/kratos-uni-app-core/styles/base.scss';</style>
230
+ `,
231
+ )
232
+ write(target, 'apps/uni-app/src/uni.scss', "@forward '@liujitcn/kratos-uni-app-core/uni.scss';\n")
233
+ write(
234
+ target,
235
+ 'apps/uni-app/src/manifest.json',
236
+ json({
237
+ name: projectName,
238
+ appid: '__UNI__KRATOS_APP',
239
+ versionName: '1.0.0',
240
+ versionCode: '100',
241
+ transformPx: false,
242
+ 'mp-weixin': { appid: '', setting: { urlCheck: false } },
243
+ h5: { router: { mode: 'hash' } },
244
+ }),
245
+ )
246
+ write(
247
+ target,
248
+ 'apps/uni-app/index.html',
249
+ `<!doctype html>
250
+ <html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><title>${projectName}</title></head>
251
+ <body><div id="app"><!--app-html--></div><script type="module" src="/src/main.ts"></script></body></html>
252
+ `,
253
+ )
254
+ write(
255
+ target,
256
+ 'apps/uni-app/vite.config.ts',
257
+ `import { createKratosUniPlugin, defineConfig, kratosApp } from '@liujitcn/kratos-uni-app-core/vite'
258
+ import { moduleManifest } from './src/module-manifest'
259
+ export default defineConfig({
260
+ resolve: { preserveSymlinks: true },
261
+ plugins: [kratosApp({ modules: moduleManifest }), createKratosUniPlugin()],
262
+ })
263
+ `,
264
+ )
265
+ write(
266
+ target,
267
+ 'tsconfig.json',
268
+ json({
269
+ extends: '@vue/tsconfig/tsconfig.json',
270
+ compilerOptions: {
271
+ allowJs: true,
272
+ moduleResolution: 'Bundler',
273
+ skipLibCheck: true,
274
+ types: ['@dcloudio/types', 'miniprogram-api-typings'],
275
+ },
276
+ include: ['apps/**/*.ts', 'apps/**/*.vue', 'packages/**/*.ts'],
277
+ }),
278
+ )
279
+ modules.forEach((name) => {
280
+ write(
281
+ target,
282
+ `packages/modules/${name}/package.json`,
283
+ json({
284
+ name: `@local/${name}`,
285
+ description: `Local Kratos uni-app module for ${name}.`,
286
+ version: '0.0.1',
287
+ type: 'module',
288
+ exports: {
289
+ '.': {
290
+ types: './src/index.d.mts',
291
+ import: './src/index.mjs',
292
+ default: './src/index.mjs',
293
+ },
294
+ './views/*': './src/views/*',
295
+ './package.json': './package.json',
296
+ },
297
+ dependencies: { '@liujitcn/kratos-uni-app-core': `^${publicPackageVersion}` },
298
+ }),
299
+ )
300
+ write(
301
+ target,
302
+ `packages/modules/${name}/README.md`,
303
+ `# @local/${name}
304
+
305
+ \`@local/${name}\` 是 \`${projectName}\` workspace 内的本地业务模块,通过 \`@liujitcn/kratos-uni-app-core\` 的公开接口接入宿主。
306
+
307
+ ## 目录结构
308
+
309
+ \`\`\`text
310
+ packages/modules/${name}
311
+ ├── src
312
+ │ ├── views # 模块页面;页面私有组件放在就近 components
313
+ │ ├── index.d.mts # 模块入口类型
314
+ │ └── index.mjs # 页面、视图键和图标注册入口
315
+ ├── package.json # 模块名称、依赖和 exports
316
+ └── README.md # 模块职责与维护说明
317
+ \`\`\`
318
+
319
+ ## 开发约束
320
+
321
+ - 页面放在 \`src/views\`,并在 \`src/index.mjs\` 的模块定义中登记页面和稳定视图键。
322
+ - 请求、认证、导航和状态能力只通过 \`@liujitcn/kratos-uni-app-core\` 的公开 exports 使用。
323
+ - 页面替换使用稳定视图键,接口不能直接下发任意组件路径。
324
+ - 修改模块后从 workspace 根目录运行对应 H5 或微信小程序命令验证装配结果。
325
+ `,
326
+ )
327
+ write(
328
+ target,
329
+ `packages/modules/${name}/src/index.mjs`,
330
+ `import { defineKratosAppModule } from '@liujitcn/kratos-uni-app-core/module'
331
+ export default defineKratosAppModule({ name: '@local/${name}', pages: {}, views: {} })
332
+ `,
333
+ )
334
+ write(
335
+ target,
336
+ `packages/modules/${name}/src/index.d.mts`,
337
+ `declare const module: import('@liujitcn/kratos-uni-app-core/module').KratosAppModule
338
+ export default module
339
+ `,
340
+ )
341
+ })
342
+ return target
343
+ }
344
+
345
+ function validateModuleName(name) {
346
+ if (!/^[a-z][a-z0-9-]*$/.test(name)) throw new Error(`模块名无效:${name}`)
347
+ }
348
+
349
+ function validatePackageName(name) {
350
+ if (!/^(?:@[a-z0-9-]+\/)?[a-z0-9-]+$/.test(name)) throw new Error(`包名无效:${name}`)
351
+ }
352
+
353
+ function write(root, file, content) {
354
+ const target = resolve(root, file)
355
+ mkdirSync(resolve(target, '..'), { recursive: true })
356
+ writeFileSync(target, content)
357
+ }
358
+
359
+ function json(value) {
360
+ return `${JSON.stringify(value, null, 2)}\n`
361
+ }