create-modsemi 0.1.0
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 +99 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +155 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/template/.browserslistrc +4 -0
- package/template/.env.example +9 -0
- package/template/.github/workflows/ci.yml +36 -0
- package/template/.nvmrc +2 -0
- package/template/README.md +199 -0
- package/template/_gitignore +33 -0
- package/template/_package.json +36 -0
- package/template/biome.json +37 -0
- package/template/modern.config.ts +38 -0
- package/template/orval.config.ts +98 -0
- package/template/src/api/instance.ts +87 -0
- package/template/src/components/Access/index.tsx +32 -0
- package/template/src/components/AppBreadcrumb/index.tsx +34 -0
- package/template/src/components/UserAvatar/index.less +66 -0
- package/template/src/components/UserAvatar/index.tsx +96 -0
- package/template/src/config/global.tsx +59 -0
- package/template/src/config/navigation.tsx +91 -0
- package/template/src/hooks/useAccess.ts +53 -0
- package/template/src/hooks/useMenuData.ts +171 -0
- package/template/src/hooks/usePageTitle.ts +26 -0
- package/template/src/layouts/ProLayout/DoubleLayout.tsx +157 -0
- package/template/src/layouts/ProLayout/LayoutBreadcrumb.tsx +32 -0
- package/template/src/layouts/ProLayout/MixLayout.tsx +134 -0
- package/template/src/layouts/ProLayout/SideLayout.tsx +108 -0
- package/template/src/layouts/ProLayout/TopLayout.tsx +98 -0
- package/template/src/layouts/ProLayout/index.tsx +75 -0
- package/template/src/layouts/SettingDrawer/index.tsx +390 -0
- package/template/src/modern-app-env.d.ts +1 -0
- package/template/src/modern.runtime.ts +3 -0
- package/template/src/pages/Dashboard/Workplace/index.tsx +7 -0
- package/template/src/pages/Error/NotFound/index.less +211 -0
- package/template/src/pages/Error/NotFound/index.tsx +64 -0
- package/template/src/pages/Login/index.less +491 -0
- package/template/src/pages/Login/index.tsx +204 -0
- package/template/src/pages/Welcome/index.less +351 -0
- package/template/src/pages/Welcome/index.tsx +164 -0
- package/template/src/routes/$.tsx +14 -0
- package/template/src/routes/dashboard/workplace/page.tsx +3 -0
- package/template/src/routes/layout.tsx +53 -0
- package/template/src/routes/login/page.tsx +3 -0
- package/template/src/routes/page.tsx +3 -0
- package/template/src/store/authStore.ts +61 -0
- package/template/src/store/layoutStore.ts +82 -0
- package/template/src/store/pageTitleStore.ts +12 -0
- package/template/src/styles/global.less +80 -0
- package/template/swagger/sample.json +263 -0
- package/template/tsconfig.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# create-modsemi
|
|
2
|
+
|
|
3
|
+
[English](#english) | [繁體中文](#繁體中文)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## English
|
|
8
|
+
|
|
9
|
+
Scaffold a [ModSemi](https://github.com/your-username/modsemi) project in seconds.
|
|
10
|
+
|
|
11
|
+
**ModSemi** is a React 19 + Modern.js + Semi Design admin template, similar to Ant Design Pro.
|
|
12
|
+
|
|
13
|
+
### Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm create modsemi@latest
|
|
17
|
+
# or
|
|
18
|
+
pnpm create modsemi
|
|
19
|
+
# or
|
|
20
|
+
yarn create modsemi
|
|
21
|
+
# or
|
|
22
|
+
npx create-modsemi
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Optionally pass the project name directly:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm create modsemi@latest my-app
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The CLI will ask:
|
|
32
|
+
|
|
33
|
+
1. **Project name** — used as the directory name and `package.json` name
|
|
34
|
+
2. **API proxy target** — backend URL for local dev (written into `modern.config.ts`)
|
|
35
|
+
3. **Enable Orval** — whether to include Orval API code generation + Swagger sample
|
|
36
|
+
|
|
37
|
+
### What you get
|
|
38
|
+
|
|
39
|
+
- React 19 + Modern.js 3.x + Semi Design 2.x (`@douyinfe/semi-ui-19`)
|
|
40
|
+
- 4 layout modes: Side / Top / Mix / Double (default)
|
|
41
|
+
- Auth system with Zustand persist
|
|
42
|
+
- Role-based access control (`useAccess` + `<Access>`)
|
|
43
|
+
- Dev proxy pre-configured (CORS-free local development)
|
|
44
|
+
- Biome for lint + format
|
|
45
|
+
- GitHub Actions CI (lint + build)
|
|
46
|
+
- Optional: Orval API code generation from Swagger/OpenAPI
|
|
47
|
+
|
|
48
|
+
### Requirements
|
|
49
|
+
|
|
50
|
+
- Node.js >= 20
|
|
51
|
+
- pnpm (recommended)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 繁體中文
|
|
56
|
+
|
|
57
|
+
幾秒鐘內快速建立一個 [ModSemi](https://github.com/your-username/modsemi) 專案。
|
|
58
|
+
|
|
59
|
+
**ModSemi** 是基於 React 19 + Modern.js + Semi Design 的後台管理模板,類似於 Ant Design Pro。
|
|
60
|
+
|
|
61
|
+
### 使用方式
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm create modsemi@latest
|
|
65
|
+
# 或
|
|
66
|
+
pnpm create modsemi
|
|
67
|
+
# 或
|
|
68
|
+
yarn create modsemi
|
|
69
|
+
# 或
|
|
70
|
+
npx create-modsemi
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
也可以直接傳入專案名稱:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm create modsemi@latest my-app
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
CLI 會依序詢問:
|
|
80
|
+
|
|
81
|
+
1. **專案名稱** — 作為目錄名稱與 `package.json` 的 name 欄位
|
|
82
|
+
2. **API Proxy 目標** — 本地開發時的後端 URL(寫入 `modern.config.ts`)
|
|
83
|
+
3. **啟用 Orval** — 是否加入 Orval API 程式碼生成及 Swagger 範例
|
|
84
|
+
|
|
85
|
+
### 你會得到什麼
|
|
86
|
+
|
|
87
|
+
- React 19 + Modern.js 3.x + Semi Design 2.x(`@douyinfe/semi-ui-19`)
|
|
88
|
+
- 4 種版面模式:Side / Top / Mix / Double(預設)
|
|
89
|
+
- 基於 Zustand persist 的身份驗證系統
|
|
90
|
+
- 角色型存取控制(`useAccess` + `<Access>`)
|
|
91
|
+
- 預配置的開發 Proxy(無 CORS 的本地開發環境)
|
|
92
|
+
- Biome 進行 lint + 格式化
|
|
93
|
+
- GitHub Actions CI(lint + build)
|
|
94
|
+
- 可選:從 Swagger/OpenAPI 使用 Orval 生成 API 程式碼
|
|
95
|
+
|
|
96
|
+
### 環境需求
|
|
97
|
+
|
|
98
|
+
- Node.js >= 20
|
|
99
|
+
- pnpm(建議使用)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cancel, confirm, intro, isCancel, outro, spinner, text, } from '@clack/prompts';
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { bold, cyan, dim, green, red, yellow } from 'kolorist';
|
|
7
|
+
const templateDir = resolve(fileURLToPath(import.meta.url), '../../template');
|
|
8
|
+
function toValidPackageName(name) {
|
|
9
|
+
return name
|
|
10
|
+
.trim()
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/\s+/g, '-')
|
|
13
|
+
.replace(/[^a-z0-9-_.]/g, '');
|
|
14
|
+
}
|
|
15
|
+
function replaceInFile(filePath, replacements) {
|
|
16
|
+
if (!existsSync(filePath))
|
|
17
|
+
return;
|
|
18
|
+
let content = readFileSync(filePath, 'utf-8');
|
|
19
|
+
for (const [from, to] of Object.entries(replacements)) {
|
|
20
|
+
content = content.replaceAll(from, to);
|
|
21
|
+
}
|
|
22
|
+
writeFileSync(filePath, content, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
async function main() {
|
|
25
|
+
console.log();
|
|
26
|
+
intro(bold(cyan(' create-modsemi ')));
|
|
27
|
+
console.log(dim(' React 19 + Modern.js + Semi Design admin template\n'));
|
|
28
|
+
// ── Step 1: Project name ────────────────────────────────────────
|
|
29
|
+
const rawArg = process.argv[2];
|
|
30
|
+
let projectName;
|
|
31
|
+
if (rawArg) {
|
|
32
|
+
projectName = rawArg;
|
|
33
|
+
console.log(` ${dim('Project name:')} ${projectName}`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const input = await text({
|
|
37
|
+
message: 'Project name',
|
|
38
|
+
placeholder: 'my-modsemi-app',
|
|
39
|
+
defaultValue: 'my-modsemi-app',
|
|
40
|
+
validate(value) {
|
|
41
|
+
const v = value.trim();
|
|
42
|
+
if (!v)
|
|
43
|
+
return 'Project name is required';
|
|
44
|
+
if (!/^[a-zA-Z0-9-_.]+$/.test(v))
|
|
45
|
+
return 'Use only letters, numbers, hyphens, underscores, or dots';
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
if (isCancel(input)) {
|
|
49
|
+
cancel('Cancelled');
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
projectName = input;
|
|
53
|
+
}
|
|
54
|
+
const packageName = toValidPackageName(projectName);
|
|
55
|
+
const targetDir = resolve(process.cwd(), projectName);
|
|
56
|
+
if (existsSync(targetDir)) {
|
|
57
|
+
const overwrite = await confirm({
|
|
58
|
+
message: `Directory "${projectName}" already exists. Overwrite?`,
|
|
59
|
+
});
|
|
60
|
+
if (isCancel(overwrite) || !overwrite) {
|
|
61
|
+
cancel('Cancelled');
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
// ── Step 2: API proxy target ────────────────────────────────────
|
|
67
|
+
const proxyInput = await text({
|
|
68
|
+
message: 'API proxy target (backend URL for local dev)',
|
|
69
|
+
placeholder: 'http://localhost:3001',
|
|
70
|
+
defaultValue: 'http://localhost:3001',
|
|
71
|
+
validate(value) {
|
|
72
|
+
const v = value.trim();
|
|
73
|
+
if (!v)
|
|
74
|
+
return 'Proxy target is required';
|
|
75
|
+
if (!/^https?:\/\/.+/.test(v))
|
|
76
|
+
return 'Must be a valid http/https URL';
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
if (isCancel(proxyInput)) {
|
|
80
|
+
cancel('Cancelled');
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
const proxyTarget = proxyInput;
|
|
84
|
+
// ── Step 3: Orval API code generation ──────────────────────────
|
|
85
|
+
const useOrval = await confirm({
|
|
86
|
+
message: 'Enable Orval API code generation? (requires Swagger/OpenAPI spec)',
|
|
87
|
+
initialValue: true,
|
|
88
|
+
});
|
|
89
|
+
if (isCancel(useOrval)) {
|
|
90
|
+
cancel('Cancelled');
|
|
91
|
+
process.exit(0);
|
|
92
|
+
}
|
|
93
|
+
// ── Step 4: Scaffold ───────────────────────────────────────────
|
|
94
|
+
const s = spinner();
|
|
95
|
+
s.start('Creating project...');
|
|
96
|
+
try {
|
|
97
|
+
mkdirSync(targetDir, { recursive: true });
|
|
98
|
+
// Copy template files
|
|
99
|
+
cpSync(templateDir, targetDir, { recursive: true });
|
|
100
|
+
// Rename _package.json → package.json
|
|
101
|
+
renameSync(join(targetDir, '_package.json'), join(targetDir, 'package.json'));
|
|
102
|
+
// Rename _gitignore → .gitignore
|
|
103
|
+
renameSync(join(targetDir, '_gitignore'), join(targetDir, '.gitignore'));
|
|
104
|
+
// Replace {{projectName}} in package.json
|
|
105
|
+
replaceInFile(join(targetDir, 'package.json'), {
|
|
106
|
+
'{{projectName}}': packageName,
|
|
107
|
+
});
|
|
108
|
+
// Replace proxy target in modern.config.ts
|
|
109
|
+
replaceInFile(join(targetDir, 'modern.config.ts'), {
|
|
110
|
+
'http://localhost:3001': proxyTarget,
|
|
111
|
+
});
|
|
112
|
+
// Remove Orval files if not needed
|
|
113
|
+
if (!useOrval) {
|
|
114
|
+
rmSync(join(targetDir, 'orval.config.ts'), { force: true });
|
|
115
|
+
rmSync(join(targetDir, 'swagger'), { recursive: true, force: true });
|
|
116
|
+
// Remove orval scripts and dependency from package.json
|
|
117
|
+
const pkgPath = join(targetDir, 'package.json');
|
|
118
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
119
|
+
delete pkg.scripts['api:gen'];
|
|
120
|
+
delete pkg.scripts['api:gen:watch'];
|
|
121
|
+
if (pkg.devDependencies)
|
|
122
|
+
delete pkg.devDependencies.orval;
|
|
123
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
124
|
+
}
|
|
125
|
+
s.stop(green('Project created!'));
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
s.stop(red('Failed to create project'));
|
|
129
|
+
console.error(err);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
// ── Done ────────────────────────────────────────────────────────
|
|
133
|
+
console.log();
|
|
134
|
+
outro(bold(green(`Done! Your project is ready at ${cyan(projectName)}/`)));
|
|
135
|
+
console.log(`
|
|
136
|
+
${bold('Next steps:')}
|
|
137
|
+
|
|
138
|
+
${dim('$')} ${cyan(`cd ${projectName}`)}
|
|
139
|
+
${dim('$')} ${cyan('pnpm install')}
|
|
140
|
+
${dim('$')} ${cyan('pnpm dev')}
|
|
141
|
+
${useOrval ? `
|
|
142
|
+
${bold('API code generation:')}
|
|
143
|
+
|
|
144
|
+
1. Put your Swagger/OpenAPI JSON in ${yellow('swagger/')}
|
|
145
|
+
2. Update ${yellow('orval.config.ts')} with your spec path
|
|
146
|
+
${dim('$')} ${cyan('pnpm api:gen')}
|
|
147
|
+
` : ''}
|
|
148
|
+
${dim('Docs:')} https://github.com/your-username/modsemi
|
|
149
|
+
`);
|
|
150
|
+
}
|
|
151
|
+
main().catch(err => {
|
|
152
|
+
console.error(red('Error:'), err);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
});
|
|
155
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EACL,MAAM,EACN,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EACL,OAAO,EACP,IAAI,GACL,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,MAAM,EACN,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAE/D,MAAM,WAAW,GAAG,OAAO,CACzB,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAC9B,gBAAgB,CACjB,CAAC;AAEF,SAAS,kBAAkB,CAAC,IAAY;IACtC,OAAO,IAAI;SACR,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB,EAAE,YAAoC;IAC3E,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO;IAClC,IAAI,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACtD,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC,CAAC;IAE1E,mEAAmE;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,WAAmB,CAAC;IAExB,IAAI,MAAM,EAAE,CAAC;QACX,WAAW,GAAG,MAAM,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,eAAe,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;YACvB,OAAO,EAAE,cAAc;YACvB,WAAW,EAAE,gBAAgB;YAC7B,YAAY,EAAE,gBAAgB;YAC9B,QAAQ,CAAC,KAAK;gBACZ,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,CAAC;oBAAE,OAAO,0BAA0B,CAAC;gBAC1C,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;oBAAE,OAAO,0DAA0D,CAAC;YACtG,CAAC;SACF,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;QAC9D,WAAW,GAAG,KAAe,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;IAEtD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC;YAC9B,OAAO,EAAE,cAAc,WAAW,8BAA8B;SACjE,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;QAChF,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,mEAAmE;IACnE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;QAC5B,OAAO,EAAE,8CAA8C;QACvD,WAAW,EAAE,uBAAuB;QACpC,YAAY,EAAE,uBAAuB;QACrC,QAAQ,CAAC,KAAK;YACZ,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,CAAC;gBAAE,OAAO,0BAA0B,CAAC;YAC1C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,OAAO,gCAAgC,CAAC;QACzE,CAAC;KACF,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IACnE,MAAM,WAAW,GAAG,UAAoB,CAAC;IAEzC,kEAAkE;IAClE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;QAC7B,OAAO,EAAE,mEAAmE;QAC5E,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAEjE,kEAAkE;IAClE,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;IACpB,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAE/B,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1C,sBAAsB;QACtB,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpD,sCAAsC;QACtC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;QAE9E,iCAAiC;QACjC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QAEzE,0CAA0C;QAC1C,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE;YAC7C,iBAAiB,EAAE,WAAW;SAC/B,CAAC,CAAC;QAEH,2CAA2C;QAC3C,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,EAAE;YACjD,uBAAuB,EAAE,WAAW;SACrC,CAAC,CAAC;QAEH,mCAAmC;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAErE,wDAAwD;YACxD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YACvD,OAAO,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC9B,OAAO,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,GAAG,CAAC,eAAe;gBAAE,OAAO,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC;YAC1D,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACvE,CAAC;QAED,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,mEAAmE;IACnE,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,kCAAkC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAE3E,OAAO,CAAC,GAAG,CAAC;IACV,IAAI,CAAC,aAAa,CAAC;;MAEjB,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,WAAW,EAAE,CAAC;MACrC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC;MAChC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC;EAChC,QAAQ,CAAC,CAAC,CAAC;IACT,IAAI,CAAC,sBAAsB,CAAC;;0CAEU,MAAM,CAAC,UAAU,CAAC;gBAC5C,MAAM,CAAC,iBAAiB,CAAC;MACnC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC;CACrC,CAAC,CAAC,CAAC,EAAE;IACF,GAAG,CAAC,OAAO,CAAC;GACb,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-modsemi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create a ModSemi project — React 19 + Modern.js + Semi Design admin template",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-modsemi": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"template"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsc --watch"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"modsemi",
|
|
19
|
+
"modern.js",
|
|
20
|
+
"semi-design",
|
|
21
|
+
"react",
|
|
22
|
+
"admin",
|
|
23
|
+
"template",
|
|
24
|
+
"scaffold"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@clack/prompts": "^0.9.1",
|
|
29
|
+
"kolorist": "^1.8.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^20",
|
|
33
|
+
"typescript": "~5.7.3"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# ModSemi 環境變數範本
|
|
2
|
+
# 複製此檔案為 .env.local 並依實際環境填寫
|
|
3
|
+
# .env.local 已加入 .gitignore,不會被提交到版本控制
|
|
4
|
+
|
|
5
|
+
# ── API ──────────────────────────────────────────────
|
|
6
|
+
# 前端 axios instance 的 baseURL
|
|
7
|
+
# 本地開發時若使用 dev.server.proxy,此值保持 /api 即可
|
|
8
|
+
# 正式環境改為後端實際位址
|
|
9
|
+
MODERN_APP_API_BASE_URL=/api
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
ci:
|
|
11
|
+
name: Lint & Build
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Setup pnpm
|
|
19
|
+
uses: pnpm/action-setup@v4
|
|
20
|
+
with:
|
|
21
|
+
version: latest
|
|
22
|
+
|
|
23
|
+
- name: Setup Node.js
|
|
24
|
+
uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: 20
|
|
27
|
+
cache: pnpm
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: pnpm install --frozen-lockfile
|
|
31
|
+
|
|
32
|
+
- name: Lint
|
|
33
|
+
run: pnpm lint
|
|
34
|
+
|
|
35
|
+
- name: Build
|
|
36
|
+
run: pnpm build
|
package/template/.nvmrc
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# ModSemi
|
|
2
|
+
|
|
3
|
+
基于 **React 19 + Modern.js + Semi Design** 打造的开箱即用中台前端 / 设计解决方案,类似 Ant Design Pro,提供完整的中后台页面框架与组件体系。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 技术栈
|
|
8
|
+
|
|
9
|
+
| 技术 | 版本 | 说明 |
|
|
10
|
+
|------|------|------|
|
|
11
|
+
| [React](https://react.dev) | 19 | 最新版 React,支持并发特性 |
|
|
12
|
+
| [Modern.js](https://modernjs.dev) | 3.x | 字节跳动开源的全栈框架,内置路由、构建、SSR |
|
|
13
|
+
| [Semi Design](https://semi.design) | 2.x(React 19 适配版) | 字节跳动企业级 UI 组件库,`@douyinfe/semi-ui-19` |
|
|
14
|
+
| [TypeScript](https://www.typescriptlang.org) | ~5.7 | 全量类型支持 |
|
|
15
|
+
| [Biome](https://biomejs.dev) | 1.9 | 高性能代码格式化 & Lint 工具 |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 环境要求
|
|
20
|
+
|
|
21
|
+
- **Node.js** >= 20
|
|
22
|
+
- **pnpm**(推荐)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 快速開始
|
|
27
|
+
|
|
28
|
+
### 方式一:使用 degit(推薦,不保留 git 歷史)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx degit your-username/modsemi my-app
|
|
32
|
+
cd my-app
|
|
33
|
+
pnpm install
|
|
34
|
+
pnpm dev
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 方式二:使用 GitHub Template
|
|
38
|
+
|
|
39
|
+
點擊右上角 **"Use this template"** 建立自己的 repo,再 clone 下來:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/your-username/my-app.git
|
|
43
|
+
cd my-app
|
|
44
|
+
pnpm install
|
|
45
|
+
pnpm dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 環境設定
|
|
51
|
+
|
|
52
|
+
### API Proxy(本地開發)
|
|
53
|
+
|
|
54
|
+
複製環境變數範本,依需求調整:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cp .env.example .env.local
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
預設 `MODERN_APP_API_BASE_URL=/api`,搭配 `modern.config.ts` 的 `dev.server.proxy`,所有 `/api/**` 請求會在 Dev Server 端轉發給後端,瀏覽器不會觸發 CORS。修改 proxy target:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// modern.config.ts
|
|
64
|
+
dev: {
|
|
65
|
+
server: {
|
|
66
|
+
proxy: {
|
|
67
|
+
'/api': {
|
|
68
|
+
target: 'http://localhost:3001', // ← 改為後端位址
|
|
69
|
+
changeOrigin: true,
|
|
70
|
+
pathRewrite: { '^/api': '' },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 本地覆蓋設定(modern.config.local.*)
|
|
78
|
+
|
|
79
|
+
Modern.js 支援 local override,在本機建立 `modern.config.local.ts`(已加入 `.gitignore`)可覆蓋任意設定,不影響其他人的開發環境:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// modern.config.local.ts(只在本機生效)
|
|
83
|
+
import { defineConfig } from '@modern-js/app-tools';
|
|
84
|
+
|
|
85
|
+
export default defineConfig({
|
|
86
|
+
dev: {
|
|
87
|
+
port: 8080, // 改本機 port
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 安装与启动
|
|
95
|
+
|
|
96
|
+
### 1. 安装依赖
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pnpm install
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. 启动开发服务器
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pnpm dev
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 3. 构建生产版本
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pnpm build
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 4. 预览生产构建
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
pnpm serve
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 5. 代码检查
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pnpm lint
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 主要依赖说明
|
|
129
|
+
|
|
130
|
+
### 运行时依赖
|
|
131
|
+
|
|
132
|
+
| 包名 | 说明 |
|
|
133
|
+
|------|------|
|
|
134
|
+
| `@douyinfe/semi-ui-19` | Semi Design React 19 兼容版 UI 组件库 |
|
|
135
|
+
| `@modern-js/runtime` | Modern.js 运行时模块(路由、数据获取等) |
|
|
136
|
+
| `react` / `react-dom` | React 19 核心库 |
|
|
137
|
+
|
|
138
|
+
### 开发依赖
|
|
139
|
+
|
|
140
|
+
| 包名 | 说明 |
|
|
141
|
+
|------|------|
|
|
142
|
+
| `@modern-js/app-tools` | Modern.js 构建与开发工具链 |
|
|
143
|
+
| `@biomejs/biome` | 代码格式化与 Lint |
|
|
144
|
+
| `typescript` | TypeScript 编译器 |
|
|
145
|
+
| `@types/react` / `@types/react-dom` | React 类型声明 |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## MCP 集成(Semi Design MCP)
|
|
150
|
+
|
|
151
|
+
Semi Design 提供了官方 MCP(Model Context Protocol)服务,可让 AI 编码助手(如 Cursor、Trae)直接查阅组件文档与源码,显著提升开发效率。
|
|
152
|
+
|
|
153
|
+
### 安装配置
|
|
154
|
+
|
|
155
|
+
在 Cursor 或 Trae 的 MCP 设置中添加以下配置:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"mcpServers": {
|
|
160
|
+
"semi-mcp": {
|
|
161
|
+
"command": "npx",
|
|
162
|
+
"args": ["-y", "@douyinfe/semi-mcp"]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> **字节内网用户**请将包名替换为 `@ies/semi-mcp-bytedance`。
|
|
169
|
+
|
|
170
|
+
### 可用工具
|
|
171
|
+
|
|
172
|
+
配置完成后,AI 助手可使用以下 MCP 工具:
|
|
173
|
+
|
|
174
|
+
| 工具 | 功能 |
|
|
175
|
+
|------|------|
|
|
176
|
+
| `get_semi_document` | 获取组件文档(Button、Table、Form 等)及专题文档(主题定制、黑暗模式、更新日志等) |
|
|
177
|
+
| `get_semi_code_block` | 获取文档中的具体代码示例(大文档中代码块被折叠时使用) |
|
|
178
|
+
| `get_component_file_list` | 列出某个组件的所有源文件路径 |
|
|
179
|
+
| `get_file_code` | 获取组件源文件代码(大文件显示结构,小文件显示完整内容) |
|
|
180
|
+
| `get_function_code` | 获取组件源码中某个具体函数的完整实现 |
|
|
181
|
+
|
|
182
|
+
### 使用示例
|
|
183
|
+
|
|
184
|
+
配置完成后,直接在 AI 对话中描述需求即可,无需手动查阅文档:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
帮我用 Semi Design 实现一个带搜索和分页的 Table 组件
|
|
188
|
+
帮我查一下 Semi Design Form 的表单验证用法
|
|
189
|
+
Semi Design 怎么做主题定制?
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 参考文档
|
|
195
|
+
|
|
196
|
+
- [Modern.js 文档](https://modernjs.dev/en)
|
|
197
|
+
- [Semi Design 文档](https://semi.design/zh-CN)
|
|
198
|
+
- [Semi Design React 19 迁移指南](https://semi.design/zh-CN/start/update-to-v2)
|
|
199
|
+
- [React 19 文档](https://react.dev)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
|
|
3
|
+
.pnp
|
|
4
|
+
.pnp.js
|
|
5
|
+
.env.local
|
|
6
|
+
.env.*.local
|
|
7
|
+
.history
|
|
8
|
+
*.log*
|
|
9
|
+
|
|
10
|
+
node_modules/
|
|
11
|
+
.yarn-integrity
|
|
12
|
+
.pnpm-store/
|
|
13
|
+
*.tsbuildinfo
|
|
14
|
+
.changeset/pre.json
|
|
15
|
+
|
|
16
|
+
dist/
|
|
17
|
+
coverage/
|
|
18
|
+
release/
|
|
19
|
+
output/
|
|
20
|
+
output_resource/
|
|
21
|
+
log/
|
|
22
|
+
|
|
23
|
+
.vscode/**/*
|
|
24
|
+
!.vscode/settings.json
|
|
25
|
+
!.vscode/extensions.json
|
|
26
|
+
.idea/
|
|
27
|
+
|
|
28
|
+
**/*/typings/auto-generated
|
|
29
|
+
|
|
30
|
+
modern.config.local.*
|
|
31
|
+
|
|
32
|
+
# orval 生成的檔案(由 pnpm api:gen 自動產生)
|
|
33
|
+
src/api/generated/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "modern dev",
|
|
6
|
+
"build": "modern build",
|
|
7
|
+
"serve": "modern serve",
|
|
8
|
+
"lint": "biome check",
|
|
9
|
+
"api:gen": "orval",
|
|
10
|
+
"api:gen:watch": "orval --watch"
|
|
11
|
+
},
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=20"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@douyinfe/semi-icons": "^2.94.0",
|
|
17
|
+
"@douyinfe/semi-icons-lab": "^2.94.1",
|
|
18
|
+
"@douyinfe/semi-ui-19": "^2.94.0",
|
|
19
|
+
"@modern-js/runtime": "3.1.3",
|
|
20
|
+
"axios": "^1.15.0",
|
|
21
|
+
"react": "^19.2.3",
|
|
22
|
+
"react-dom": "^19.2.0",
|
|
23
|
+
"zustand": "^5.0.12"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@biomejs/biome": "1.9.4",
|
|
27
|
+
"@modern-js/app-tools": "3.1.3",
|
|
28
|
+
"@modern-js/tsconfig": "3.1.3",
|
|
29
|
+
"@types/node": "^20",
|
|
30
|
+
"@types/react": "^19.1.8",
|
|
31
|
+
"@types/react-dom": "^19.1.6",
|
|
32
|
+
"less": "^4.6.4",
|
|
33
|
+
"orval": "^8.7.0",
|
|
34
|
+
"typescript": "~5.7.3"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"defaultBranch": "main",
|
|
6
|
+
"clientKind": "git",
|
|
7
|
+
"useIgnoreFile": true
|
|
8
|
+
},
|
|
9
|
+
"formatter": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"indentStyle": "space"
|
|
12
|
+
},
|
|
13
|
+
"javascript": {
|
|
14
|
+
"formatter": {
|
|
15
|
+
"quoteStyle": "single",
|
|
16
|
+
"arrowParentheses": "asNeeded",
|
|
17
|
+
"jsxQuoteStyle": "double",
|
|
18
|
+
"lineWidth": 80
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"linter": {
|
|
22
|
+
"enabled": true,
|
|
23
|
+
"rules": {
|
|
24
|
+
"recommended": true,
|
|
25
|
+
"suspicious": {
|
|
26
|
+
"noDuplicateFontNames": "off"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"organizeImports": {
|
|
31
|
+
"enabled": true
|
|
32
|
+
},
|
|
33
|
+
"files": {
|
|
34
|
+
"ignoreUnknown": true,
|
|
35
|
+
"ignore": [".vscode/**/*", "node_modules/**/*", "dist/**/*"]
|
|
36
|
+
}
|
|
37
|
+
}
|