@ubean/cli 0.1.8 → 0.1.10
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/dist/cli.js +27 -592
- package/dist/index.js +1 -1
- package/dist/page-VyP_7yLT.js +1680 -0
- package/package.json +12 -12
- package/dist/page-Cmp7s9l2.js +0 -672
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as createFsOps, S as renderTemplate, a as scaffold, c as scaffoldStarterTemplate, i as recoverScaffold, l as scaffoldUnifyTemplate, n as listScaffoldableFiles, o as scaffoldBlogTemplate, r as pageCommand, s as scaffoldMinimalTemplate, t as deleteScaffold } from "./page-VyP_7yLT.js";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { extname, normalize } from "node:path";
|
|
4
4
|
import { consola } from "consola";
|
|
@@ -847,13 +847,17 @@ SESSION_SECRET=your-session-secret
|
|
|
847
847
|
//#region src/init.ts
|
|
848
848
|
const logger$3 = consola.withTag("ubean-cli");
|
|
849
849
|
const TEMPLATES = [
|
|
850
|
+
{
|
|
851
|
+
value: "unify",
|
|
852
|
+
label: "Unify (recommended, full-stack with islands/i18n/layouts/middleware)"
|
|
853
|
+
},
|
|
850
854
|
{
|
|
851
855
|
value: "minimal",
|
|
852
856
|
label: "Minimal (just a hello world page)"
|
|
853
857
|
},
|
|
854
858
|
{
|
|
855
859
|
value: "starter",
|
|
856
|
-
label: "Starter (
|
|
860
|
+
label: "Starter (includes pages/api/layouts)"
|
|
857
861
|
},
|
|
858
862
|
{
|
|
859
863
|
value: "blog",
|
|
@@ -934,559 +938,6 @@ async function confirm(question, defaultValue = true) {
|
|
|
934
938
|
function isNonInteractive() {
|
|
935
939
|
return !process.stdin.isTTY || process.env.CI !== void 0 || process.env.NONINTERACTIVE !== void 0;
|
|
936
940
|
}
|
|
937
|
-
const PACKAGE_JSON_TEMPLATE = `{
|
|
938
|
-
"name": "{{name}}",
|
|
939
|
-
"private": true,
|
|
940
|
-
"type": "module",
|
|
941
|
-
"scripts": {
|
|
942
|
-
"dev": "ubean dev",
|
|
943
|
-
"build": "ubean build",
|
|
944
|
-
"preview": "ubean preview",
|
|
945
|
-
"prepare": "ubean prepare",
|
|
946
|
-
"typecheck": "vue-tsc --noEmit"
|
|
947
|
-
},
|
|
948
|
-
"dependencies": {
|
|
949
|
-
"ubean": "latest",
|
|
950
|
-
"vue": "^3.5.0"
|
|
951
|
-
},
|
|
952
|
-
"devDependencies": {
|
|
953
|
-
"typescript": "^5.6.0",
|
|
954
|
-
"vue-tsc": "^2.1.0"
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
`;
|
|
958
|
-
const TSCONFIG_TEMPLATE = `{
|
|
959
|
-
"compilerOptions": {
|
|
960
|
-
"target": "ESNext",
|
|
961
|
-
"module": "ESNext",
|
|
962
|
-
"moduleResolution": "Bundler",
|
|
963
|
-
"strict": true,
|
|
964
|
-
"jsx": "preserve",
|
|
965
|
-
"resolveJsonModule": true,
|
|
966
|
-
"esModuleInterop": true,
|
|
967
|
-
"skipLibCheck": true,
|
|
968
|
-
"isolatedModules": true,
|
|
969
|
-
"allowImportingTsExtensions": true,
|
|
970
|
-
"noEmit": true,
|
|
971
|
-
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
972
|
-
"types": ["ubean/client"]
|
|
973
|
-
},
|
|
974
|
-
"include": ["src/**/*.ts", "src/**/*.vue", ".ubean/**/*.d.ts"],
|
|
975
|
-
"exclude": ["node_modules", "dist"]
|
|
976
|
-
}
|
|
977
|
-
`;
|
|
978
|
-
const UBEAN_CONFIG_TEMPLATE = `import { defineConfig } from 'ubean';
|
|
979
|
-
|
|
980
|
-
export default defineConfig({
|
|
981
|
-
srcDir: 'src',
|
|
982
|
-
preset: '{{preset}}'
|
|
983
|
-
});
|
|
984
|
-
`;
|
|
985
|
-
const APP_VUE_TEMPLATE = `<template>
|
|
986
|
-
<div id="app">
|
|
987
|
-
<RouterView />
|
|
988
|
-
</div>
|
|
989
|
-
</template>
|
|
990
|
-
|
|
991
|
-
<script setup lang="ts">
|
|
992
|
-
import { RouterView } from 'vue-router';
|
|
993
|
-
<\/script>
|
|
994
|
-
|
|
995
|
-
<style>
|
|
996
|
-
* {
|
|
997
|
-
margin: 0;
|
|
998
|
-
padding: 0;
|
|
999
|
-
box-sizing: border-box;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
body {
|
|
1003
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
#app {
|
|
1007
|
-
min-height: 100vh;
|
|
1008
|
-
}
|
|
1009
|
-
</style>
|
|
1010
|
-
`;
|
|
1011
|
-
const INDEX_PAGE_TEMPLATE = `<template>
|
|
1012
|
-
<div class="home-page">
|
|
1013
|
-
<h1>Welcome to ubean</h1>
|
|
1014
|
-
<p>Your Vue meta framework is ready! 🚀</p>
|
|
1015
|
-
<div class="links">
|
|
1016
|
-
<RouterLink to="/about">About</RouterLink>
|
|
1017
|
-
</div>
|
|
1018
|
-
</div>
|
|
1019
|
-
</template>
|
|
1020
|
-
|
|
1021
|
-
<script setup lang="ts">
|
|
1022
|
-
import { RouterLink } from 'vue-router';
|
|
1023
|
-
|
|
1024
|
-
definePage({
|
|
1025
|
-
meta: {
|
|
1026
|
-
title: 'Home'
|
|
1027
|
-
}
|
|
1028
|
-
});
|
|
1029
|
-
<\/script>
|
|
1030
|
-
|
|
1031
|
-
<style scoped>
|
|
1032
|
-
.home-page {
|
|
1033
|
-
display: flex;
|
|
1034
|
-
flex-direction: column;
|
|
1035
|
-
align-items: center;
|
|
1036
|
-
justify-content: center;
|
|
1037
|
-
min-height: 100vh;
|
|
1038
|
-
padding: 2rem;
|
|
1039
|
-
text-align: center;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
h1 {
|
|
1043
|
-
font-size: 3rem;
|
|
1044
|
-
margin-bottom: 1rem;
|
|
1045
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
1046
|
-
-webkit-background-clip: text;
|
|
1047
|
-
-webkit-text-fill-color: transparent;
|
|
1048
|
-
background-clip: text;
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
p {
|
|
1052
|
-
color: #666;
|
|
1053
|
-
font-size: 1.2rem;
|
|
1054
|
-
margin-bottom: 2rem;
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
.links {
|
|
1058
|
-
display: flex;
|
|
1059
|
-
gap: 1rem;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
a {
|
|
1063
|
-
padding: 0.75rem 1.5rem;
|
|
1064
|
-
border-radius: 8px;
|
|
1065
|
-
background: #667eea;
|
|
1066
|
-
color: white;
|
|
1067
|
-
text-decoration: none;
|
|
1068
|
-
font-weight: 500;
|
|
1069
|
-
transition: all 0.2s;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
a:hover {
|
|
1073
|
-
background: #5a67d8;
|
|
1074
|
-
transform: translateY(-1px);
|
|
1075
|
-
}
|
|
1076
|
-
</style>
|
|
1077
|
-
`;
|
|
1078
|
-
const ABOUT_PAGE_TEMPLATE = `<template>
|
|
1079
|
-
<div class="about-page">
|
|
1080
|
-
<h1>About</h1>
|
|
1081
|
-
<p>This page is built with ubean.</p>
|
|
1082
|
-
<RouterLink to="/">Back to Home</RouterLink>
|
|
1083
|
-
</div>
|
|
1084
|
-
</template>
|
|
1085
|
-
|
|
1086
|
-
<script setup lang="ts">
|
|
1087
|
-
import { RouterLink } from 'vue-router';
|
|
1088
|
-
|
|
1089
|
-
definePage({
|
|
1090
|
-
meta: {
|
|
1091
|
-
title: 'About'
|
|
1092
|
-
}
|
|
1093
|
-
});
|
|
1094
|
-
<\/script>
|
|
1095
|
-
|
|
1096
|
-
<style scoped>
|
|
1097
|
-
.about-page {
|
|
1098
|
-
max-width: 800px;
|
|
1099
|
-
margin: 0 auto;
|
|
1100
|
-
padding: 3rem 2rem;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
h1 {
|
|
1104
|
-
margin-bottom: 1rem;
|
|
1105
|
-
color: #333;
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
p {
|
|
1109
|
-
color: #666;
|
|
1110
|
-
line-height: 1.6;
|
|
1111
|
-
margin-bottom: 2rem;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
a {
|
|
1115
|
-
color: #667eea;
|
|
1116
|
-
text-decoration: none;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
a:hover {
|
|
1120
|
-
text-decoration: underline;
|
|
1121
|
-
}
|
|
1122
|
-
</style>
|
|
1123
|
-
`;
|
|
1124
|
-
const HELLO_API_TEMPLATE = `import { defineHandler } from 'ubean';
|
|
1125
|
-
|
|
1126
|
-
export const GET = defineHandler(c => {
|
|
1127
|
-
return c.json({
|
|
1128
|
-
message: 'Hello from ubean API!',
|
|
1129
|
-
timestamp: Date.now()
|
|
1130
|
-
});
|
|
1131
|
-
});
|
|
1132
|
-
`;
|
|
1133
|
-
/**
|
|
1134
|
-
* 类型化请求客户端模板 - 浏览器端
|
|
1135
|
-
*
|
|
1136
|
-
* 启动 dev server 后,ubean 会自动生成 .ubean/openapi.d.ts(包含项目所有 API 的 paths 类型)。
|
|
1137
|
-
* 本文件将 paths 类型绑定到 createTypedClient,使浏览器端请求的路径、参数、请求体和返回值都获得类型安全。
|
|
1138
|
-
*
|
|
1139
|
-
* 使用方式:
|
|
1140
|
-
* import { api } from '../request/client';
|
|
1141
|
-
* const user = await api.get('/api/users/{id}', { params: { path: { id: 1 } } });
|
|
1142
|
-
*/
|
|
1143
|
-
const REQUEST_CLIENT_TEMPLATE = `import { createRequest } from '@soybeanjs/fetch';
|
|
1144
|
-
import { createTypedClient, toFlatTypedClient } from '@soybeanjs/fetch/openapi';
|
|
1145
|
-
import type { paths } from '../../.ubean/openapi';
|
|
1146
|
-
|
|
1147
|
-
/**
|
|
1148
|
-
* 底层 HTTP 请求实例(@soybeanjs/fetch 封装)。
|
|
1149
|
-
*
|
|
1150
|
-
* api 和 flatApi 共用同一份 RequestInstance,共享 baseURL/timeout/headers/state 等。
|
|
1151
|
-
* 调整配置时只需修改此处一处。
|
|
1152
|
-
*/
|
|
1153
|
-
const request = createRequest({
|
|
1154
|
-
// baseURL: '/api', // 按需设置 API 基础路径
|
|
1155
|
-
// timeout: 10000,
|
|
1156
|
-
});
|
|
1157
|
-
|
|
1158
|
-
/**
|
|
1159
|
-
* 浏览器端类型化 HTTP 客户端(抛异常模式)
|
|
1160
|
-
*
|
|
1161
|
-
* 路径、参数、请求体和返回值类型均从 OpenAPI schema 自动推断。
|
|
1162
|
-
* 启动 dev server 后类型会自动更新(.ubean/openapi.d.ts)。
|
|
1163
|
-
*
|
|
1164
|
-
* 支持通过 responseType 配置不同的返回类型:
|
|
1165
|
-
* - 'json' (默认): 返回解析后的 JSON 数据
|
|
1166
|
-
* - 'blob': 返回 { file: Blob; filename: string; contentType: string }
|
|
1167
|
-
* - 'text': 返回 string
|
|
1168
|
-
* - 'arraybuffer': 返回 { file: ArrayBuffer; filename: string; contentType: string }
|
|
1169
|
-
*
|
|
1170
|
-
* @example
|
|
1171
|
-
* import { api } from '../request/client';
|
|
1172
|
-
*
|
|
1173
|
-
* // JSON 请求(默认)
|
|
1174
|
-
* const user = await api.get('/api/users/{id}', { pathParams: { id: 1 } });
|
|
1175
|
-
*
|
|
1176
|
-
* // 文件下载
|
|
1177
|
-
* const file = await api.get('/api/export', { responseType: 'blob' });
|
|
1178
|
-
* // file: { file: Blob; filename: string; contentType: string }
|
|
1179
|
-
*
|
|
1180
|
-
* // 文本
|
|
1181
|
-
* const text = await api.get('/api/readme', { responseType: 'text' });
|
|
1182
|
-
* // text: string
|
|
1183
|
-
*/
|
|
1184
|
-
export const api = createTypedClient<paths>(request);
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
* 扁平模式类型化 HTTP 客户端(不抛异常,通过返回值判断)
|
|
1188
|
-
*
|
|
1189
|
-
* toFlatTypedClient 接收同一个 RequestInstance,内部通过 withResponse + try/catch
|
|
1190
|
-
* 实现扁平化返回,与 api 共享 state/cache/auth。
|
|
1191
|
-
*
|
|
1192
|
-
* 返回 { data, error, response } — 成功时 error 为 null,失败时 data 为 null。
|
|
1193
|
-
* 接口与 api 一致,同样支持 responseType。
|
|
1194
|
-
*
|
|
1195
|
-
* @example
|
|
1196
|
-
* import { flatApi } from '../request/client';
|
|
1197
|
-
*
|
|
1198
|
-
* const { data, error } = await flatApi.get('/api/users/{id}', {
|
|
1199
|
-
* pathParams: { id: 1 }
|
|
1200
|
-
* });
|
|
1201
|
-
* if (error) {
|
|
1202
|
-
* console.error('Failed:', error.message);
|
|
1203
|
-
* } else {
|
|
1204
|
-
* console.log('User:', data);
|
|
1205
|
-
* }
|
|
1206
|
-
*/
|
|
1207
|
-
export const flatApi = toFlatTypedClient<paths>(request);
|
|
1208
|
-
`;
|
|
1209
|
-
/**
|
|
1210
|
-
* 类型化请求客户端模板 - server 端内部调度
|
|
1211
|
-
*
|
|
1212
|
-
* 在 API 路由或 useData 的 fetcher 中使用,自动转发 cookie/authorization 等请求头。
|
|
1213
|
-
* 与 client.ts 接口一致,但内部通过 createInternalAdapter + @soybeanjs/fetch 发起请求(进程内调度)。
|
|
1214
|
-
*
|
|
1215
|
-
* 使用方式:
|
|
1216
|
-
* import { createServerApi } from '../request/internal';
|
|
1217
|
-
* export const GET = defineHandler(async (c) => {
|
|
1218
|
-
* const api = createServerApi(c);
|
|
1219
|
-
* const user = await api.get('/api/users/{id}', { pathParams: { id: 1 } });
|
|
1220
|
-
* return c.json(user);
|
|
1221
|
-
* });
|
|
1222
|
-
*/
|
|
1223
|
-
const REQUEST_INTERNAL_TEMPLATE = `import { createInternalAdapter } from 'ubean';
|
|
1224
|
-
import { createRequest } from '@soybeanjs/fetch';
|
|
1225
|
-
import { createTypedClient } from '@soybeanjs/fetch/openapi';
|
|
1226
|
-
import type { paths } from '../../.ubean/openapi';
|
|
1227
|
-
|
|
1228
|
-
/**
|
|
1229
|
-
* server 端类型化内部 fetch
|
|
1230
|
-
*
|
|
1231
|
-
* 在 API 路由或 useData 的 fetcher 中使用,自动转发 cookie/authorization 等请求头。
|
|
1232
|
-
* 与 client.ts 的 api 接口一致,但通过进程内调度发起请求(不发起新的网络请求)。
|
|
1233
|
-
*
|
|
1234
|
-
* @example
|
|
1235
|
-
* // src/routes/api/posts.ts
|
|
1236
|
-
* import { defineHandler } from 'ubean';
|
|
1237
|
-
* import { createServerApi } from '../request/internal';
|
|
1238
|
-
*
|
|
1239
|
-
* export const GET = defineHandler(async (c) => {
|
|
1240
|
-
* const api = createServerApi(c);
|
|
1241
|
-
* const user = await api.get('/api/users/{id}', { pathParams: { id: 1 } });
|
|
1242
|
-
* return c.json(user);
|
|
1243
|
-
* });
|
|
1244
|
-
*
|
|
1245
|
-
* @example
|
|
1246
|
-
* // 在 useData 中使用
|
|
1247
|
-
* import { useData, defineHandler } from 'ubean';
|
|
1248
|
-
* import { createServerApi } from '../request/internal';
|
|
1249
|
-
*
|
|
1250
|
-
* export const GET = defineHandler(async (c) => {
|
|
1251
|
-
* const api = createServerApi(c);
|
|
1252
|
-
* const result = await useData({
|
|
1253
|
-
* fetcher: async () => api.get('/api/users/{id}', { pathParams: { id: 1 } })
|
|
1254
|
-
* });
|
|
1255
|
-
* return c.json(result.data);
|
|
1256
|
-
* });
|
|
1257
|
-
*/
|
|
1258
|
-
export function createServerApi(context: Parameters<typeof createInternalAdapter>[0]) {
|
|
1259
|
-
const adapter = createInternalAdapter(context);
|
|
1260
|
-
const request = createRequest(
|
|
1261
|
-
{ retry: { retries: 0 }, adapter },
|
|
1262
|
-
{ isBackendSuccess: () => true, transform: response => response.data }
|
|
1263
|
-
);
|
|
1264
|
-
return createTypedClient<paths>(request);
|
|
1265
|
-
}
|
|
1266
|
-
`;
|
|
1267
|
-
const DEFAULT_LAYOUT_TEMPLATE = `<template>
|
|
1268
|
-
<slot />
|
|
1269
|
-
</template>
|
|
1270
|
-
|
|
1271
|
-
<script setup lang="ts">
|
|
1272
|
-
<\/script>
|
|
1273
|
-
|
|
1274
|
-
<style>
|
|
1275
|
-
body {
|
|
1276
|
-
line-height: 1.5;
|
|
1277
|
-
}
|
|
1278
|
-
</style>
|
|
1279
|
-
`;
|
|
1280
|
-
const GITIGNORE_TEMPLATE = `node_modules
|
|
1281
|
-
dist
|
|
1282
|
-
.ubean
|
|
1283
|
-
.DS_Store
|
|
1284
|
-
*.log
|
|
1285
|
-
.env
|
|
1286
|
-
.env.local
|
|
1287
|
-
.env.*.local
|
|
1288
|
-
`;
|
|
1289
|
-
const FAVICON_SVG_TEMPLATE = `<svg width="100%" height="100%" version="1.1" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg"
|
|
1290
|
-
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
1291
|
-
<g>
|
|
1292
|
-
<path
|
|
1293
|
-
d="M 200,866 C 100,866 50,779.4 100,692.8 L 200,519.6 C 220,485 240,490 265,499.6 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
|
1294
|
-
fill="url(#LinearGradient)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1295
|
-
<path
|
|
1296
|
-
d="M 420,866 C 455,861 478,846 500,827 C 614,696 615,597 500,517 C 394,444 333,374 380,207.82 L 260,415.67 C 240.22,450 254.37,465.1 275.28,481.79 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
|
1297
|
-
fill="url(#LinearGradient_2)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1298
|
-
<path d="M 500,517 C 394,444 333,374 380,207.82 L 400,173.2 C 367,295 421,350 603,428 C 572,440 524,474 500,517"
|
|
1299
|
-
fill="url(#LinearGradient_3)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1300
|
-
<path d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 572,440 524,474 500,517 C 615,597 614,696 500,827"
|
|
1301
|
-
fill="url(#LinearGradient_4)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1302
|
-
<path d="M 400,173.2 C 367,295 421,350 603,428 C 690,389, 750,445 788,500 L 600,173.2 C 550,86.6 450,86.6 400,173.2"
|
|
1303
|
-
fill="url(#LinearGradient_5)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1304
|
-
<path
|
|
1305
|
-
d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 690,389, 750,445 788,500 C 816,554 797,606 750,640 L 500,827"
|
|
1306
|
-
fill="url(#LinearGradient_6)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1307
|
-
<path
|
|
1308
|
-
d="M 788,500 C 816,554 797,606 750,640 L 500,827 C 497,851 513,862 540,866 L 800,866 C 900,866 950,779.4 900,692.8 L 788,500"
|
|
1309
|
-
fill="url(#LinearGradient_7)" fill-rule="nonzero" opacity="1" stroke="none" />
|
|
1310
|
-
<g transform="translate(140, 650) scale(0.18)">
|
|
1311
|
-
<path d="M539.04,146.5c-77.37,32.74-126.47,114.53-123.22,198,.61,150.92,169.47,210.6,214.99,341.13,39.71,96.62-16.62,230.68-122.31,253.16-374.89-83.15-390.44-785.49,30.54-792.29ZM564.61,948.5c68.1-32.18,118.51-95.45,132.49-169.97,41.81-214.6-158.22-254.7-215.15-413.02-31.14-86.21,21.33-198.66,114.56-214.57,129.21,21.58,214.93,148.7,230.96,272.19,7.94,38.53,21.57,75.37,34.41,112.43,75.75,198.26-76.06,438.99-297.26,412.94Z" fill="#ffffff" fill-rule="evenodd"/>
|
|
1312
|
-
</g>
|
|
1313
|
-
</g>
|
|
1314
|
-
<defs>
|
|
1315
|
-
<linearGradient gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)"
|
|
1316
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient" x1="0" x2="1" y1="0" y2="0">
|
|
1317
|
-
<stop offset="0" stop-color="#373ebf" />
|
|
1318
|
-
<stop offset="1" stop-color="#5058e6" />
|
|
1319
|
-
</linearGradient>
|
|
1320
|
-
<linearGradient gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)"
|
|
1321
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient_2" x1="0" x2="1" y1="0" y2="0">
|
|
1322
|
-
<stop offset="0" stop-color="#c2d6ff" />
|
|
1323
|
-
<stop offset="1" stop-color="#646cff" />
|
|
1324
|
-
</linearGradient>
|
|
1325
|
-
<linearGradient gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)"
|
|
1326
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient_3" x1="0" x2="1" y1="0" y2="0">
|
|
1327
|
-
<stop offset="0" stop-color="#5058e6" />
|
|
1328
|
-
<stop offset="1" stop-color="#373ebf" />
|
|
1329
|
-
</linearGradient>
|
|
1330
|
-
<linearGradient gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)"
|
|
1331
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient_4" x1="0" x2="1" y1="0" y2="0">
|
|
1332
|
-
<stop offset="0" stop-color="#91a7ff" />
|
|
1333
|
-
<stop offset="1" stop-color="#5058e6" />
|
|
1334
|
-
</linearGradient>
|
|
1335
|
-
<linearGradient gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)"
|
|
1336
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient_5" x1="0" x2="1" y1="0" y2="0">
|
|
1337
|
-
<stop offset="0" stop-color="#646cff" />
|
|
1338
|
-
<stop offset="1" stop-color="#c2d6ff" />
|
|
1339
|
-
</linearGradient>
|
|
1340
|
-
<linearGradient gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)"
|
|
1341
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient_6" x1="0" x2="1" y1="0" y2="0">
|
|
1342
|
-
<stop offset="0" stop-color="#c2d6ff" />
|
|
1343
|
-
<stop offset="1" stop-color="#646cff" />
|
|
1344
|
-
</linearGradient>
|
|
1345
|
-
<linearGradient gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)"
|
|
1346
|
-
gradientUnits="userSpaceOnUse" id="LinearGradient_7" x1="0" x2="1" y1="0" y2="0">
|
|
1347
|
-
<stop offset="0" stop-color="#373ebf" />
|
|
1348
|
-
<stop offset="1" stop-color="#5058e6" />
|
|
1349
|
-
</linearGradient>
|
|
1350
|
-
</defs>
|
|
1351
|
-
</svg>
|
|
1352
|
-
`;
|
|
1353
|
-
const README_TEMPLATE = `# {{name}}
|
|
1354
|
-
|
|
1355
|
-
A Vue meta-framework project powered by ubean.
|
|
1356
|
-
|
|
1357
|
-
## Getting Started
|
|
1358
|
-
|
|
1359
|
-
\`\`\`bash
|
|
1360
|
-
# Install dependencies
|
|
1361
|
-
{{pm}} install
|
|
1362
|
-
|
|
1363
|
-
# Start dev server
|
|
1364
|
-
{{pm}} dev
|
|
1365
|
-
|
|
1366
|
-
# Build for production
|
|
1367
|
-
{{pm}} build
|
|
1368
|
-
|
|
1369
|
-
# Preview production build
|
|
1370
|
-
{{pm}} preview
|
|
1371
|
-
\`\`\`
|
|
1372
|
-
|
|
1373
|
-
## Project Structure
|
|
1374
|
-
|
|
1375
|
-
\`\`\`
|
|
1376
|
-
├── src/
|
|
1377
|
-
│ ├── pages/ # File-based routing
|
|
1378
|
-
│ ├── layouts/ # Layout components
|
|
1379
|
-
│ ├── routes/ # API routes
|
|
1380
|
-
│ ├── components/ # Vue components
|
|
1381
|
-
│ ├── composables/ # Auto-imported composables
|
|
1382
|
-
│ ├── plugins/ # App plugins
|
|
1383
|
-
│ ├── middleware/ # Request middleware
|
|
1384
|
-
│ ├── crons/ # Scheduled tasks
|
|
1385
|
-
│ ├── queues/ # Background jobs
|
|
1386
|
-
│ ├── request/ # Typed HTTP client & internal fetch
|
|
1387
|
-
│ └── app.vue # Root app component
|
|
1388
|
-
├── public/ # Static assets
|
|
1389
|
-
└── ubean.config.ts # ubean configuration
|
|
1390
|
-
\`\`\`
|
|
1391
|
-
`;
|
|
1392
|
-
const BLOG_INDEX_TEMPLATE = `<template>
|
|
1393
|
-
<div class="blog-page">
|
|
1394
|
-
<h1>Blog</h1>
|
|
1395
|
-
<div class="posts">
|
|
1396
|
-
<article v-for="post in posts" :key="post.slug" class="post-card">
|
|
1397
|
-
<h2><RouterLink :to="'/blog/' + post.slug">{{ post.title }}</RouterLink></h2>
|
|
1398
|
-
<p class="date">{{ post.date }}</p>
|
|
1399
|
-
<p class="excerpt">{{ post.excerpt }}</p>
|
|
1400
|
-
</article>
|
|
1401
|
-
</div>
|
|
1402
|
-
</div>
|
|
1403
|
-
</template>
|
|
1404
|
-
|
|
1405
|
-
<script setup lang="ts">
|
|
1406
|
-
import { RouterLink } from 'vue-router';
|
|
1407
|
-
import { useData } from 'ubean';
|
|
1408
|
-
|
|
1409
|
-
definePage({
|
|
1410
|
-
meta: {
|
|
1411
|
-
title: 'Blog'
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1414
|
-
|
|
1415
|
-
const { data: posts } = await useData('posts', () => {
|
|
1416
|
-
return [
|
|
1417
|
-
{ slug: 'hello-world', title: 'Hello World', date: '2024-01-15', excerpt: 'Welcome to my blog!' }
|
|
1418
|
-
];
|
|
1419
|
-
});
|
|
1420
|
-
<\/script>
|
|
1421
|
-
|
|
1422
|
-
<style scoped>
|
|
1423
|
-
.blog-page {
|
|
1424
|
-
max-width: 800px;
|
|
1425
|
-
margin: 0 auto;
|
|
1426
|
-
padding: 3rem 2rem;
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
h1 {
|
|
1430
|
-
margin-bottom: 2rem;
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
.posts {
|
|
1434
|
-
display: flex;
|
|
1435
|
-
flex-direction: column;
|
|
1436
|
-
gap: 2rem;
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
.post-card {
|
|
1440
|
-
padding: 1.5rem;
|
|
1441
|
-
border-radius: 8px;
|
|
1442
|
-
border: 1px solid #eee;
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
h2 {
|
|
1446
|
-
font-size: 1.5rem;
|
|
1447
|
-
margin-bottom: 0.5rem;
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
h2 a {
|
|
1451
|
-
color: #333;
|
|
1452
|
-
text-decoration: none;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
h2 a:hover {
|
|
1456
|
-
color: #667eea;
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
.date {
|
|
1460
|
-
color: #999;
|
|
1461
|
-
font-size: 0.9rem;
|
|
1462
|
-
margin-bottom: 0.5rem;
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
.excerpt {
|
|
1466
|
-
color: #666;
|
|
1467
|
-
}
|
|
1468
|
-
</style>
|
|
1469
|
-
`;
|
|
1470
|
-
const BLOG_POST_MD_TEMPLATE = `---
|
|
1471
|
-
title: Hello World
|
|
1472
|
-
date: 2024-01-15
|
|
1473
|
-
description: Welcome to my ubean blog!
|
|
1474
|
-
---
|
|
1475
|
-
|
|
1476
|
-
# Hello World
|
|
1477
|
-
|
|
1478
|
-
Welcome to my new blog built with **ubean**!
|
|
1479
|
-
|
|
1480
|
-
This is a markdown blog post.
|
|
1481
|
-
|
|
1482
|
-
## Features
|
|
1483
|
-
|
|
1484
|
-
- File-based routing
|
|
1485
|
-
- Markdown support
|
|
1486
|
-
- Auto-imports
|
|
1487
|
-
- API routes
|
|
1488
|
-
- And much more!
|
|
1489
|
-
`;
|
|
1490
941
|
async function scaffoldProject(options) {
|
|
1491
942
|
const targetDir = resolve$1(options.cwd, options.dir);
|
|
1492
943
|
const fs = createFsOps(targetDir);
|
|
@@ -1502,40 +953,24 @@ async function scaffoldProject(options) {
|
|
|
1502
953
|
}
|
|
1503
954
|
}
|
|
1504
955
|
}
|
|
1505
|
-
|
|
1506
|
-
await fs.ensureDir("src/pages");
|
|
1507
|
-
await fs.ensureDir("src/layouts");
|
|
1508
|
-
await fs.ensureDir("src/routes");
|
|
1509
|
-
await fs.ensureDir("src/components");
|
|
1510
|
-
await fs.ensureDir("src/composables");
|
|
1511
|
-
await fs.ensureDir("src/plugins");
|
|
1512
|
-
await fs.ensureDir("src/request");
|
|
1513
|
-
await fs.ensureDir("public");
|
|
1514
|
-
await fs.writeFile("package.json", renderTemplate(PACKAGE_JSON_TEMPLATE, { variables: { name: projectName } }));
|
|
1515
|
-
await fs.writeFile("public/favicon.svg", FAVICON_SVG_TEMPLATE);
|
|
1516
|
-
await fs.writeFile("tsconfig.json", TSCONFIG_TEMPLATE);
|
|
1517
|
-
await fs.writeFile("ubean.config.ts", renderTemplate(UBEAN_CONFIG_TEMPLATE, { variables: { preset: options.preset || "standard" } }));
|
|
1518
|
-
await fs.writeFile(".gitignore", GITIGNORE_TEMPLATE);
|
|
1519
|
-
await fs.writeFile("README.md", renderTemplate(README_TEMPLATE, { variables: {
|
|
956
|
+
const templateOptions = {
|
|
1520
957
|
name: projectName,
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
await fs.writeFile("src/pages/about.vue", ABOUT_PAGE_TEMPLATE);
|
|
1538
|
-
await fs.writeFile("src/routes/hello.get.ts", HELLO_API_TEMPLATE);
|
|
958
|
+
preset: options.preset || "standard",
|
|
959
|
+
packageManager: pm
|
|
960
|
+
};
|
|
961
|
+
switch (options.template) {
|
|
962
|
+
case "unify":
|
|
963
|
+
await scaffoldUnifyTemplate(fs, templateOptions);
|
|
964
|
+
break;
|
|
965
|
+
case "minimal":
|
|
966
|
+
await scaffoldMinimalTemplate(fs, templateOptions);
|
|
967
|
+
break;
|
|
968
|
+
case "blog":
|
|
969
|
+
await scaffoldBlogTemplate(fs, templateOptions);
|
|
970
|
+
break;
|
|
971
|
+
default:
|
|
972
|
+
await scaffoldStarterTemplate(fs, templateOptions);
|
|
973
|
+
break;
|
|
1539
974
|
}
|
|
1540
975
|
if (options.git) try {
|
|
1541
976
|
const { execSync } = await import("node:child_process");
|
|
@@ -1548,7 +983,7 @@ async function scaffoldProject(options) {
|
|
|
1548
983
|
console.log(`Project: ${projectName}`);
|
|
1549
984
|
console.log(`Location: ${targetDir}`);
|
|
1550
985
|
console.log(`Preset: ${options.preset || "standard"}`);
|
|
1551
|
-
console.log(`Template: ${options.template || "
|
|
986
|
+
console.log(`Template: ${options.template || "unify"}`);
|
|
1552
987
|
console.log("\nNext steps:");
|
|
1553
988
|
if (options.dir !== ".") console.log(` cd ${options.dir}`);
|
|
1554
989
|
console.log(` ${pm} install`);
|
|
@@ -1578,7 +1013,7 @@ const initCommand = {
|
|
|
1578
1013
|
},
|
|
1579
1014
|
template: {
|
|
1580
1015
|
type: "string",
|
|
1581
|
-
description: "Project template (minimal/starter/blog)"
|
|
1016
|
+
description: "Project template (unify/minimal/starter/blog)"
|
|
1582
1017
|
},
|
|
1583
1018
|
preset: {
|
|
1584
1019
|
type: "string",
|
|
@@ -1611,7 +1046,7 @@ const initCommand = {
|
|
|
1611
1046
|
logger$3.info("🚀 ubean project initializer");
|
|
1612
1047
|
if (!nonInteractive) {
|
|
1613
1048
|
name = name || await prompt("Project name", args.dir === "." ? basename(cwd) : args.dir);
|
|
1614
|
-
template = template || await select("Select a template:", TEMPLATES, "
|
|
1049
|
+
template = template || await select("Select a template:", TEMPLATES, "unify");
|
|
1615
1050
|
preset = preset || await select("Select a preset:", PRESETS, "standard");
|
|
1616
1051
|
packageManager = packageManager || await prompt("Package manager (npm/pnpm/yarn/bun)", "npm");
|
|
1617
1052
|
if (git === void 0) git = await confirm("Initialize git repository?", true);
|
|
@@ -1620,7 +1055,7 @@ const initCommand = {
|
|
|
1620
1055
|
cwd,
|
|
1621
1056
|
dir: args.dir,
|
|
1622
1057
|
force: args.force,
|
|
1623
|
-
template: template || "
|
|
1058
|
+
template: template || "unify",
|
|
1624
1059
|
preset: preset || "standard",
|
|
1625
1060
|
packageManager: packageManager || "npm",
|
|
1626
1061
|
git: git !== false,
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as toCamelCase, E as createFsOps, S as renderTemplate, T as toPascalCase, _ as renderCronTemplate, a as scaffold, b as renderPageTemplate, d as CRON_TEMPLATE, f as LAYOUT_TEMPLATE, g as renderApiTemplate, h as PLUGIN_TEMPLATE, i as recoverScaffold, m as PAGE_TEMPLATE, n as listScaffoldableFiles, p as MIDDLEWARE_TEMPLATE, t as deleteScaffold, u as API_TEMPLATE, v as renderLayoutTemplate, w as toKebabCase, x as renderPluginTemplate, y as renderMiddlewareTemplate } from "./page-VyP_7yLT.js";
|
|
2
2
|
export { API_TEMPLATE, CRON_TEMPLATE, LAYOUT_TEMPLATE, MIDDLEWARE_TEMPLATE, PAGE_TEMPLATE, PLUGIN_TEMPLATE, createFsOps, deleteScaffold, listScaffoldableFiles, recoverScaffold, renderApiTemplate, renderCronTemplate, renderLayoutTemplate, renderMiddlewareTemplate, renderPageTemplate, renderPluginTemplate, renderTemplate, scaffold, toCamelCase, toKebabCase, toPascalCase };
|