create-soybean 1.7.0 → 1.7.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.
Files changed (148) hide show
  1. package/README.en_US.md +7 -5
  2. package/README.md +7 -5
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +27 -15
  5. package/package.json +12 -24
  6. package/template-ts-lib/_vite-hooks/pre-commit +1 -0
  7. package/template-ts-lib/package.json +40 -0
  8. package/template-ts-lib/pnpm-workspace.yaml +11 -0
  9. package/{template-tsdown → template-ts-lib}/tsconfig.json +7 -6
  10. package/template-ts-lib/vite.config.ts +22 -0
  11. package/template-ubean/README.md +20 -0
  12. package/template-ubean/_editorconfig +11 -0
  13. package/template-ubean/_gitattributes +2 -0
  14. package/template-ubean/_gitignore +32 -0
  15. package/template-ubean/_vite-hooks/pre-commit +1 -0
  16. package/template-ubean/eslint.config.mjs +3 -0
  17. package/template-ubean/package.json +38 -0
  18. package/template-ubean/pnpm-workspace.yaml +11 -0
  19. package/template-ubean/public/data.json +5 -0
  20. package/template-ubean/public/favicon.svg +64 -0
  21. package/template-ubean/src/app.ts +39 -0
  22. package/template-ubean/src/components/islands/IslandClock.vue +57 -0
  23. package/template-ubean/src/components/islands/IslandCounter.vue +66 -0
  24. package/template-ubean/src/components/islands/IslandMedia.vue +69 -0
  25. package/template-ubean/src/components/islands/IslandOnly.vue +54 -0
  26. package/template-ubean/src/components/islands/IslandVisibility.vue +60 -0
  27. package/template-ubean/src/layouts/admin.vue +13 -0
  28. package/template-ubean/src/layouts/default.vue +97 -0
  29. package/template-ubean/src/locales/en.json +31 -0
  30. package/template-ubean/src/locales/zh.json +31 -0
  31. package/template-ubean/src/middleware/01.global.ts +9 -0
  32. package/template-ubean/src/pages/about.vue +135 -0
  33. package/template-ubean/src/pages/blog/[...slug].vue +30 -0
  34. package/template-ubean/src/pages/dashboard/index.vue +19 -0
  35. package/template-ubean/src/pages/data-fetch.vue +95 -0
  36. package/template-ubean/src/pages/index.vue +117 -0
  37. package/template-ubean/src/pages/islands-test.vue +155 -0
  38. package/template-ubean/src/routes/api/hello.ts +60 -0
  39. package/template-ubean/src/routes/api/users/[id].ts +94 -0
  40. package/template-ubean/src/routes/api/users/index.ts +79 -0
  41. package/template-ubean/src/server.ts +9 -0
  42. package/template-ubean/src/typings/env.d.ts +37 -0
  43. package/template-ubean/tsconfig.json +26 -0
  44. package/template-ubean/ubean.config.ts +24 -0
  45. package/template-ubean/vite.config.ts +9 -0
  46. package/template-ubean-client/README.md +18 -0
  47. package/template-ubean-client/_gitignore +32 -0
  48. package/template-ubean-client/_vite-hooks/pre-commit +1 -0
  49. package/template-ubean-client/eslint.config.mjs +3 -0
  50. package/template-ubean-client/index.html +14 -0
  51. package/template-ubean-client/package.json +37 -0
  52. package/template-ubean-client/pnpm-workspace.yaml +11 -0
  53. package/template-ubean-client/public/favicon.svg +64 -0
  54. package/template-ubean-client/src/App.vue +135 -0
  55. package/template-ubean-client/src/main.ts +63 -0
  56. package/template-ubean-client/src/pages/404.vue +36 -0
  57. package/template-ubean-client/src/pages/about.vue +151 -0
  58. package/template-ubean-client/src/pages/about2.reuse.ts +8 -0
  59. package/template-ubean-client/src/pages/blog/[...slug].vue +72 -0
  60. package/template-ubean-client/src/pages/guide.md +30 -0
  61. package/template-ubean-client/src/pages/index.vue +101 -0
  62. package/template-ubean-client/src/pages/users/[id=numeric].vue +80 -0
  63. package/template-ubean-client/src/pages/users/index.vue +56 -0
  64. package/template-ubean-client/src/typings/globals.d.ts +17 -0
  65. package/template-ubean-client/tsconfig.json +25 -0
  66. package/template-ubean-client/vite.config.ts +20 -0
  67. package/template-vue/.gitignore +2 -0
  68. package/template-vue/_vite-hooks/pre-commit +1 -0
  69. package/template-vue/eslint.config.mjs +3 -0
  70. package/template-vue/package.json +17 -26
  71. package/template-vue/pnpm-workspace.yaml +11 -0
  72. package/template-vue/src/App.vue +3 -3
  73. package/template-vue/src/main.ts +2 -7
  74. package/template-vue/uno.config.ts +3 -3
  75. package/template-vue/vite.config.ts +10 -6
  76. package/template-vue-lib/_editorconfig +11 -0
  77. package/template-vue-lib/_gitattributes +2 -0
  78. package/template-vue-lib/_vite-hooks/pre-commit +1 -0
  79. package/template-vue-lib/eslint.config.mjs +3 -0
  80. package/template-vue-lib/package.json +53 -0
  81. package/template-vue-lib/pnpm-workspace.yaml +11 -0
  82. package/template-vue-lib/vite.config.ts +33 -0
  83. package/template-tsdown/_npmrc +0 -1
  84. package/template-tsdown/_oxfmtrc.json +0 -7
  85. package/template-tsdown/_oxlintrc.json +0 -16
  86. package/template-tsdown/package.json +0 -54
  87. package/template-tsdown/tsdown.config.ts +0 -10
  88. package/template-vue/_npmrc +0 -1
  89. package/template-vue/_oxfmtrc.json +0 -7
  90. package/template-vue/_oxlintrc.json +0 -17
  91. package/template-vue/er.config.ts +0 -9
  92. package/template-vue/src/components/HelloWorld.vue +0 -5
  93. package/template-vue/src/constants/index.ts +0 -0
  94. package/template-vue/src/layouts/base/index.vue +0 -9
  95. package/template-vue/src/layouts/blank/index.vue +0 -9
  96. package/template-vue/src/plugins/assets.ts +0 -4
  97. package/template-vue/src/router/index.ts +0 -25
  98. package/template-vue/src/shared/index.ts +0 -0
  99. package/template-vue/src/store/_plugin.ts +0 -17
  100. package/template-vue/src/store/counter/index.ts +0 -14
  101. package/template-vue/src/store/index.ts +0 -12
  102. package/template-vue/src/styles/app.css +0 -49
  103. package/template-vue/src/typings/components.d.ts +0 -17
  104. package/template-vue/src/views/(builtin)/403.vue +0 -5
  105. package/template-vue/src/views/(builtin)/404.vue +0 -5
  106. package/template-vue/src/views/(builtin)/login/index.vue +0 -5
  107. package/template-vue/src/views/(builtin)/wip.vue +0 -5
  108. package/template-vue/src/views/demo.tsx +0 -7
  109. package/template-vue/src/views/home/child.vue +0 -5
  110. package/template-vue/src/views/home/child2.vue +0 -5
  111. package/template-vue/src/views/home/index.vue +0 -9
  112. package/template-vue/src/views/list/[id].vue +0 -9
  113. package/template-vue/src/views/list/add.vue +0 -5
  114. package/template-vue/src/views/list/components/demo.vue +0 -0
  115. package/template-vue/src/views/list/components/search-list.vue +0 -5
  116. package/template-vue/src/views/list/detail2-[[id]]-[[userId]].vue +0 -5
  117. package/template-vue/src/views/list/detail_[id]_[userId].vue +0 -5
  118. package/template-vue/src/views/list/edit_[id].vue +0 -5
  119. package/template-vue/src/views/list/index.vue +0 -5
  120. package/template-vue/src/views/list/modules/list-table.vue +0 -5
  121. package/template-vue-tsdown/_npmrc +0 -1
  122. package/template-vue-tsdown/_oxfmtrc.json +0 -7
  123. package/template-vue-tsdown/_oxlintrc.json +0 -17
  124. package/template-vue-tsdown/package.json +0 -64
  125. package/template-vue-tsdown/tsdown.config.ts +0 -16
  126. package/template-vue-tsdown/vite.config.ts +0 -7
  127. /package/{template-tsdown → template-ts-lib}/.github/workflows/release.yml +0 -0
  128. /package/{template-tsdown → template-ts-lib}/.vscode/extensions.json +0 -0
  129. /package/{template-tsdown → template-ts-lib}/.vscode/launch.json +0 -0
  130. /package/{template-tsdown → template-ts-lib}/.vscode/settings.json +0 -0
  131. /package/{template-tsdown → template-ts-lib}/_editorconfig +0 -0
  132. /package/{template-tsdown → template-ts-lib}/_gitattributes +0 -0
  133. /package/{template-tsdown → template-ts-lib}/_gitignore +0 -0
  134. /package/{template-tsdown → template-ts-lib}/src/index.ts +0 -0
  135. /package/{template-vue-tsdown → template-ubean-client}/_editorconfig +0 -0
  136. /package/{template-vue-tsdown → template-ubean-client}/_gitattributes +0 -0
  137. /package/{template-vue-tsdown → template-vue-lib}/.github/workflows/release.yml +0 -0
  138. /package/{template-vue-tsdown → template-vue-lib}/.vscode/extensions.json +0 -0
  139. /package/{template-vue-tsdown → template-vue-lib}/.vscode/launch.json +0 -0
  140. /package/{template-vue-tsdown → template-vue-lib}/.vscode/settings.json +0 -0
  141. /package/{template-vue-tsdown → template-vue-lib}/_gitignore +0 -0
  142. /package/{template-vue-tsdown → template-vue-lib}/playground/index.html +0 -0
  143. /package/{template-vue-tsdown → template-vue-lib}/playground/src/App.vue +0 -0
  144. /package/{template-vue-tsdown → template-vue-lib}/playground/src/index.ts +0 -0
  145. /package/{template-vue-tsdown → template-vue-lib}/playground/src/style.css +0 -0
  146. /package/{template-vue-tsdown → template-vue-lib}/src/demo-pkg.vue +0 -0
  147. /package/{template-vue-tsdown → template-vue-lib}/src/index.ts +0 -0
  148. /package/{template-vue-tsdown → template-vue-lib}/tsconfig.json +0 -0
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vite-plus';
2
+ import { ubeanPlugin } from 'ubean/vite';
3
+
4
+ export default defineConfig({
5
+ resolve: {
6
+ tsconfigPaths: true
7
+ },
8
+ plugins: [ubeanPlugin()]
9
+ });
@@ -0,0 +1,18 @@
1
+ # template-ubean-client
2
+
3
+ 基于 [@ubean/vue](https://github.com/soybeanjs/ubean) 的独立 SPA(纯客户端)模板:精简内核 + 文件式路由,无 SSR、无自动引入,全部显式导入。
4
+
5
+ ## 使用
6
+
7
+ ```bash
8
+ pnpm install
9
+ pnpm dev
10
+ ```
11
+
12
+ ## 演示内容
13
+
14
+ - 文件式路由: `src/pages/`(动态参数 `[id=numeric]`、catch-all `[...slug]`、reuse `.reuse.ts`、特殊页 `404.vue`)
15
+ - 页面级 head: `definePage({ head })` 提取到 route.meta(@unhead/vue 懒加载)
16
+ - matcher 校验: `/users/abc` 会被守卫重定向到 404
17
+ - Markdown 页面: `guide.md`、`blog/[...slug].vue`(@ubean/markdown 按需加载)
18
+ - 路由实例: `src/main.ts` 用 vue-router 原生 `createRouter` 创建
@@ -0,0 +1,32 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ .DS_Store
12
+ dist
13
+ dist-ssr
14
+ coverage
15
+ *.local
16
+
17
+ # ubean
18
+ .ubean
19
+
20
+ # Editor directories and files
21
+ .vscode/*
22
+ !.vscode/extensions.json
23
+ !.vscode/settings.json
24
+ !.vscode/launch.json
25
+ .idea
26
+ *.suo
27
+ *.ntvs*
28
+ *.njsproj
29
+ *.sln
30
+ *.sw?
31
+
32
+ .VSCodeCounter
@@ -0,0 +1 @@
1
+ vp staged
@@ -0,0 +1,3 @@
1
+ import { defineConfig } from '@soybeanjs/eslint-config-vue';
2
+
3
+ export default defineConfig();
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" href="https://r2.soybeanjs.tech/soybeanjs/logo-ubean.svg?v=202608211738" type="image/svg+xml" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>ubean-client · standalone SPA</title>
8
+ </head>
9
+
10
+ <body>
11
+ <div id="app"></div>
12
+ <script type="module" src="/src/main.ts"></script>
13
+ </body>
14
+ </html>
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "template-ubean-client",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "vp build",
8
+ "cleanup": "soy cleanup",
9
+ "commit": "soy git-commit",
10
+ "dev": "vp dev",
11
+ "fmt": "vp fmt",
12
+ "lint": "vp lint --fix && pnpm lint:vue",
13
+ "lint:vue": "eslint . --ext .vue --fix",
14
+ "preview": "vp preview",
15
+ "typecheck": "vue-tsc --noEmit --skipLibCheck",
16
+ "upkg": "soy ncu"
17
+ },
18
+ "dependencies": {
19
+ "@ubean/vue": "^0.5.1",
20
+ "vue": "^3.5.42",
21
+ "vue-router": "^5.3.1"
22
+ },
23
+ "devDependencies": {
24
+ "@soybeanjs/cli": "^1.8.3",
25
+ "@soybeanjs/eslint-config-vue": "^0.1.1",
26
+ "@soybeanjs/oxc-config": "^0.2.6",
27
+ "@types/node": "^26.5.1",
28
+ "@ubean/markdown": "^0.5.1",
29
+ "@unhead/vue": "^3.4.0",
30
+ "@vitejs/plugin-vue": "^6.0.8",
31
+ "typescript": "catalog:",
32
+ "vite": "catalog:",
33
+ "vite-plus": "catalog:",
34
+ "vue-tsc": "^3.3.11"
35
+ },
36
+ "packageManager": "pnpm@12.4.1"
37
+ }
@@ -0,0 +1,11 @@
1
+ catalog:
2
+ vite: npm:@voidzero-dev/vite-plus-core@latest
3
+ vite-plus: latest
4
+ typescript: npm:typescript-native-bridge@latest
5
+ overrides:
6
+ vite: 'catalog:'
7
+ typescript: 'catalog:'
8
+ shamefullyHoist: true
9
+ allowBuilds:
10
+ esbuild: false
11
+ minimumReleaseAge: 0
@@ -0,0 +1,64 @@
1
+ <svg width="100%" height="100%" version="1.1" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg"
2
+ xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <g>
4
+ <path
5
+ 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"
6
+ fill="url(#LinearGradient)" fill-rule="nonzero" opacity="1" stroke="none" />
7
+ <path
8
+ 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"
9
+ fill="url(#LinearGradient_2)" fill-rule="nonzero" opacity="1" stroke="none" />
10
+ <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"
11
+ fill="url(#LinearGradient_3)" fill-rule="nonzero" opacity="1" stroke="none" />
12
+ <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"
13
+ fill="url(#LinearGradient_4)" fill-rule="nonzero" opacity="1" stroke="none" />
14
+ <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"
15
+ fill="url(#LinearGradient_5)" fill-rule="nonzero" opacity="1" stroke="none" />
16
+ <path
17
+ 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"
18
+ fill="url(#LinearGradient_6)" fill-rule="nonzero" opacity="1" stroke="none" />
19
+ <path
20
+ 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"
21
+ fill="url(#LinearGradient_7)" fill-rule="nonzero" opacity="1" stroke="none" />
22
+ <!-- bean -->
23
+ <g transform="translate(140, 650) scale(0.18)">
24
+ <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"/>
25
+ </g>
26
+ </g>
27
+ <defs>
28
+ <linearGradient gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)"
29
+ gradientUnits="userSpaceOnUse" id="LinearGradient" x1="0" x2="1" y1="0" y2="0">
30
+ <stop offset="0" stop-color="#373ebf" />
31
+ <stop offset="1" stop-color="#5058e6" />
32
+ </linearGradient>
33
+ <linearGradient gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)"
34
+ gradientUnits="userSpaceOnUse" id="LinearGradient_2" x1="0" x2="1" y1="0" y2="0">
35
+ <stop offset="0" stop-color="#c2d6ff" />
36
+ <stop offset="1" stop-color="#646cff" />
37
+ </linearGradient>
38
+ <linearGradient gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)"
39
+ gradientUnits="userSpaceOnUse" id="LinearGradient_3" x1="0" x2="1" y1="0" y2="0">
40
+ <stop offset="0" stop-color="#5058e6" />
41
+ <stop offset="1" stop-color="#373ebf" />
42
+ </linearGradient>
43
+ <linearGradient gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)"
44
+ gradientUnits="userSpaceOnUse" id="LinearGradient_4" x1="0" x2="1" y1="0" y2="0">
45
+ <stop offset="0" stop-color="#91a7ff" />
46
+ <stop offset="1" stop-color="#5058e6" />
47
+ </linearGradient>
48
+ <linearGradient gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)"
49
+ gradientUnits="userSpaceOnUse" id="LinearGradient_5" x1="0" x2="1" y1="0" y2="0">
50
+ <stop offset="0" stop-color="#646cff" />
51
+ <stop offset="1" stop-color="#c2d6ff" />
52
+ </linearGradient>
53
+ <linearGradient gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)"
54
+ gradientUnits="userSpaceOnUse" id="LinearGradient_6" x1="0" x2="1" y1="0" y2="0">
55
+ <stop offset="0" stop-color="#c2d6ff" />
56
+ <stop offset="1" stop-color="#646cff" />
57
+ </linearGradient>
58
+ <linearGradient gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)"
59
+ gradientUnits="userSpaceOnUse" id="LinearGradient_7" x1="0" x2="1" y1="0" y2="0">
60
+ <stop offset="0" stop-color="#373ebf" />
61
+ <stop offset="1" stop-color="#5058e6" />
62
+ </linearGradient>
63
+ </defs>
64
+ </svg>
@@ -0,0 +1,135 @@
1
+ <script setup lang="ts">
2
+ // 应用外壳 = 布局(精简内核无布局扫描,App.vue 直接承担)。
3
+ // Link/PageView 为全局组件(ubeanVue 插件注册),类型见 src/typings/globals.d.ts。
4
+ import { useRouter } from 'vue-router';
5
+
6
+ const router = useRouter();
7
+ </script>
8
+
9
+ <template>
10
+ <div class="layout">
11
+ <header class="header">
12
+ <nav class="nav">
13
+ <Link to="/" class="logo">ubean-client</Link>
14
+ <div class="nav-links">
15
+ <Link to="/">首页</Link>
16
+ <Link to="/users">用户</Link>
17
+ <Link to="/guide">指南</Link>
18
+ <Link to="/blog/hello">博客</Link>
19
+ <Link to="/about">关于</Link>
20
+ <button class="back-btn" type="button" @click="router.back()">← back</button>
21
+ </div>
22
+ </nav>
23
+ </header>
24
+ <main class="main">
25
+ <!-- 页面渲染出口:keep-alive / transition / reload 信号都在这里生效 -->
26
+ <PageView />
27
+ </main>
28
+ <footer class="footer">
29
+ <p>standalone SPA · 只依赖 @ubean/vue(vue + vue-router)</p>
30
+ </footer>
31
+ </div>
32
+ </template>
33
+
34
+ <style>
35
+ * {
36
+ margin: 0;
37
+ padding: 0;
38
+ box-sizing: border-box;
39
+ }
40
+
41
+ body {
42
+ background: #fafafa;
43
+ color: #24292f;
44
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
45
+ }
46
+
47
+ .layout {
48
+ min-height: 100vh;
49
+ display: flex;
50
+ flex-direction: column;
51
+ }
52
+
53
+ .header {
54
+ background: linear-gradient(135deg, #42b883, #35495e);
55
+ padding: 0 20px;
56
+ }
57
+
58
+ .nav {
59
+ max-width: 960px;
60
+ margin: 0 auto;
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ height: 60px;
65
+ }
66
+
67
+ .logo {
68
+ color: white;
69
+ font-size: 1.2rem;
70
+ font-weight: 700;
71
+ text-decoration: none;
72
+ font-family: 'SF Mono', ui-monospace, monospace;
73
+ }
74
+
75
+ .nav-links {
76
+ display: flex;
77
+ gap: 0.95rem;
78
+ align-items: center;
79
+ flex-wrap: wrap;
80
+ }
81
+
82
+ .nav-links a {
83
+ color: rgba(255, 255, 255, 0.88);
84
+ text-decoration: none;
85
+ font-weight: 500;
86
+ font-size: 0.88rem;
87
+ }
88
+
89
+ .nav-links a.router-link-active {
90
+ color: white;
91
+ text-decoration: underline;
92
+ text-underline-offset: 6px;
93
+ }
94
+
95
+ .back-btn {
96
+ background: rgba(255, 255, 255, 0.15);
97
+ border: 1px solid rgba(255, 255, 255, 0.35);
98
+ color: white;
99
+ border-radius: 6px;
100
+ padding: 4px 10px;
101
+ font-size: 0.8rem;
102
+ cursor: pointer;
103
+ }
104
+
105
+ .back-btn:hover {
106
+ background: rgba(255, 255, 255, 0.25);
107
+ }
108
+
109
+ .main {
110
+ flex: 1;
111
+ max-width: 960px;
112
+ margin: 0 auto;
113
+ padding: 40px 20px;
114
+ width: 100%;
115
+ }
116
+
117
+ .footer {
118
+ border-top: 1px solid rgba(128, 128, 128, 0.25);
119
+ color: gray;
120
+ text-align: center;
121
+ padding: 1.2rem;
122
+ font-size: 0.85rem;
123
+ }
124
+
125
+ /* about 路由声明的页面级过渡(meta.transition: 'fade') */
126
+ .fade-enter-active,
127
+ .fade-leave-active {
128
+ transition: opacity 0.25s ease;
129
+ }
130
+
131
+ .fade-enter-from,
132
+ .fade-leave-to {
133
+ opacity: 0;
134
+ }
135
+ </style>
@@ -0,0 +1,63 @@
1
+ import { createApp } from 'vue';
2
+ import { createRouter, createWebHistory } from 'vue-router';
3
+ import {
4
+ ubeanVue,
5
+ defineMatcher,
6
+ createMatcherGuard,
7
+ createPageHead,
8
+ setupPageHeadGuard,
9
+ LOADING_KEY,
10
+ ERROR_KEY
11
+ } from '@ubean/vue';
12
+ import { routes, loadingComponent, errorComponent } from 'virtual:ubean-vue-routes';
13
+ import App from './App.vue';
14
+
15
+ /**
16
+ * 独立 SPA 引导 —— @ubean/vue 精简内核 + 文件式路由(全能力):
17
+ * 1. 路由表来自 `virtual:ubean-vue-routes`(@ubean/vue/vite 扫描 src/pages
18
+ * 并编译期提取 definePage/frontmatter 生成);内核不产出 router 工厂,
19
+ * 直接用 vue-router 原生 createRouter 自行创建实例。
20
+ * 2. `app.use(ubeanVue, { routes })` 一次完成:
21
+ * 全局组件(Link/PageView/SlotView)注册 + keep-alive 缓存播种。
22
+ * 3. 动态参数 matcher:`[id=numeric]` 文件语法把 matchers 写进 route.meta,
23
+ * 这边注册校验函数 + 挂守卫;校验失败重定向 NotFound(404.vue)。
24
+ * 4. 特殊页注入协议:loading/error 组件经 LOADING_KEY/ERROR_KEY 接入
25
+ * PageView 的 <Suspense>/<ErrorBoundary>(框架运行时默认提供,精简内核自行 provide)。
26
+ * 5. 页面级 head(opt-in):@unhead/vue 为 optional peer,createPageHead
27
+ * 懒加载;守卫在每次导航后 push route.meta.head。
28
+ *
29
+ * 无应用工厂、无 i18n、无自动引入 —— 全部显式导入。
30
+ */
31
+
32
+ // matcher 注册:`[id=numeric]` 文件语法的运行时校验函数
33
+ defineMatcher('numeric', value => /^\d+$/.test(value));
34
+
35
+ const router = createRouter({
36
+ history: createWebHistory(),
37
+ routes,
38
+ scrollBehavior(_to, _from, savedPosition) {
39
+ if (savedPosition) return savedPosition;
40
+ if (_to.hash) return { el: _to.hash, behavior: 'smooth' };
41
+ return { top: 0 };
42
+ }
43
+ });
44
+
45
+ // matcher 守卫:meta.matchers 校验失败 → NotFound(/users/abc 会被拦截)
46
+ router.beforeEach(createMatcherGuard());
47
+
48
+ const app = createApp(App);
49
+ app.use(router);
50
+ app.use(ubeanVue, { routes });
51
+
52
+ // 特殊页注入(PageView 的 Suspense fallback / ErrorBoundary 渲染)
53
+ app.provide(LOADING_KEY, loadingComponent);
54
+ app.provide(ERROR_KEY, errorComponent);
55
+
56
+ // 页面级 head(@unhead/vue 懒加载;失败静默 —— head 是纯增强)
57
+ createPageHead()
58
+ .then(head => setupPageHeadGuard(router, head))
59
+ .catch(() => {
60
+ /* @unhead/vue 未安装时跳过 */
61
+ });
62
+
63
+ app.mount('#app');
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ // 特殊页:pages/404.vue 由 vite 插件注册为 catch-all /:pathMatch(.*)*
3
+ import { useRoute } from 'vue-router';
4
+
5
+ const route = useRoute();
6
+ </script>
7
+
8
+ <template>
9
+ <section class="not-found">
10
+ <h1>404</h1>
11
+ <p class="mono">未匹配的路径:{{ route.fullPath }}</p>
12
+ <p>
13
+ 回到
14
+ <Link to="/">首页</Link>
15
+ </p>
16
+ </section>
17
+ </template>
18
+
19
+ <style scoped>
20
+ .not-found {
21
+ text-align: center;
22
+ padding: 4rem 0;
23
+ }
24
+
25
+ h1 {
26
+ font-size: 4rem;
27
+ color: #42b883;
28
+ margin-bottom: 0.5rem;
29
+ }
30
+
31
+ .mono {
32
+ font-family: 'SF Mono', ui-monospace, monospace;
33
+ color: gray;
34
+ margin-bottom: 1rem;
35
+ }
36
+ </style>
@@ -0,0 +1,151 @@
1
+ <script lang="ts">
2
+ // 模块级挂载计数:跨组件实例持久 —— reload 会销毁并重建实例,
3
+ // 实例内的状态会随之重置,模块级变量才能观察"重挂载了几次"。
4
+ let totalMounts = 0;
5
+ </script>
6
+
7
+ <script setup lang="ts">
8
+ // 过渡与重载演示 —— definePage({ transition: 'fade' }) 声明页面级过渡(CSS 在 App.vue);
9
+ // reload 内部:隐藏页面(实例入缓存)→ 空窗口内剪除缓存条目 →
10
+ // bump 渲染 key 全新挂载并重新入缓存,全程不触碰活跃页的缓存成员关系。
11
+ import { ref } from 'vue';
12
+ import { useRoute, useRouter } from 'vue-router';
13
+ import {
14
+ definePage,
15
+ useReloadSignal,
16
+ getPageTransitionName,
17
+ setPageTransition,
18
+ clearPageTransition,
19
+ usePage
20
+ } from '@ubean/vue';
21
+
22
+ definePage({ name: 'About', cache: true, transition: 'fade' });
23
+
24
+ const reload = useReloadSignal();
25
+ const transitionName = getPageTransitionName();
26
+ const route = useRoute();
27
+ const router = useRouter();
28
+ // 精简版 usePage():仅 pageData(props/component/errors)。
29
+ // 精简 SPA 无工厂注入 → 共享空对象;路由态用 useRoute()。
30
+ const pageData = usePage();
31
+
32
+ const mountSeq = ref(++totalMounts);
33
+
34
+ async function doReload() {
35
+ await reload.reload('About');
36
+ }
37
+
38
+ function setFade() {
39
+ setPageTransition('fade');
40
+ }
41
+
42
+ function clearTransition() {
43
+ clearPageTransition();
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <section>
49
+ <h1>过渡与重载控制</h1>
50
+ <p class="subtitle">
51
+ 本页路由声明
52
+ <code>meta.transition: 'fade'</code>
53
+ ;全局过渡名可运行时切换。
54
+ </p>
55
+
56
+ <div class="card">
57
+ <p>
58
+ 全局过渡名:
59
+ <code class="mono">{{ transitionName || '(无)' }}</code>
60
+ </p>
61
+ <div class="row">
62
+ <button type="button" @click="setFade">setPageTransition('fade')</button>
63
+ <button type="button" @click="clearTransition">clearPageTransition</button>
64
+ </div>
65
+ </div>
66
+
67
+ <div class="card">
68
+ <p>
69
+ 重载计数:
70
+ <strong>{{ reload.counter.value }}</strong>
71
+ </p>
72
+ <p>
73
+ 重载中:
74
+ <strong>{{ reload.reloading.value }}</strong>
75
+ </p>
76
+ <p class="mono">本实例是 About 页第 {{ mountSeq }} 次挂载(reload 递增)</p>
77
+ <div class="row">
78
+ <button type="button" :disabled="reload.reloading.value" @click="doReload">reload.reload('About')</button>
79
+ <button type="button" @click="router.push('/')">router.push('/')</button>
80
+ </div>
81
+ </div>
82
+
83
+ <p class="hint">
84
+ <code>useRoute().fullPath</code>
85
+ =
86
+ <code class="mono">{{ route.fullPath }}</code>
87
+ (路由驱动);精简版
88
+ <code>usePage()</code>
89
+ 仅 pageData —— component/props/errors 为
90
+ <code class="mono">
91
+ {{ String(pageData.component ?? '(空)') }}/{{ Object.keys(pageData.props ?? {}).length }}/{{
92
+ pageData.errors === null ? 'null' : 'map'
93
+ }}
94
+ </code>
95
+ (无工厂注入)。
96
+ </p>
97
+ </section>
98
+ </template>
99
+
100
+ <style scoped>
101
+ h1 {
102
+ font-size: 1.5rem;
103
+ margin-bottom: 0.5rem;
104
+ }
105
+
106
+ .subtitle {
107
+ color: gray;
108
+ margin-bottom: 1.25rem;
109
+ font-size: 0.92rem;
110
+ }
111
+
112
+ .card {
113
+ border: 1px solid rgba(128, 128, 128, 0.3);
114
+ border-radius: 10px;
115
+ padding: 1rem 1.25rem;
116
+ margin-bottom: 1rem;
117
+ }
118
+
119
+ .row {
120
+ display: flex;
121
+ gap: 0.6rem;
122
+ flex-wrap: wrap;
123
+ margin-top: 0.5rem;
124
+ }
125
+
126
+ .row button {
127
+ cursor: pointer;
128
+ border: 1px solid rgba(66, 184, 131, 0.6);
129
+ background: transparent;
130
+ color: inherit;
131
+ border-radius: 6px;
132
+ padding: 5px 12px;
133
+ }
134
+
135
+ .row button:disabled {
136
+ opacity: 0.5;
137
+ cursor: wait;
138
+ }
139
+
140
+ .mono {
141
+ font-family: 'SF Mono', ui-monospace, monospace;
142
+ font-size: 0.82rem;
143
+ }
144
+
145
+ .hint {
146
+ margin-top: 1.25rem;
147
+ font-size: 0.88rem;
148
+ color: gray;
149
+ line-height: 1.7;
150
+ }
151
+ </style>
@@ -0,0 +1,8 @@
1
+ import { definePage } from '@ubean/vue';
2
+
3
+ /**
4
+ * reuse 路由 —— 纯元数据文件(无组件):
5
+ * 注册 /about2 路由,组件复用目标页 `About`(src/pages/about.vue)。
6
+ * 未显式声明 cache 时继承目标的缓存声明(About cache: true)。
7
+ */
8
+ definePage({ reuse: 'About' });
@@ -0,0 +1,72 @@
1
+ <script setup lang="ts">
2
+ // catch-all:文件名 `[...slug]` → 路由 `/blog/**:slug`(零或多个参数,数组)。
3
+ import { computed } from 'vue';
4
+ import { useRoute } from 'vue-router';
5
+ import { definePage } from '@ubean/vue';
6
+
7
+ definePage({ name: 'BlogAllSlug' });
8
+
9
+ const route = useRoute();
10
+ // typed-router 生效时 route.params 是全路由参数联合,此处按本页形状窄化。
11
+ const params = route.params as { slug?: string[] };
12
+ const crumbs = computed(() => params.slug ?? []);
13
+ </script>
14
+
15
+ <template>
16
+ <section>
17
+ <h1>博客(catch-all)</h1>
18
+ <p class="subtitle">
19
+ 路由
20
+ <code>/blog/**:slug</code>
21
+ —— 文件
22
+ <code>[...slug].vue</code>
23
+ </p>
24
+ <div class="card">
25
+ <p>
26
+ slug 段数:
27
+ <strong>{{ crumbs.length }}</strong>
28
+ </p>
29
+ <ol class="crumbs">
30
+ <li v-for="(c, i) in crumbs" :key="i" class="mono">{{ c }}</li>
31
+ </ol>
32
+ </div>
33
+ <nav class="toc">
34
+ <Link to="/blog">/blog</Link>
35
+ <Link to="/blog/vue/release-notes">/blog/vue/release-notes</Link>
36
+ <Link to="/blog/2026/08/kernel">/blog/2026/08/kernel</Link>
37
+ </nav>
38
+ </section>
39
+ </template>
40
+
41
+ <style scoped>
42
+ h1 {
43
+ font-size: 1.5rem;
44
+ margin-bottom: 0.5rem;
45
+ }
46
+ .subtitle {
47
+ color: gray;
48
+ margin-bottom: 1.25rem;
49
+ font-size: 0.92rem;
50
+ }
51
+ .card {
52
+ border: 1px solid rgba(128, 128, 128, 0.3);
53
+ border-radius: 10px;
54
+ padding: 1rem 1.25rem;
55
+ }
56
+ .crumbs {
57
+ margin: 0.5rem 0 0 1.2rem;
58
+ }
59
+ .mono {
60
+ font-family: 'SF Mono', ui-monospace, monospace;
61
+ }
62
+ .toc {
63
+ display: flex;
64
+ gap: 1rem;
65
+ margin-top: 1rem;
66
+ flex-wrap: wrap;
67
+ }
68
+ .toc a {
69
+ color: #42b883;
70
+ text-decoration: none;
71
+ }
72
+ </style>