create-secra 0.1.4 → 0.1.7
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 +6 -0
- package/README.zh-CN.md +6 -0
- package/antd-adapter-template/apps/core/index.html +13 -0
- package/antd-adapter-template/apps/core/package.json +18 -0
- package/antd-adapter-template/apps/core/public/favicon.ico +1 -0
- package/antd-adapter-template/apps/core/public/favicon.svg +1 -0
- package/antd-adapter-template/apps/core/public/logo.svg +1 -0
- package/antd-adapter-template/apps/core/src/api/auth.ts +49 -0
- package/antd-adapter-template/apps/core/src/assets/react.svg +1 -0
- package/antd-adapter-template/apps/core/src/components/AntdGlobalProvider.tsx +87 -0
- package/antd-adapter-template/apps/core/src/components/AntdRootLayout.tsx +10 -0
- package/antd-adapter-template/apps/core/src/components/layout.tsx +387 -0
- package/antd-adapter-template/apps/core/src/guards/auth-route-guard.ts +45 -0
- package/antd-adapter-template/apps/core/src/main.tsx +65 -0
- package/antd-adapter-template/apps/core/src/pages/auth/components/account-login-fields.tsx +60 -0
- package/antd-adapter-template/apps/core/src/pages/auth/components/phone-login-fields.tsx +60 -0
- package/antd-adapter-template/apps/core/src/pages/auth/login.tsx +169 -0
- package/antd-adapter-template/apps/core/src/pages/index.tsx +156 -0
- package/antd-adapter-template/apps/core/src/router.ts +42 -0
- package/antd-adapter-template/apps/core/src/shims/use-sync-external-store-shim.ts +3 -0
- package/antd-adapter-template/apps/core/src/theme/theme.css +48 -0
- package/antd-adapter-template/apps/core/src/types/crypto-js.d.ts +5 -0
- package/antd-adapter-template/apps/core/src/utils/index.ts +12 -0
- package/antd-adapter-template/apps/core/src/utils/md5.ts +6 -0
- package/antd-adapter-template/apps/core/tsconfig.app.json +11 -0
- package/antd-adapter-template/apps/core/tsconfig.json +13 -0
- package/antd-adapter-template/apps/core/tsconfig.node.json +7 -0
- package/antd-adapter-template/apps/core/vite.config.ts +118 -0
- package/antd-adapter-template/eslint.config.js +23 -0
- package/antd-adapter-template/package.json +63 -0
- package/antd-adapter-template/packages/sdk/.swcrc +18 -0
- package/antd-adapter-template/packages/sdk/package.json +52 -0
- package/antd-adapter-template/packages/sdk/src/build/index.ts +28 -0
- package/antd-adapter-template/packages/sdk/src/build/plugins/auto-import.ts +46 -0
- package/antd-adapter-template/packages/sdk/src/build/plugins/bundle-analyzer.ts +33 -0
- package/antd-adapter-template/packages/sdk/src/build/plugins/remove-console.ts +23 -0
- package/antd-adapter-template/packages/sdk/src/build/plugins/unocss.ts +202 -0
- package/antd-adapter-template/packages/sdk/src/build/plugins/unplugin-icon.ts +43 -0
- package/antd-adapter-template/packages/sdk/src/components/i18n-switch-dropdown.tsx +139 -0
- package/antd-adapter-template/packages/sdk/src/components/index.ts +2 -0
- package/antd-adapter-template/packages/sdk/src/components/theme-switch-dropdown.tsx +131 -0
- package/antd-adapter-template/packages/sdk/src/hooks/auth/core.ts +101 -0
- package/antd-adapter-template/packages/sdk/src/hooks/auth/index.ts +139 -0
- package/antd-adapter-template/packages/sdk/src/hooks/auth/with-auth.tsx +41 -0
- package/antd-adapter-template/packages/sdk/src/hooks/index.ts +1 -0
- package/antd-adapter-template/packages/sdk/src/i18n/index.ts +150 -0
- package/antd-adapter-template/packages/sdk/src/index.ts +11 -0
- package/antd-adapter-template/packages/sdk/src/request/index.ts +436 -0
- package/antd-adapter-template/packages/sdk/src/storage/README.md +30 -0
- package/antd-adapter-template/packages/sdk/src/storage/index.ts +57 -0
- package/antd-adapter-template/packages/sdk/src/styles/reset.css +111 -0
- package/antd-adapter-template/packages/sdk/src/theme/index.ts +466 -0
- package/antd-adapter-template/packages/sdk/tsconfig.json +16 -0
- package/antd-adapter-template/pnpm-workspace.yaml +3 -0
- package/antd-adapter-template/tsconfig.app.json +29 -0
- package/antd-adapter-template/tsconfig.json +7 -0
- package/antd-adapter-template/tsconfig.node.json +27 -0
- package/antd-adapter-template/turbo.json +17 -0
- package/bin/index.mjs +165 -33
- package/package.json +6 -2
- package/template/apps/core/src/main.tsx +11 -18
- package/template/apps/core/src/router.ts +5 -1
- package/template/package.json +1 -1
- package/template/packages/sdk/src/build/plugins/unocss.ts +3 -0
package/bin/index.mjs
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
3
|
import { cpSync, existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { emitKeypressEvents } from "node:readline";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import process from "node:process";
|
|
8
8
|
|
|
9
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const DEFAULT_TEMPLATE = path.resolve(__dirname, "../template");
|
|
11
|
+
const ANT_DESIGN_ADAPTER_TEMPLATE = path.resolve(__dirname, "../antd-adapter-template");
|
|
12
|
+
const TEMPLATE_OPTIONS = [
|
|
13
|
+
{
|
|
14
|
+
key: "1",
|
|
15
|
+
label: "最小可用版本",
|
|
16
|
+
templatePath: DEFAULT_TEMPLATE,
|
|
17
|
+
templateName: "template",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: "2",
|
|
21
|
+
label: "antd UI 适配器版本",
|
|
22
|
+
templatePath: ANT_DESIGN_ADAPTER_TEMPLATE,
|
|
23
|
+
templateName: "antd-adapter-template",
|
|
24
|
+
},
|
|
25
|
+
];
|
|
11
26
|
const EXCLUDED_DIRS = new Set(["node_modules", "dist", ".turbo", ".git"]);
|
|
12
27
|
const targetArg = process.argv[2];
|
|
13
28
|
const targetDir = targetArg && targetArg.trim() ? targetArg.trim() : "secra-app";
|
|
@@ -42,41 +57,163 @@ function updatePackageName(cwd, name) {
|
|
|
42
57
|
}
|
|
43
58
|
}
|
|
44
59
|
|
|
45
|
-
function detectPackageManager() {
|
|
60
|
+
function detectPackageManager(projectRoot) {
|
|
46
61
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
47
62
|
if (userAgent.startsWith("pnpm")) return "pnpm";
|
|
48
63
|
if (userAgent.startsWith("yarn")) return "yarn";
|
|
49
64
|
if (userAgent.startsWith("bun")) return "bun";
|
|
65
|
+
|
|
66
|
+
// Fallback to the project's packageManager field (e.g. "pnpm@9.x").
|
|
67
|
+
if (projectRoot) {
|
|
68
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
69
|
+
if (existsSync(packageJsonPath)) {
|
|
70
|
+
try {
|
|
71
|
+
const content = readFileSync(packageJsonPath, "utf8");
|
|
72
|
+
const json = JSON.parse(content);
|
|
73
|
+
const packageManager = String(json.packageManager || "").trim();
|
|
74
|
+
if (packageManager.startsWith("pnpm")) return "pnpm";
|
|
75
|
+
if (packageManager.startsWith("yarn")) return "yarn";
|
|
76
|
+
if (packageManager.startsWith("bun")) return "bun";
|
|
77
|
+
if (packageManager.startsWith("npm")) return "npm";
|
|
78
|
+
} catch {
|
|
79
|
+
// Ignore parsing failures and fall through to npm.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
50
84
|
return "npm";
|
|
51
85
|
}
|
|
52
86
|
|
|
53
|
-
function
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
?
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
async function promptTemplateSelection() {
|
|
88
|
+
const renderMenu = (selectedIndex) => {
|
|
89
|
+
const lines = ["[create-secra] 请选择初始化版本(↑/↓ 切换,Enter 确认):"];
|
|
90
|
+
for (let i = 0; i < TEMPLATE_OPTIONS.length; i += 1) {
|
|
91
|
+
const option = TEMPLATE_OPTIONS[i];
|
|
92
|
+
const prefix = i === selectedIndex ? "❯" : " ";
|
|
93
|
+
lines.push(` ${prefix} ${option.key}. ${option.label}`);
|
|
94
|
+
}
|
|
95
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
let selectedIndex = 0;
|
|
100
|
+
let renderedLines = 0;
|
|
101
|
+
const stdin = process.stdin;
|
|
102
|
+
const stdout = process.stdout;
|
|
103
|
+
const shouldRestoreRaw = stdin.isTTY && !stdin.isRaw;
|
|
104
|
+
|
|
105
|
+
const clearRenderedMenu = () => {
|
|
106
|
+
if (renderedLines > 0) {
|
|
107
|
+
stdout.write(`\u001b[${renderedLines}A`);
|
|
108
|
+
stdout.write("\u001b[J");
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const draw = () => {
|
|
113
|
+
clearRenderedMenu();
|
|
114
|
+
renderMenu(selectedIndex);
|
|
115
|
+
renderedLines = TEMPLATE_OPTIONS.length + 1;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const cleanup = () => {
|
|
119
|
+
stdin.removeListener("keypress", onKeypress);
|
|
120
|
+
if (stdin.isTTY && shouldRestoreRaw) {
|
|
121
|
+
stdin.setRawMode(false);
|
|
122
|
+
}
|
|
123
|
+
stdin.pause();
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const finish = () => {
|
|
127
|
+
cleanup();
|
|
128
|
+
clearRenderedMenu();
|
|
129
|
+
const selected = TEMPLATE_OPTIONS[selectedIndex] ?? TEMPLATE_OPTIONS[0];
|
|
130
|
+
stdout.write(`[create-secra] 请选择初始化版本:${selected.label}\n`);
|
|
131
|
+
resolve(selected);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const onKeypress = (_str, key) => {
|
|
135
|
+
if (key?.name === "up") {
|
|
136
|
+
selectedIndex = (selectedIndex - 1 + TEMPLATE_OPTIONS.length) % TEMPLATE_OPTIONS.length;
|
|
137
|
+
draw();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (key?.name === "down") {
|
|
142
|
+
selectedIndex = (selectedIndex + 1) % TEMPLATE_OPTIONS.length;
|
|
143
|
+
draw();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (key?.name === "return") {
|
|
148
|
+
finish();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (key?.ctrl && key?.name === "c") {
|
|
153
|
+
cleanup();
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
emitKeypressEvents(stdin);
|
|
159
|
+
stdin.setRawMode(true);
|
|
160
|
+
stdin.resume();
|
|
161
|
+
stdin.on("keypress", onKeypress);
|
|
162
|
+
draw();
|
|
74
163
|
});
|
|
75
164
|
}
|
|
76
165
|
|
|
166
|
+
async function resolveTemplate() {
|
|
167
|
+
const templateName = process.env.SECRA_TEMPLATE_NAME || "";
|
|
168
|
+
const templateFromEnv = process.env.SECRA_TEMPLATE;
|
|
169
|
+
|
|
170
|
+
if (templateFromEnv) {
|
|
171
|
+
return {
|
|
172
|
+
template: templateFromEnv,
|
|
173
|
+
selectedName: templateName || "custom",
|
|
174
|
+
selectedLabel: templateName || "自定义模板",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (templateName) {
|
|
179
|
+
const matchedByName = TEMPLATE_OPTIONS.find((option) => option.templateName === templateName);
|
|
180
|
+
if (matchedByName) {
|
|
181
|
+
return {
|
|
182
|
+
template: matchedByName.templatePath,
|
|
183
|
+
selectedName: matchedByName.templateName,
|
|
184
|
+
selectedLabel: matchedByName.label,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const matchedByArg = TEMPLATE_OPTIONS.find((option) => option.key === process.argv[3]);
|
|
190
|
+
if (matchedByArg) {
|
|
191
|
+
return {
|
|
192
|
+
template: matchedByArg.templatePath,
|
|
193
|
+
selectedName: matchedByArg.templateName,
|
|
194
|
+
selectedLabel: matchedByArg.label,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
199
|
+
const fallback = TEMPLATE_OPTIONS[0];
|
|
200
|
+
return {
|
|
201
|
+
template: fallback.templatePath,
|
|
202
|
+
selectedName: fallback.templateName,
|
|
203
|
+
selectedLabel: fallback.label,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const selected = await promptTemplateSelection();
|
|
208
|
+
return {
|
|
209
|
+
template: selected.templatePath,
|
|
210
|
+
selectedName: selected.templateName,
|
|
211
|
+
selectedLabel: selected.label,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
77
215
|
async function main() {
|
|
78
|
-
const template =
|
|
79
|
-
const manager = detectPackageManager();
|
|
216
|
+
const { template, selectedLabel } = await resolveTemplate();
|
|
80
217
|
|
|
81
218
|
if (existsSync(targetPath)) {
|
|
82
219
|
const files = readdirSync(targetPath);
|
|
@@ -89,6 +226,7 @@ async function main() {
|
|
|
89
226
|
fail(`Template does not exist: ${template}`);
|
|
90
227
|
}
|
|
91
228
|
|
|
229
|
+
console.log(`[create-secra] 已选择:${selectedLabel}`);
|
|
92
230
|
console.log(`[create-secra] Scaffolding from local template: ${template} ...`);
|
|
93
231
|
try {
|
|
94
232
|
cpSync(template, targetPath, {
|
|
@@ -101,17 +239,11 @@ async function main() {
|
|
|
101
239
|
}
|
|
102
240
|
|
|
103
241
|
updatePackageName(targetPath, path.basename(targetPath));
|
|
104
|
-
|
|
105
|
-
console.log(`[create-secra] Installing dependencies with ${manager} ...`);
|
|
106
|
-
try {
|
|
107
|
-
await runInstall(targetPath, manager);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
fail(error instanceof Error ? error.message : String(error));
|
|
110
|
-
}
|
|
242
|
+
const manager = detectPackageManager(targetPath);
|
|
111
243
|
|
|
112
244
|
console.log(`[create-secra] Done. Next steps:`);
|
|
113
245
|
console.log(` cd ${targetDir}`);
|
|
114
|
-
console.log(`
|
|
246
|
+
console.log(` ${manager === "yarn" ? "yarn" : `${manager} install`}`);
|
|
115
247
|
console.log(` pnpm -r --filter "./packages/*" build`);
|
|
116
248
|
console.log(` pnpm dev`);
|
|
117
249
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-secra",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Create a Secra project from the official template.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,12 +8,16 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
|
-
"template"
|
|
11
|
+
"template",
|
|
12
|
+
"antd-adapter-template"
|
|
12
13
|
],
|
|
13
14
|
"keywords": [
|
|
14
15
|
"create",
|
|
15
16
|
"secra",
|
|
16
17
|
"scaffold"
|
|
17
18
|
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"prepublishOnly": "npm version patch"
|
|
21
|
+
},
|
|
18
22
|
"license": "MIT"
|
|
19
23
|
}
|
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import '@vlian/sdk/reset.css';
|
|
2
2
|
import { startApp } from '@vlian/framework/core';
|
|
3
|
-
import { LogLevel } from '@vlian/framework/utils';
|
|
4
3
|
import { getRoutes } from './router';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
},
|
|
16
|
-
router: {
|
|
17
|
-
enabled: true,
|
|
18
|
-
routes: getRoutes,
|
|
19
|
-
mode: 'browser',
|
|
20
|
-
}
|
|
4
|
+
|
|
5
|
+
startApp({
|
|
6
|
+
router: {
|
|
7
|
+
enabled: true,
|
|
8
|
+
routes: getRoutes,
|
|
9
|
+
mode: 'browser',
|
|
10
|
+
},
|
|
11
|
+
}).catch((error) => {
|
|
12
|
+
// eslint-disable-next-line no-console
|
|
13
|
+
console.error('启动失败:', error);
|
|
21
14
|
});
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { RouteConfig } from "@vlian/framework/core"
|
|
2
2
|
|
|
3
|
+
const HomePage = lazy(() => import("./pages/index"));
|
|
4
|
+
|
|
3
5
|
export const getRoutes = async (): Promise<RouteConfig[]> => {
|
|
4
6
|
return [
|
|
5
7
|
{
|
|
6
8
|
path: "/",
|
|
7
9
|
name: "home",
|
|
8
|
-
page: () =>
|
|
10
|
+
page: async () => ({
|
|
11
|
+
default: HomePage,
|
|
12
|
+
}),
|
|
9
13
|
handle: {
|
|
10
14
|
title: "首页",
|
|
11
15
|
order: 1,
|
package/template/package.json
CHANGED
|
@@ -24,6 +24,9 @@ export function setupUnocss(
|
|
|
24
24
|
unocssConfig?: Partial<UserConfig>
|
|
25
25
|
): ReturnType<typeof unocss> {
|
|
26
26
|
return unocss({
|
|
27
|
+
// Disable auto-loading `uno.config.*` from cwd to avoid noisy
|
|
28
|
+
// "Config file not found" logs in template apps without standalone config files.
|
|
29
|
+
configFile: false,
|
|
27
30
|
presets: [
|
|
28
31
|
// 基础预设 - 包含 Tailwind CSS 兼容的工具类
|
|
29
32
|
presetUno(),
|