@ybais/create-ybais-app 0.2.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 +21 -0
- package/dist/index.js +371 -0
- package/package.json +34 -0
- package/template/.cursor/rules/ybais-app.mdc +21 -0
- package/template/.cursor/skills/ybais-app/SKILL.md +140 -0
- package/template/.cursor/skills/ybais-app/reference.md +180 -0
- package/template/.env +2 -0
- package/template/.env.prod +8 -0
- package/template/.env.test +8 -0
- package/template/.mise/tasks/build +107 -0
- package/template/.oxlintrc.json +22 -0
- package/template/AGENTS.md +25 -0
- package/template/README.md +251 -0
- package/template/dist/assets/css/index-bQrzgOlr.css +1 -0
- package/template/dist/assets/js/dist-CX33qWwE.js +2 -0
- package/template/dist/assets/js/dist-legacy-BnxRxjXx.js +1 -0
- package/template/dist/assets/js/index-BNqkt-js.js +2 -0
- package/template/dist/assets/js/index-legacy-DPO2FCfH.js +1 -0
- package/template/dist/assets/js/polyfills-Dsaw-v00.js +1 -0
- package/template/dist/assets/js/polyfills-legacy-DyZJWH2U.js +1 -0
- package/template/dist/assets/js/rolldown-runtime-LhxUO5vB.js +1 -0
- package/template/dist/assets/js/rolldown-runtime-legacy-BptCTa2h.js +1 -0
- package/template/dist/assets/js/routes-D2ibRZk6.js +1 -0
- package/template/dist/assets/js/routes-legacy-DGEWjKnS.js +1 -0
- package/template/dist/assets/js/vconsole.min-BcOaunN2.js +1 -0
- package/template/dist/assets/js/vconsole.min-legacy-Bub-moxG.js +1 -0
- package/template/dist/favicon.svg +1 -0
- package/template/dist/index.html +29 -0
- package/template/dist/version.json +4 -0
- package/template/index.html +19 -0
- package/template/mise.toml +11 -0
- package/template/package.json +60 -0
- package/template/plugins/app-version.ts +88 -0
- package/template/pnpm-lock.yaml +3359 -0
- package/template/pnpm-workspace.yaml +7 -0
- package/template/postcss.config.js +24 -0
- package/template/public/favicon.svg +1 -0
- package/template/scripts/run-build.mjs +5 -0
- package/template/scripts/setup-mise.mjs +47 -0
- package/template/scripts/with-mise.mjs +107 -0
- package/template/src/api/alova.d.ts +7 -0
- package/template/src/api/alova.ts +50 -0
- package/template/src/api/index.ts +8 -0
- package/template/src/api/qiniu.ts +8 -0
- package/template/src/api/uploader.ts +25 -0
- package/template/src/components/NotFoundComponent/index.tsx +48 -0
- package/template/src/components/RouterErrorComponent/index.tsx +27 -0
- package/template/src/components/index.ts +2 -0
- package/template/src/lib/README.md +17 -0
- package/template/src/main.tsx +64 -0
- package/template/src/routeTree.gen.ts +59 -0
- package/template/src/router.ts +10 -0
- package/template/src/routes/__root.tsx +10 -0
- package/template/src/routes/index.tsx +39 -0
- package/template/src/styles/index.css +42 -0
- package/template/src/styles/variant.css +18 -0
- package/template/src/styles/webview-compat.css +49 -0
- package/template/src/utils/cn.ts +63 -0
- package/template/src/vite-env.d.ts +41 -0
- package/template/tailwind.config.js +14 -0
- package/template/tsconfig.app.json +37 -0
- package/template/tsconfig.json +7 -0
- package/template/tsconfig.node.json +28 -0
- package/template/vite.config.ts +131 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
兼容性处理:
|
|
3
|
+
iOS 12 使用 constant(safe-area-inset-*)
|
|
4
|
+
iOS 13+ 使用 env(safe-area-inset-*)
|
|
5
|
+
*/
|
|
6
|
+
:root {
|
|
7
|
+
--sat: constant(safe-area-inset-top);
|
|
8
|
+
--sat: env(safe-area-inset-top);
|
|
9
|
+
|
|
10
|
+
--sab: constant(safe-area-inset-bottom);
|
|
11
|
+
--sab: env(safe-area-inset-bottom);
|
|
12
|
+
|
|
13
|
+
--sal: constant(safe-area-inset-left);
|
|
14
|
+
--sal: env(safe-area-inset-left);
|
|
15
|
+
|
|
16
|
+
--sar: constant(safe-area-inset-right);
|
|
17
|
+
--sar: env(safe-area-inset-right);
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebView 兼容补丁(iOS ≥12 / Android ≥7 / Chrome ≥55 / Safari ≥12)
|
|
3
|
+
* - 补回可能被 cssTarget chrome55 剥掉的 -webkit-user-select
|
|
4
|
+
* - 降级 sonner 运行时注入样式(注入晚于本文件,关键声明用 !important)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* 强制保留 WebKit 前缀:css minify 按 chrome55 会去掉 -webkit-user-select */
|
|
8
|
+
html,
|
|
9
|
+
body {
|
|
10
|
+
-webkit-user-select: none !important;
|
|
11
|
+
user-select: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
input,
|
|
15
|
+
textarea {
|
|
16
|
+
-webkit-user-select: auto !important;
|
|
17
|
+
user-select: auto;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* sonner toast:无 flex gap 时用子项 margin 保间距 */
|
|
21
|
+
[data-sonner-toast][data-styled="true"] {
|
|
22
|
+
gap: 0 !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
[data-sonner-toast][data-styled="true"] > [data-icon] {
|
|
26
|
+
margin-right: 6px !important;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
[data-sonner-toast][data-styled="true"] [data-content] {
|
|
30
|
+
gap: 0 !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
[data-sonner-toast][data-styled="true"] [data-content] > [data-description] {
|
|
34
|
+
margin-top: 2px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-sonner-toast] {
|
|
38
|
+
/* anywhere 需 Safari 15.4+;降级为 break-word */
|
|
39
|
+
overflow-wrap: break-word !important;
|
|
40
|
+
word-wrap: break-word !important;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* sonner loading:inset → 四向(Chrome 87+ / Safari 14.1+ 才有 inset) */
|
|
44
|
+
.sonner-loading-wrapper {
|
|
45
|
+
top: 0 !important;
|
|
46
|
+
right: 0 !important;
|
|
47
|
+
bottom: 0 !important;
|
|
48
|
+
left: 0 !important;
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 条件拼接 className(轻量 clsx 风格,无第三方依赖)。
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* cn("btn", active && "btn--active", { "is-disabled": disabled })
|
|
6
|
+
* // => "btn btn--active" 或 "btn is-disabled"
|
|
7
|
+
*
|
|
8
|
+
* 按需引入:`import { cn } from "@/utils/cn"`(勿做 utils 聚合 barrel,利于 tree-shake)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export type ClassValue =
|
|
12
|
+
| string
|
|
13
|
+
| number
|
|
14
|
+
| boolean
|
|
15
|
+
| null
|
|
16
|
+
| undefined
|
|
17
|
+
| ClassDictionary
|
|
18
|
+
| ClassArray;
|
|
19
|
+
|
|
20
|
+
export type ClassDictionary = Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
export type ClassArray = ClassValue[];
|
|
23
|
+
|
|
24
|
+
function append(buf: string[], value: ClassValue): void {
|
|
25
|
+
if (value == null || value === false || value === true) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
30
|
+
const s = String(value).trim();
|
|
31
|
+
if (s) {
|
|
32
|
+
buf.push(s);
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
for (let i = 0; i < value.length; i++) {
|
|
39
|
+
append(buf, value[i]);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (typeof value === "object") {
|
|
45
|
+
for (const key in value) {
|
|
46
|
+
if (Object.prototype.hasOwnProperty.call(value, key) && value[key]) {
|
|
47
|
+
const s = key.trim();
|
|
48
|
+
if (s) {
|
|
49
|
+
buf.push(s);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 将多种条件输入合并为单个 className 字符串 */
|
|
57
|
+
export function cn(...inputs: ClassValue[]): string {
|
|
58
|
+
const buf: string[] = [];
|
|
59
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
60
|
+
append(buf, inputs[i]);
|
|
61
|
+
}
|
|
62
|
+
return buf.join(" ");
|
|
63
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
interface ImportMetaEnv {
|
|
4
|
+
readonly VITE_APP_ENV: "test" | "prod";
|
|
5
|
+
readonly VITE_API_BASE_URL: string;
|
|
6
|
+
readonly VITE_APP_TITLE?: string;
|
|
7
|
+
readonly VITE_QINIU_AES_KEY: string;
|
|
8
|
+
readonly VITE_QINIU_AES_IV: string;
|
|
9
|
+
/** 构建/开发时注入的当前 git 分支;master 下杜绝 vConsole */
|
|
10
|
+
readonly VITE_GIT_BRANCH?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ImportMeta {
|
|
14
|
+
readonly env: ImportMetaEnv;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare module "vconsole" {
|
|
18
|
+
export default class VConsole {
|
|
19
|
+
constructor(options?: Record<string, unknown>);
|
|
20
|
+
destroy(): void;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Window {
|
|
25
|
+
// iOS WebKit 注入对象
|
|
26
|
+
webkit?: {
|
|
27
|
+
messageHandlers?: Record<
|
|
28
|
+
string,
|
|
29
|
+
{ postMessage: (data: unknown) => void }
|
|
30
|
+
>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Android WebInterface 注入对象
|
|
34
|
+
AndroidBridge?: Record<string, (data?: string) => void>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Native → H5 命名回调(如 AuthCallback)及 callNative 临时回调。
|
|
38
|
+
* 业务侧请用 onNative / useNativeCallback,勿直接覆盖。
|
|
39
|
+
*/
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
|
4
|
+
theme: {
|
|
5
|
+
extend: {
|
|
6
|
+
// 可在此处扩充针对 Safe Area 的自定义工具类
|
|
7
|
+
spacing: {
|
|
8
|
+
"safe-top": "var(--sat)",
|
|
9
|
+
"safe-bottom": "var(--sab)",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
plugins: [],
|
|
14
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2023",
|
|
7
|
+
"DOM"
|
|
8
|
+
],
|
|
9
|
+
"module": "esnext",
|
|
10
|
+
"types": [
|
|
11
|
+
"vite/client"
|
|
12
|
+
],
|
|
13
|
+
"allowArbitraryExtensions": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
/* Bundler mode */
|
|
16
|
+
"moduleResolution": "bundler",
|
|
17
|
+
"allowImportingTsExtensions": true,
|
|
18
|
+
"verbatimModuleSyntax": true,
|
|
19
|
+
"moduleDetection": "force",
|
|
20
|
+
"noEmit": true,
|
|
21
|
+
"jsx": "react-jsx",
|
|
22
|
+
/* Path alias — TS6: no baseUrl, prefix is inlined into paths */
|
|
23
|
+
"paths": {
|
|
24
|
+
"@/*": [
|
|
25
|
+
"./src/*"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
/* Linting */
|
|
29
|
+
"noUnusedLocals": true,
|
|
30
|
+
"noUnusedParameters": true,
|
|
31
|
+
"erasableSyntaxOnly": true,
|
|
32
|
+
"noFallthroughCasesInSwitch": true
|
|
33
|
+
},
|
|
34
|
+
"include": [
|
|
35
|
+
"src"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2023"
|
|
7
|
+
],
|
|
8
|
+
"types": [
|
|
9
|
+
"node"
|
|
10
|
+
],
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
/* Bundler mode */
|
|
13
|
+
"module": "nodenext",
|
|
14
|
+
"allowImportingTsExtensions": true,
|
|
15
|
+
"verbatimModuleSyntax": true,
|
|
16
|
+
"moduleDetection": "force",
|
|
17
|
+
"noEmit": true,
|
|
18
|
+
/* Linting */
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"erasableSyntaxOnly": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true
|
|
23
|
+
},
|
|
24
|
+
"include": [
|
|
25
|
+
"vite.config.ts",
|
|
26
|
+
"plugins/**/*.ts"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { defineConfig, loadEnv } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import legacy from "@vitejs/plugin-legacy";
|
|
4
|
+
import { tanstackRouter } from "@tanstack/router-plugin/vite";
|
|
5
|
+
import { execSync } from "node:child_process";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { appVersionPlugin } from "./plugins/app-version.ts";
|
|
8
|
+
|
|
9
|
+
function resolveGitBranch(): string {
|
|
10
|
+
try {
|
|
11
|
+
return execSync("git rev-parse --abbrev-ref HEAD", {
|
|
12
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
13
|
+
})
|
|
14
|
+
.toString()
|
|
15
|
+
.trim();
|
|
16
|
+
} catch {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// https://vite.dev/config/
|
|
22
|
+
export default defineConfig(({ mode }) => {
|
|
23
|
+
const env = loadEnv(mode, process.cwd(), "");
|
|
24
|
+
const proxyTarget =
|
|
25
|
+
env.VITE_API_BASE_URL || "https://api-test.example.com";
|
|
26
|
+
const gitBranch = resolveGitBranch();
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
base: "./",
|
|
30
|
+
|
|
31
|
+
define: {
|
|
32
|
+
"import.meta.env.VITE_GIT_BRANCH": JSON.stringify(gitBranch),
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
resolve: {
|
|
36
|
+
alias: {
|
|
37
|
+
"@": path.resolve(__dirname, "./src"),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
server: {
|
|
42
|
+
// 仅开发:把 /proxyApi 转到真实 API,解决浏览器跨域;构建产物不含此前缀
|
|
43
|
+
proxy: {
|
|
44
|
+
"/proxyApi": {
|
|
45
|
+
target: proxyTarget,
|
|
46
|
+
changeOrigin: true,
|
|
47
|
+
rewrite: (p) => p.replace(/^\/proxyApi/, ""),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
plugins: [
|
|
53
|
+
appVersionPlugin(),
|
|
54
|
+
tanstackRouter({
|
|
55
|
+
target: "react",
|
|
56
|
+
autoCodeSplitting: true,
|
|
57
|
+
}),
|
|
58
|
+
react(),
|
|
59
|
+
legacy({
|
|
60
|
+
targets: ["ios >= 12", "android >= 7", "chrome >= 55", "safari >= 12"],
|
|
61
|
+
// DOM / Web API 不在 core-js usage 检测内,须手动追加(见 additional*)
|
|
62
|
+
additionalLegacyPolyfills: [
|
|
63
|
+
"regenerator-runtime/runtime",
|
|
64
|
+
// alova/fetch + TanStack Router 均 new AbortController();Chrome <66 无此 API
|
|
65
|
+
"abortcontroller-polyfill/dist/polyfill-patch-fetch",
|
|
66
|
+
// 显式固化,避免仅靠 usage 漏检
|
|
67
|
+
"core-js/modules/web.queue-microtask.js",
|
|
68
|
+
"core-js/modules/es.promise.all-settled.js",
|
|
69
|
+
// TanStack 路径解码;Chrome <85 / Safari <13.1 / 全部 iOS 12
|
|
70
|
+
"core-js/modules/es.string.replace-all.js",
|
|
71
|
+
],
|
|
72
|
+
// modern 默认按 chrome>=105 等收集 polyfill,会漏掉 App 内嵌 WebView(ESM 但内核偏旧)
|
|
73
|
+
additionalModernPolyfills: [
|
|
74
|
+
"abortcontroller-polyfill/dist/polyfill-patch-fetch",
|
|
75
|
+
// error-guard / TanStack:Chrome <71、部分 iOS 12.0
|
|
76
|
+
"core-js/modules/web.queue-microtask.js",
|
|
77
|
+
// TanStack load-matches:Chrome <76、Safari <13(含全部 iOS 12)
|
|
78
|
+
"core-js/modules/es.promise.all-settled.js",
|
|
79
|
+
// TanStack 路径解码
|
|
80
|
+
"core-js/modules/es.string.replace-all.js",
|
|
81
|
+
],
|
|
82
|
+
// 自动按照 Target 引入 core-js 中的按需 Polyfill
|
|
83
|
+
modernPolyfills: true,
|
|
84
|
+
renderLegacyChunks: true,
|
|
85
|
+
}),
|
|
86
|
+
],
|
|
87
|
+
|
|
88
|
+
build: {
|
|
89
|
+
// 限制 CSS 压缩目标,防止生成 iOS 12 Safari 不支持的新 CSS 语法
|
|
90
|
+
// JS target 由 @vitejs/plugin-legacy 的 targets 接管,勿再设 build.target
|
|
91
|
+
cssTarget: "chrome55",
|
|
92
|
+
outDir: "dist",
|
|
93
|
+
assetsDir: "assets",
|
|
94
|
+
cssCodeSplit: true,
|
|
95
|
+
// 显式指定 Terser 进行 JS 压缩,避免 esbuild 在旧版 Safari ES5 转换上的语法 bug
|
|
96
|
+
minify: "terser",
|
|
97
|
+
terserOptions: {
|
|
98
|
+
compress: {
|
|
99
|
+
drop_console: false, // 生产环境可设为 true 清除 console
|
|
100
|
+
drop_debugger: true,
|
|
101
|
+
},
|
|
102
|
+
// Vite 8 会注入 format,不可再用已弃用的 output,否则会与 format 冲突
|
|
103
|
+
format: {
|
|
104
|
+
// 强制输出 ASCII 字符,防止旧内核 WebView 因 Unicode 解析异常导致白屏
|
|
105
|
+
ascii_only: true,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
// Vite 8 底层为 Rolldown,仍兼容 rollupOptions(官方兼容层会映射)
|
|
109
|
+
// @see https://cn.vite.dev/blog/announcing-vite8#a-unified-toolchain
|
|
110
|
+
rollupOptions: {
|
|
111
|
+
output: {
|
|
112
|
+
entryFileNames: "assets/js/[name]-[hash].js",
|
|
113
|
+
chunkFileNames: "assets/js/[name]-[hash].js",
|
|
114
|
+
assetFileNames: (assetInfo) => {
|
|
115
|
+
const name = assetInfo.names?.[0] ?? assetInfo.name ?? "";
|
|
116
|
+
if (/\.css$/i.test(name)) {
|
|
117
|
+
return "assets/css/[name]-[hash][extname]";
|
|
118
|
+
}
|
|
119
|
+
if (/\.(png|jpe?g|gif|svg|webp|avif|ico)$/i.test(name)) {
|
|
120
|
+
return "assets/img/[name]-[hash][extname]";
|
|
121
|
+
}
|
|
122
|
+
if (/\.(woff2?|ttf|eot|otf)$/i.test(name)) {
|
|
123
|
+
return "assets/fonts/[name]-[hash][extname]";
|
|
124
|
+
}
|
|
125
|
+
return "assets/[name]-[hash][extname]";
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
});
|