@jasonshimmy/vite-plugin-cer-app 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.
Files changed (299) hide show
  1. package/.github/copilot-instructions.md +130 -0
  2. package/.github/workflows/publish.yml +206 -0
  3. package/.nvmrc +1 -0
  4. package/CHANGELOG.md +10 -0
  5. package/IMPLEMENTATION_PLAN.md +391 -0
  6. package/README.md +231 -0
  7. package/VITE_PLUGIN_FRAMEWORK_PLAN.md +594 -0
  8. package/commits.txt +3 -0
  9. package/dist/__tests__/plugin/path-utils.test.d.ts +2 -0
  10. package/dist/__tests__/plugin/path-utils.test.d.ts.map +1 -0
  11. package/dist/__tests__/plugin/path-utils.test.js +305 -0
  12. package/dist/__tests__/plugin/path-utils.test.js.map +1 -0
  13. package/dist/__tests__/plugin/scanner.test.d.ts +2 -0
  14. package/dist/__tests__/plugin/scanner.test.d.ts.map +1 -0
  15. package/dist/__tests__/plugin/scanner.test.js +143 -0
  16. package/dist/__tests__/plugin/scanner.test.js.map +1 -0
  17. package/dist/__tests__/plugin/transforms/auto-import.test.d.ts +2 -0
  18. package/dist/__tests__/plugin/transforms/auto-import.test.d.ts.map +1 -0
  19. package/dist/__tests__/plugin/transforms/auto-import.test.js +151 -0
  20. package/dist/__tests__/plugin/transforms/auto-import.test.js.map +1 -0
  21. package/dist/__tests__/plugin/transforms/head-inject.test.d.ts +2 -0
  22. package/dist/__tests__/plugin/transforms/head-inject.test.d.ts.map +1 -0
  23. package/dist/__tests__/plugin/transforms/head-inject.test.js +151 -0
  24. package/dist/__tests__/plugin/transforms/head-inject.test.js.map +1 -0
  25. package/dist/__tests__/plugin/virtual/components.test.d.ts +2 -0
  26. package/dist/__tests__/plugin/virtual/components.test.d.ts.map +1 -0
  27. package/dist/__tests__/plugin/virtual/components.test.js +47 -0
  28. package/dist/__tests__/plugin/virtual/components.test.js.map +1 -0
  29. package/dist/__tests__/plugin/virtual/composables.test.d.ts +2 -0
  30. package/dist/__tests__/plugin/virtual/composables.test.d.ts.map +1 -0
  31. package/dist/__tests__/plugin/virtual/composables.test.js +48 -0
  32. package/dist/__tests__/plugin/virtual/composables.test.js.map +1 -0
  33. package/dist/__tests__/plugin/virtual/layouts.test.d.ts +2 -0
  34. package/dist/__tests__/plugin/virtual/layouts.test.d.ts.map +1 -0
  35. package/dist/__tests__/plugin/virtual/layouts.test.js +59 -0
  36. package/dist/__tests__/plugin/virtual/layouts.test.js.map +1 -0
  37. package/dist/__tests__/plugin/virtual/middleware.test.d.ts +2 -0
  38. package/dist/__tests__/plugin/virtual/middleware.test.d.ts.map +1 -0
  39. package/dist/__tests__/plugin/virtual/middleware.test.js +58 -0
  40. package/dist/__tests__/plugin/virtual/middleware.test.js.map +1 -0
  41. package/dist/__tests__/plugin/virtual/plugins.test.d.ts +2 -0
  42. package/dist/__tests__/plugin/virtual/plugins.test.d.ts.map +1 -0
  43. package/dist/__tests__/plugin/virtual/plugins.test.js +73 -0
  44. package/dist/__tests__/plugin/virtual/plugins.test.js.map +1 -0
  45. package/dist/__tests__/plugin/virtual/routes.test.d.ts +2 -0
  46. package/dist/__tests__/plugin/virtual/routes.test.d.ts.map +1 -0
  47. package/dist/__tests__/plugin/virtual/routes.test.js +167 -0
  48. package/dist/__tests__/plugin/virtual/routes.test.js.map +1 -0
  49. package/dist/__tests__/plugin/virtual/server-api.test.d.ts +2 -0
  50. package/dist/__tests__/plugin/virtual/server-api.test.d.ts.map +1 -0
  51. package/dist/__tests__/plugin/virtual/server-api.test.js +72 -0
  52. package/dist/__tests__/plugin/virtual/server-api.test.js.map +1 -0
  53. package/dist/__tests__/runtime/use-head.test.d.ts +2 -0
  54. package/dist/__tests__/runtime/use-head.test.d.ts.map +1 -0
  55. package/dist/__tests__/runtime/use-head.test.js +202 -0
  56. package/dist/__tests__/runtime/use-head.test.js.map +1 -0
  57. package/dist/__tests__/runtime/use-page-data.test.d.ts +2 -0
  58. package/dist/__tests__/runtime/use-page-data.test.d.ts.map +1 -0
  59. package/dist/__tests__/runtime/use-page-data.test.js +41 -0
  60. package/dist/__tests__/runtime/use-page-data.test.js.map +1 -0
  61. package/dist/cli/commands/build.d.ts +3 -0
  62. package/dist/cli/commands/build.d.ts.map +1 -0
  63. package/dist/cli/commands/build.js +103 -0
  64. package/dist/cli/commands/build.js.map +1 -0
  65. package/dist/cli/commands/dev.d.ts +3 -0
  66. package/dist/cli/commands/dev.d.ts.map +1 -0
  67. package/dist/cli/commands/dev.js +92 -0
  68. package/dist/cli/commands/dev.js.map +1 -0
  69. package/dist/cli/commands/generate.d.ts +7 -0
  70. package/dist/cli/commands/generate.d.ts.map +1 -0
  71. package/dist/cli/commands/generate.js +72 -0
  72. package/dist/cli/commands/generate.js.map +1 -0
  73. package/dist/cli/commands/preview.d.ts +3 -0
  74. package/dist/cli/commands/preview.d.ts.map +1 -0
  75. package/dist/cli/commands/preview.js +191 -0
  76. package/dist/cli/commands/preview.js.map +1 -0
  77. package/dist/cli/create/index.d.ts +3 -0
  78. package/dist/cli/create/index.d.ts.map +1 -0
  79. package/dist/cli/create/index.js +184 -0
  80. package/dist/cli/create/index.js.map +1 -0
  81. package/dist/cli/index.d.ts +3 -0
  82. package/dist/cli/index.d.ts.map +1 -0
  83. package/dist/cli/index.js +17 -0
  84. package/dist/cli/index.js.map +1 -0
  85. package/dist/index.d.ts +9 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +4 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/plugin/build-ssg.d.ts +12 -0
  90. package/dist/plugin/build-ssg.d.ts.map +1 -0
  91. package/dist/plugin/build-ssg.js +212 -0
  92. package/dist/plugin/build-ssg.js.map +1 -0
  93. package/dist/plugin/build-ssr.d.ts +10 -0
  94. package/dist/plugin/build-ssr.d.ts.map +1 -0
  95. package/dist/plugin/build-ssr.js +139 -0
  96. package/dist/plugin/build-ssr.js.map +1 -0
  97. package/dist/plugin/dev-server.d.ts +46 -0
  98. package/dist/plugin/dev-server.d.ts.map +1 -0
  99. package/dist/plugin/dev-server.js +194 -0
  100. package/dist/plugin/dev-server.js.map +1 -0
  101. package/dist/plugin/dts-generator.d.ts +27 -0
  102. package/dist/plugin/dts-generator.d.ts.map +1 -0
  103. package/dist/plugin/dts-generator.js +180 -0
  104. package/dist/plugin/dts-generator.js.map +1 -0
  105. package/dist/plugin/index.d.ts +13 -0
  106. package/dist/plugin/index.d.ts.map +1 -0
  107. package/dist/plugin/index.js +298 -0
  108. package/dist/plugin/index.js.map +1 -0
  109. package/dist/plugin/path-utils.d.ts +57 -0
  110. package/dist/plugin/path-utils.d.ts.map +1 -0
  111. package/dist/plugin/path-utils.js +160 -0
  112. package/dist/plugin/path-utils.js.map +1 -0
  113. package/dist/plugin/scanner.d.ts +17 -0
  114. package/dist/plugin/scanner.d.ts.map +1 -0
  115. package/dist/plugin/scanner.js +54 -0
  116. package/dist/plugin/scanner.js.map +1 -0
  117. package/dist/plugin/transforms/auto-import.d.ts +14 -0
  118. package/dist/plugin/transforms/auto-import.d.ts.map +1 -0
  119. package/dist/plugin/transforms/auto-import.js +154 -0
  120. package/dist/plugin/transforms/auto-import.js.map +1 -0
  121. package/dist/plugin/transforms/head-inject.d.ts +29 -0
  122. package/dist/plugin/transforms/head-inject.d.ts.map +1 -0
  123. package/dist/plugin/transforms/head-inject.js +127 -0
  124. package/dist/plugin/transforms/head-inject.js.map +1 -0
  125. package/dist/plugin/virtual/components.d.ts +6 -0
  126. package/dist/plugin/virtual/components.d.ts.map +1 -0
  127. package/dist/plugin/virtual/components.js +22 -0
  128. package/dist/plugin/virtual/components.js.map +1 -0
  129. package/dist/plugin/virtual/composables.d.ts +6 -0
  130. package/dist/plugin/virtual/composables.d.ts.map +1 -0
  131. package/dist/plugin/virtual/composables.js +22 -0
  132. package/dist/plugin/virtual/composables.js.map +1 -0
  133. package/dist/plugin/virtual/error.d.ts +13 -0
  134. package/dist/plugin/virtual/error.d.ts.map +1 -0
  135. package/dist/plugin/virtual/error.js +32 -0
  136. package/dist/plugin/virtual/error.js.map +1 -0
  137. package/dist/plugin/virtual/layouts.d.ts +6 -0
  138. package/dist/plugin/virtual/layouts.d.ts.map +1 -0
  139. package/dist/plugin/virtual/layouts.js +33 -0
  140. package/dist/plugin/virtual/layouts.js.map +1 -0
  141. package/dist/plugin/virtual/loading.d.ts +11 -0
  142. package/dist/plugin/virtual/loading.d.ts.map +1 -0
  143. package/dist/plugin/virtual/loading.js +30 -0
  144. package/dist/plugin/virtual/loading.js.map +1 -0
  145. package/dist/plugin/virtual/middleware.d.ts +6 -0
  146. package/dist/plugin/virtual/middleware.d.ts.map +1 -0
  147. package/dist/plugin/virtual/middleware.js +36 -0
  148. package/dist/plugin/virtual/middleware.js.map +1 -0
  149. package/dist/plugin/virtual/plugins.d.ts +6 -0
  150. package/dist/plugin/virtual/plugins.d.ts.map +1 -0
  151. package/dist/plugin/virtual/plugins.js +30 -0
  152. package/dist/plugin/virtual/plugins.js.map +1 -0
  153. package/dist/plugin/virtual/routes.d.ts +16 -0
  154. package/dist/plugin/virtual/routes.d.ts.map +1 -0
  155. package/dist/plugin/virtual/routes.js +131 -0
  156. package/dist/plugin/virtual/routes.js.map +1 -0
  157. package/dist/plugin/virtual/server-api.d.ts +6 -0
  158. package/dist/plugin/virtual/server-api.d.ts.map +1 -0
  159. package/dist/plugin/virtual/server-api.js +41 -0
  160. package/dist/plugin/virtual/server-api.js.map +1 -0
  161. package/dist/plugin/virtual/server-middleware.d.ts +6 -0
  162. package/dist/plugin/virtual/server-middleware.d.ts.map +1 -0
  163. package/dist/plugin/virtual/server-middleware.js +36 -0
  164. package/dist/plugin/virtual/server-middleware.js.map +1 -0
  165. package/dist/runtime/app-template.d.ts +10 -0
  166. package/dist/runtime/app-template.d.ts.map +1 -0
  167. package/dist/runtime/app-template.js +143 -0
  168. package/dist/runtime/app-template.js.map +1 -0
  169. package/dist/runtime/composables/index.d.ts +4 -0
  170. package/dist/runtime/composables/index.d.ts.map +1 -0
  171. package/dist/runtime/composables/index.js +3 -0
  172. package/dist/runtime/composables/index.js.map +1 -0
  173. package/dist/runtime/composables/use-head.d.ts +30 -0
  174. package/dist/runtime/composables/use-head.d.ts.map +1 -0
  175. package/dist/runtime/composables/use-head.js +182 -0
  176. package/dist/runtime/composables/use-head.js.map +1 -0
  177. package/dist/runtime/composables/use-page-data.d.ts +32 -0
  178. package/dist/runtime/composables/use-page-data.d.ts.map +1 -0
  179. package/dist/runtime/composables/use-page-data.js +41 -0
  180. package/dist/runtime/composables/use-page-data.js.map +1 -0
  181. package/dist/runtime/entry-client-template.d.ts +8 -0
  182. package/dist/runtime/entry-client-template.d.ts.map +1 -0
  183. package/dist/runtime/entry-client-template.js +18 -0
  184. package/dist/runtime/entry-client-template.js.map +1 -0
  185. package/dist/runtime/entry-server-template.d.ts +9 -0
  186. package/dist/runtime/entry-server-template.d.ts.map +1 -0
  187. package/dist/runtime/entry-server-template.js +72 -0
  188. package/dist/runtime/entry-server-template.js.map +1 -0
  189. package/dist/types/api.d.ts +16 -0
  190. package/dist/types/api.d.ts.map +1 -0
  191. package/dist/types/api.js +2 -0
  192. package/dist/types/api.js.map +1 -0
  193. package/dist/types/config.d.ts +32 -0
  194. package/dist/types/config.d.ts.map +1 -0
  195. package/dist/types/config.js +4 -0
  196. package/dist/types/config.js.map +1 -0
  197. package/dist/types/index.d.ts +7 -0
  198. package/dist/types/index.d.ts.map +1 -0
  199. package/dist/types/index.js +2 -0
  200. package/dist/types/index.js.map +1 -0
  201. package/dist/types/middleware.d.ts +6 -0
  202. package/dist/types/middleware.d.ts.map +1 -0
  203. package/dist/types/middleware.js +2 -0
  204. package/dist/types/middleware.js.map +1 -0
  205. package/dist/types/page.d.ts +21 -0
  206. package/dist/types/page.d.ts.map +1 -0
  207. package/dist/types/page.js +2 -0
  208. package/dist/types/page.js.map +1 -0
  209. package/dist/types/plugin.d.ts +12 -0
  210. package/dist/types/plugin.d.ts.map +1 -0
  211. package/dist/types/plugin.js +2 -0
  212. package/dist/types/plugin.js.map +1 -0
  213. package/docs/cli.md +233 -0
  214. package/docs/components.md +114 -0
  215. package/docs/composables.md +99 -0
  216. package/docs/configuration.md +270 -0
  217. package/docs/data-loading.md +165 -0
  218. package/docs/getting-started.md +235 -0
  219. package/docs/head-management.md +206 -0
  220. package/docs/layouts.md +112 -0
  221. package/docs/middleware.md +140 -0
  222. package/docs/plugins.md +138 -0
  223. package/docs/rendering-modes.md +251 -0
  224. package/docs/routing.md +180 -0
  225. package/docs/server-api.md +172 -0
  226. package/docs/testing.md +462 -0
  227. package/package.json +75 -0
  228. package/src/__tests__/plugin/path-utils.test.ts +399 -0
  229. package/src/__tests__/plugin/scanner.test.ts +172 -0
  230. package/src/__tests__/plugin/transforms/auto-import.test.ts +229 -0
  231. package/src/__tests__/plugin/transforms/head-inject.test.ts +178 -0
  232. package/src/__tests__/plugin/virtual/components.test.ts +56 -0
  233. package/src/__tests__/plugin/virtual/composables.test.ts +57 -0
  234. package/src/__tests__/plugin/virtual/layouts.test.ts +70 -0
  235. package/src/__tests__/plugin/virtual/middleware.test.ts +68 -0
  236. package/src/__tests__/plugin/virtual/plugins.test.ts +84 -0
  237. package/src/__tests__/plugin/virtual/routes.test.ts +202 -0
  238. package/src/__tests__/plugin/virtual/server-api.test.ts +85 -0
  239. package/src/__tests__/runtime/use-head.test.ts +243 -0
  240. package/src/__tests__/runtime/use-page-data.test.ts +45 -0
  241. package/src/cli/commands/build.ts +114 -0
  242. package/src/cli/commands/dev.ts +101 -0
  243. package/src/cli/commands/generate.ts +81 -0
  244. package/src/cli/commands/preview.ts +218 -0
  245. package/src/cli/create/index.ts +250 -0
  246. package/src/cli/create/templates/spa/app/app.ts.tpl +74 -0
  247. package/src/cli/create/templates/spa/app/layouts/default.ts.tpl +15 -0
  248. package/src/cli/create/templates/spa/app/pages/index.ts.tpl +8 -0
  249. package/src/cli/create/templates/spa/cer.config.ts.tpl +6 -0
  250. package/src/cli/create/templates/spa/index.html.tpl +12 -0
  251. package/src/cli/create/templates/spa/package.json.tpl +18 -0
  252. package/src/cli/create/templates/ssg/app/app.ts.tpl +74 -0
  253. package/src/cli/create/templates/ssg/app/layouts/default.ts.tpl +15 -0
  254. package/src/cli/create/templates/ssg/app/pages/index.ts.tpl +17 -0
  255. package/src/cli/create/templates/ssg/cer.config.ts.tpl +13 -0
  256. package/src/cli/create/templates/ssg/index.html.tpl +12 -0
  257. package/src/cli/create/templates/ssg/package.json.tpl +19 -0
  258. package/src/cli/create/templates/ssr/app/app.ts.tpl +74 -0
  259. package/src/cli/create/templates/ssr/app/layouts/default.ts.tpl +15 -0
  260. package/src/cli/create/templates/ssr/app/pages/index.ts.tpl +8 -0
  261. package/src/cli/create/templates/ssr/cer.config.ts.tpl +10 -0
  262. package/src/cli/create/templates/ssr/index.html.tpl +12 -0
  263. package/src/cli/create/templates/ssr/package.json.tpl +18 -0
  264. package/src/cli/index.ts +20 -0
  265. package/src/index.ts +13 -0
  266. package/src/plugin/build-ssg.ts +259 -0
  267. package/src/plugin/build-ssr.ts +147 -0
  268. package/src/plugin/dev-server.ts +266 -0
  269. package/src/plugin/dts-generator.ts +214 -0
  270. package/src/plugin/index.ts +330 -0
  271. package/src/plugin/path-utils.ts +186 -0
  272. package/src/plugin/scanner.ts +65 -0
  273. package/src/plugin/transforms/auto-import.ts +190 -0
  274. package/src/plugin/transforms/head-inject.ts +161 -0
  275. package/src/plugin/virtual/components.ts +28 -0
  276. package/src/plugin/virtual/composables.ts +28 -0
  277. package/src/plugin/virtual/error.ts +34 -0
  278. package/src/plugin/virtual/layouts.ts +41 -0
  279. package/src/plugin/virtual/loading.ts +33 -0
  280. package/src/plugin/virtual/middleware.ts +45 -0
  281. package/src/plugin/virtual/plugins.ts +36 -0
  282. package/src/plugin/virtual/routes.ts +147 -0
  283. package/src/plugin/virtual/server-api.ts +52 -0
  284. package/src/plugin/virtual/server-middleware.ts +44 -0
  285. package/src/runtime/app-template.ts +142 -0
  286. package/src/runtime/composables/index.ts +3 -0
  287. package/src/runtime/composables/use-head.ts +204 -0
  288. package/src/runtime/composables/use-page-data.ts +39 -0
  289. package/src/runtime/entry-client-template.ts +17 -0
  290. package/src/runtime/entry-server-template.ts +71 -0
  291. package/src/types/api.ts +19 -0
  292. package/src/types/config.ts +39 -0
  293. package/src/types/index.ts +6 -0
  294. package/src/types/middleware.ts +16 -0
  295. package/src/types/page.ts +29 -0
  296. package/src/types/plugin.ts +13 -0
  297. package/tsconfig.build.json +10 -0
  298. package/tsconfig.json +19 -0
  299. package/vitest.config.ts +29 -0
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * create-cer-app scaffold CLI.
4
+ * Usage: create-cer-app [project-name] [--mode spa|ssr|ssg]
5
+ */
6
+ import { Command } from 'commander'
7
+ import { resolve, join, dirname, basename } from 'pathe'
8
+ import { existsSync } from 'node:fs'
9
+ import { mkdir, readFile, writeFile, readdir, stat } from 'node:fs/promises'
10
+ import { createInterface } from 'node:readline'
11
+ import { fileURLToPath } from 'node:url'
12
+
13
+ const __filename = fileURLToPath(import.meta.url)
14
+ const __dirname = dirname(__filename)
15
+
16
+ type AppMode = 'spa' | 'ssr' | 'ssg'
17
+
18
+ /**
19
+ * Prompts the user for input on stdin.
20
+ */
21
+ function prompt(question: string, defaultValue?: string): Promise<string> {
22
+ return new Promise((resolve) => {
23
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
24
+ const displayQuestion = defaultValue
25
+ ? `${question} (${defaultValue}): `
26
+ : `${question}: `
27
+
28
+ rl.question(displayQuestion, (answer) => {
29
+ rl.close()
30
+ resolve(answer.trim() || defaultValue || '')
31
+ })
32
+ })
33
+ }
34
+
35
+ /**
36
+ * Prompts the user to choose a mode from a list.
37
+ */
38
+ async function promptMode(): Promise<AppMode> {
39
+ console.log('Select app mode:')
40
+ console.log(' 1. spa — Single-Page App (client-side rendering)')
41
+ console.log(' 2. ssr — Server-Side Rendering')
42
+ console.log(' 3. ssg — Static Site Generation')
43
+
44
+ const answer = await prompt('Mode [1/2/3]', '1')
45
+
46
+ const modeMap: Record<string, AppMode> = {
47
+ '1': 'spa',
48
+ '2': 'ssr',
49
+ '3': 'ssg',
50
+ spa: 'spa',
51
+ ssr: 'ssr',
52
+ ssg: 'ssg',
53
+ }
54
+
55
+ return modeMap[answer] ?? 'spa'
56
+ }
57
+
58
+ /**
59
+ * Recursively reads all files from the template directory.
60
+ */
61
+ async function readTemplateFiles(dir: string): Promise<Map<string, string>> {
62
+ const files = new Map<string, string>()
63
+
64
+ async function walk(currentDir: string, prefix: string): Promise<void> {
65
+ const entries = await readdir(currentDir)
66
+ for (const entry of entries) {
67
+ const fullPath = join(currentDir, entry)
68
+ const relativePath = prefix ? `${prefix}/${entry}` : entry
69
+ const info = await stat(fullPath)
70
+
71
+ if (info.isDirectory()) {
72
+ await walk(fullPath, relativePath)
73
+ } else {
74
+ const content = await readFile(fullPath, 'utf-8')
75
+ // Strip .tpl extension from key
76
+ const key = relativePath.endsWith('.tpl') ? relativePath.slice(0, -4) : relativePath
77
+ files.set(key, content)
78
+ }
79
+ }
80
+ }
81
+
82
+ await walk(dir, '')
83
+ return files
84
+ }
85
+
86
+ /**
87
+ * Replaces template tokens in a content string.
88
+ */
89
+ function applyTokens(content: string, tokens: Record<string, string>): string {
90
+ let result = content
91
+ for (const [key, value] of Object.entries(tokens)) {
92
+ result = result.replaceAll(`{{${key}}}`, value)
93
+ }
94
+ return result
95
+ }
96
+
97
+ /**
98
+ * Writes template files to the target directory.
99
+ */
100
+ async function writeTemplateFiles(
101
+ files: Map<string, string>,
102
+ targetDir: string,
103
+ tokens: Record<string, string>,
104
+ ): Promise<void> {
105
+ for (const [relativePath, rawContent] of files) {
106
+ const content = applyTokens(rawContent, tokens)
107
+ const outputPath = join(targetDir, relativePath)
108
+ await mkdir(dirname(outputPath), { recursive: true })
109
+ await writeFile(outputPath, content, 'utf-8')
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Returns the path to the template directory for the given mode.
115
+ * Resolves relative to the compiled dist output.
116
+ */
117
+ function getTemplateDir(mode: AppMode): string {
118
+ // When running from compiled dist/, templates are in create/templates/
119
+ // This file is at dist/cli/create/index.js, so templates are at dist/cli/create/templates/
120
+ return join(__dirname, 'templates', mode)
121
+ }
122
+
123
+ async function main(): Promise<void> {
124
+ const program = new Command()
125
+
126
+ program
127
+ .name('create-cer-app')
128
+ .description('Scaffold a new CER App project')
129
+ .argument('[project-name]', 'Name of the project to create')
130
+ .option('--mode <mode>', 'App mode: spa, ssr, or ssg')
131
+ .option('--dir <dir>', 'Directory to create the project in (defaults to project name)')
132
+ .action(async (projectNameArg?: string, options?: { mode?: string; dir?: string }) => {
133
+ console.log('\nWelcome to create-cer-app!\n')
134
+
135
+ // Gather inputs
136
+ const projectName = projectNameArg ?? (await prompt('Project name', 'my-cer-app'))
137
+ const mode: AppMode = (options?.mode as AppMode | undefined) ?? (await promptMode())
138
+ const targetDir = resolve(options?.dir ?? projectName)
139
+
140
+ console.log(`\nCreating ${mode.toUpperCase()} project: ${projectName}`)
141
+ console.log(` Directory: ${targetDir}\n`)
142
+
143
+ if (existsSync(targetDir)) {
144
+ const overwrite = await prompt(`Directory "${targetDir}" already exists. Overwrite? [y/N]`, 'N')
145
+ if (!overwrite.toLowerCase().startsWith('y')) {
146
+ console.log('Aborted.')
147
+ process.exit(0)
148
+ }
149
+ }
150
+
151
+ // Load template files
152
+ const templateDir = getTemplateDir(mode)
153
+
154
+ if (!existsSync(templateDir)) {
155
+ // Fallback: generate minimal template inline
156
+ console.warn(`[create-cer-app] Template directory not found at ${templateDir}, using inline template.`)
157
+ await generateInlineTemplate(targetDir, projectName, mode)
158
+ } else {
159
+ const files = await readTemplateFiles(templateDir)
160
+ await writeTemplateFiles(files, targetDir, { projectName })
161
+ }
162
+
163
+ console.log(`\nProject created! To get started:\n`)
164
+ console.log(` cd ${basename(targetDir)}`)
165
+ console.log(` npm install`)
166
+ console.log(` npm run dev\n`)
167
+ })
168
+
169
+ await program.parseAsync(process.argv)
170
+ }
171
+
172
+ /**
173
+ * Generates a minimal project structure inline when templates aren't available.
174
+ */
175
+ async function generateInlineTemplate(
176
+ targetDir: string,
177
+ projectName: string,
178
+ mode: AppMode,
179
+ ): Promise<void> {
180
+ await mkdir(join(targetDir, 'app/pages'), { recursive: true })
181
+ await mkdir(join(targetDir, 'app/layouts'), { recursive: true })
182
+
183
+ // package.json
184
+ await writeFile(
185
+ join(targetDir, 'package.json'),
186
+ JSON.stringify(
187
+ {
188
+ name: projectName,
189
+ version: '0.1.0',
190
+ type: 'module',
191
+ scripts: {
192
+ dev: 'cer-app dev',
193
+ build: 'cer-app build',
194
+ preview: 'cer-app preview',
195
+ },
196
+ dependencies: {
197
+ '@jasonshimmy/custom-elements-runtime': '^3.1.1',
198
+ },
199
+ devDependencies: {
200
+ vite: '^5.0.0',
201
+ 'vite-plugin-cer-app': '^0.1.0',
202
+ typescript: '^5.4.0',
203
+ },
204
+ },
205
+ null,
206
+ 2,
207
+ ),
208
+ 'utf-8',
209
+ )
210
+
211
+ // cer.config.ts
212
+ await writeFile(
213
+ join(targetDir, 'cer.config.ts'),
214
+ `import { defineConfig } from 'vite-plugin-cer-app'\n\nexport default defineConfig({\n mode: '${mode}',\n autoImports: { components: true, composables: true, directives: true, runtime: true },\n})\n`,
215
+ 'utf-8',
216
+ )
217
+
218
+ // app/app.ts
219
+ await writeFile(
220
+ join(targetDir, 'app/app.ts'),
221
+ `import '@jasonshimmy/custom-elements-runtime/css'\nimport 'virtual:cer-components'\nimport routes from 'virtual:cer-routes'\nimport layouts from 'virtual:cer-layouts'\nimport plugins from 'virtual:cer-plugins'\nimport { hasLoading, loadingTag } from 'virtual:cer-loading'\nimport { hasError, errorTag } from 'virtual:cer-error'\nimport { component, ref, useOnConnected, useOnDisconnected, registerBuiltinComponents } from '@jasonshimmy/custom-elements-runtime'\nimport { initRouter } from '@jasonshimmy/custom-elements-runtime/router'\nimport { enableJITCSS } from '@jasonshimmy/custom-elements-runtime/jit-css'\nimport { createDOMJITCSS } from '@jasonshimmy/custom-elements-runtime/dom-jit-css'\n\nregisterBuiltinComponents()\nenableJITCSS()\n\nconst router = initRouter({ routes })\n\nconst isNavigating = ref(false)\nconst currentError = ref(null)\n;(globalThis as any).resetError = () => { currentError.value = null; router.replace(router.getCurrent().path) }\nconst _push = router.push.bind(router)\nconst _replace = router.replace.bind(router)\nrouter.push = async (path) => { isNavigating.value = true; currentError.value = null; try { await _push(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false } }\nrouter.replace = async (path) => { isNavigating.value = true; currentError.value = null; try { await _replace(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false } }\n\ncomponent('cer-layout-view', () => {\n const current = ref(router.getCurrent())\n let unsub: (() => void) | undefined\n useOnConnected(() => { unsub = router.subscribe((s: typeof current.value) => { current.value = s }) })\n useOnDisconnected(() => { unsub?.(); unsub = undefined })\n if (currentError.value !== null) {\n if (hasError && errorTag) return { tag: errorTag, props: { attrs: { error: String(currentError.value) } }, children: [] }\n return { tag: 'div', props: { attrs: { style: 'padding:2rem;font-family:monospace' } }, children: [String(currentError.value)] }\n }\n if (isNavigating.value && hasLoading && loadingTag) return { tag: loadingTag, props: {}, children: [] }\n const matched = router.matchRoute(current.value.path)\n const layoutName = (matched?.route as any)?.meta?.layout ?? 'default'\n const layoutTag = (layouts as Record<string, string>)[layoutName]\n const routerView = { tag: 'router-view', props: {}, children: [] }\n return layoutTag ? { tag: layoutTag, props: {}, children: [routerView] } : routerView\n})\n\nfor (const plugin of plugins ?? []) {\n if (plugin && typeof plugin.setup === 'function') {\n await plugin.setup({ router, provide: (key, value) => { (globalThis as any)[key] = value }, config: {} })\n }\n}\n\nif (typeof window !== 'undefined') {\n await router.replace(window.location.pathname + window.location.search + window.location.hash)\n createDOMJITCSS().mount()\n}\n\nexport { router }\n`,
222
+ 'utf-8',
223
+ )
224
+
225
+ // app/pages/index.ts
226
+ await writeFile(
227
+ join(targetDir, 'app/pages/index.ts'),
228
+ `component('page-index', () => {\n return html\`\n <div>\n <h1>Welcome to ${projectName}</h1>\n <p>Edit <code>app/pages/index.ts</code> to get started.</p>\n </div>\n \`\n})\n`,
229
+ 'utf-8',
230
+ )
231
+
232
+ // app/layouts/default.ts
233
+ await writeFile(
234
+ join(targetDir, 'app/layouts/default.ts'),
235
+ `component('layout-default', () => {\n return html\`\n <header><nav><router-link to="/">Home</router-link></nav></header>\n <main><slot></slot></main>\n <footer><p>Built with CER App</p></footer>\n \`\n})\n`,
236
+ 'utf-8',
237
+ )
238
+
239
+ // index.html
240
+ await writeFile(
241
+ join(targetDir, 'index.html'),
242
+ `<!DOCTYPE html>\n<html lang="en">\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>${projectName}</title>\n </head>\n <body>\n <cer-layout-view></cer-layout-view>\n <script type="module" src="/app/app.ts"></script>\n </body>\n</html>\n`,
243
+ 'utf-8',
244
+ )
245
+ }
246
+
247
+ main().catch((err) => {
248
+ console.error('[create-cer-app] Fatal error:', err)
249
+ process.exit(1)
250
+ })
@@ -0,0 +1,74 @@
1
+ import '@jasonshimmy/custom-elements-runtime/css'
2
+ import 'virtual:cer-components'
3
+ import routes from 'virtual:cer-routes'
4
+ import layouts from 'virtual:cer-layouts'
5
+ import plugins from 'virtual:cer-plugins'
6
+ import { hasLoading, loadingTag } from 'virtual:cer-loading'
7
+ import { hasError, errorTag } from 'virtual:cer-error'
8
+ import {
9
+ component,
10
+ ref,
11
+ useOnConnected,
12
+ useOnDisconnected,
13
+ registerBuiltinComponents,
14
+ } from '@jasonshimmy/custom-elements-runtime'
15
+ import { initRouter } from '@jasonshimmy/custom-elements-runtime/router'
16
+ import { enableJITCSS } from '@jasonshimmy/custom-elements-runtime/jit-css'
17
+ import { createDOMJITCSS } from '@jasonshimmy/custom-elements-runtime/dom-jit-css'
18
+
19
+ registerBuiltinComponents()
20
+ enableJITCSS()
21
+
22
+ const router = initRouter({ routes })
23
+
24
+ const isNavigating = ref(false)
25
+ const currentError = ref(null)
26
+ ;(globalThis as any).resetError = () => {
27
+ currentError.value = null
28
+ router.replace(router.getCurrent().path)
29
+ }
30
+
31
+ const _push = router.push.bind(router)
32
+ const _replace = router.replace.bind(router)
33
+ router.push = async (path) => {
34
+ isNavigating.value = true
35
+ currentError.value = null
36
+ try { await _push(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false }
37
+ }
38
+ router.replace = async (path) => {
39
+ isNavigating.value = true
40
+ currentError.value = null
41
+ try { await _replace(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false }
42
+ }
43
+
44
+ component('cer-layout-view', () => {
45
+ const current = ref(router.getCurrent())
46
+ let unsub: (() => void) | undefined
47
+ useOnConnected(() => { unsub = router.subscribe((s: typeof current.value) => { current.value = s }) })
48
+ useOnDisconnected(() => { unsub?.(); unsub = undefined })
49
+
50
+ if (currentError.value !== null) {
51
+ if (hasError && errorTag) return { tag: errorTag, props: { attrs: { error: String(currentError.value) } }, children: [] }
52
+ return { tag: 'div', props: { attrs: { style: 'padding:2rem;font-family:monospace' } }, children: [String(currentError.value)] }
53
+ }
54
+ if (isNavigating.value && hasLoading && loadingTag) return { tag: loadingTag, props: {}, children: [] }
55
+
56
+ const matched = router.matchRoute(current.value.path)
57
+ const layoutName = (matched?.route as any)?.meta?.layout ?? 'default'
58
+ const layoutTag = (layouts as Record<string, string>)[layoutName]
59
+ const routerView = { tag: 'router-view', props: {}, children: [] }
60
+ return layoutTag ? { tag: layoutTag, props: {}, children: [routerView] } : routerView
61
+ })
62
+
63
+ for (const plugin of plugins) {
64
+ if (plugin && typeof plugin.setup === 'function') {
65
+ await plugin.setup({ router, provide: (key, value) => { (globalThis as any)[key] = value }, config: {} })
66
+ }
67
+ }
68
+
69
+ if (typeof window !== 'undefined') {
70
+ await router.replace(window.location.pathname + window.location.search + window.location.hash)
71
+ createDOMJITCSS().mount()
72
+ }
73
+
74
+ export { router }
@@ -0,0 +1,15 @@
1
+ component('layout-default', () => {
2
+ return html`
3
+ <header>
4
+ <nav>
5
+ <router-link to="/">Home</router-link>
6
+ </nav>
7
+ </header>
8
+ <main>
9
+ <slot></slot>
10
+ </main>
11
+ <footer>
12
+ <p>Built with CER App</p>
13
+ </footer>
14
+ `
15
+ })
@@ -0,0 +1,8 @@
1
+ component('page-index', () => {
2
+ return html`
3
+ <div>
4
+ <h1>Welcome to {{projectName}}</h1>
5
+ <p>Edit <code>app/pages/index.ts</code> to get started.</p>
6
+ </div>
7
+ `
8
+ })
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vite-plugin-cer-app'
2
+
3
+ export default defineConfig({
4
+ mode: 'spa',
5
+ autoImports: { components: true, composables: true, directives: true, runtime: true },
6
+ })
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{projectName}}</title>
7
+ </head>
8
+ <body>
9
+ <cer-layout-view></cer-layout-view>
10
+ <script type="module" src="/app/app.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "cer-app dev",
7
+ "build": "cer-app build",
8
+ "preview": "cer-app preview"
9
+ },
10
+ "dependencies": {
11
+ "@jasonshimmy/custom-elements-runtime": "^3.1.1"
12
+ },
13
+ "devDependencies": {
14
+ "vite": "^5.0.0",
15
+ "vite-plugin-cer-app": "^0.1.0",
16
+ "typescript": "^5.4.0"
17
+ }
18
+ }
@@ -0,0 +1,74 @@
1
+ import '@jasonshimmy/custom-elements-runtime/css'
2
+ import 'virtual:cer-components'
3
+ import routes from 'virtual:cer-routes'
4
+ import layouts from 'virtual:cer-layouts'
5
+ import plugins from 'virtual:cer-plugins'
6
+ import { hasLoading, loadingTag } from 'virtual:cer-loading'
7
+ import { hasError, errorTag } from 'virtual:cer-error'
8
+ import {
9
+ component,
10
+ ref,
11
+ useOnConnected,
12
+ useOnDisconnected,
13
+ registerBuiltinComponents,
14
+ } from '@jasonshimmy/custom-elements-runtime'
15
+ import { initRouter } from '@jasonshimmy/custom-elements-runtime/router'
16
+ import { enableJITCSS } from '@jasonshimmy/custom-elements-runtime/jit-css'
17
+ import { createDOMJITCSS } from '@jasonshimmy/custom-elements-runtime/dom-jit-css'
18
+
19
+ registerBuiltinComponents()
20
+ enableJITCSS()
21
+
22
+ const router = initRouter({ routes })
23
+
24
+ const isNavigating = ref(false)
25
+ const currentError = ref(null)
26
+ ;(globalThis as any).resetError = () => {
27
+ currentError.value = null
28
+ router.replace(router.getCurrent().path)
29
+ }
30
+
31
+ const _push = router.push.bind(router)
32
+ const _replace = router.replace.bind(router)
33
+ router.push = async (path) => {
34
+ isNavigating.value = true
35
+ currentError.value = null
36
+ try { await _push(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false }
37
+ }
38
+ router.replace = async (path) => {
39
+ isNavigating.value = true
40
+ currentError.value = null
41
+ try { await _replace(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false }
42
+ }
43
+
44
+ component('cer-layout-view', () => {
45
+ const current = ref(router.getCurrent())
46
+ let unsub: (() => void) | undefined
47
+ useOnConnected(() => { unsub = router.subscribe((s: typeof current.value) => { current.value = s }) })
48
+ useOnDisconnected(() => { unsub?.(); unsub = undefined })
49
+
50
+ if (currentError.value !== null) {
51
+ if (hasError && errorTag) return { tag: errorTag, props: { attrs: { error: String(currentError.value) } }, children: [] }
52
+ return { tag: 'div', props: { attrs: { style: 'padding:2rem;font-family:monospace' } }, children: [String(currentError.value)] }
53
+ }
54
+ if (isNavigating.value && hasLoading && loadingTag) return { tag: loadingTag, props: {}, children: [] }
55
+
56
+ const matched = router.matchRoute(current.value.path)
57
+ const layoutName = (matched?.route as any)?.meta?.layout ?? 'default'
58
+ const layoutTag = (layouts as Record<string, string>)[layoutName]
59
+ const routerView = { tag: 'router-view', props: {}, children: [] }
60
+ return layoutTag ? { tag: layoutTag, props: {}, children: [routerView] } : routerView
61
+ })
62
+
63
+ for (const plugin of plugins) {
64
+ if (plugin && typeof plugin.setup === 'function') {
65
+ await plugin.setup({ router, provide: (key, value) => { (globalThis as any)[key] = value }, config: {} })
66
+ }
67
+ }
68
+
69
+ if (typeof window !== 'undefined') {
70
+ await router.replace(window.location.pathname + window.location.search + window.location.hash)
71
+ createDOMJITCSS().mount()
72
+ }
73
+
74
+ export { router }
@@ -0,0 +1,15 @@
1
+ component('layout-default', () => {
2
+ return html`
3
+ <header>
4
+ <nav>
5
+ <router-link to="/">Home</router-link>
6
+ </nav>
7
+ </header>
8
+ <main>
9
+ <slot></slot>
10
+ </main>
11
+ <footer>
12
+ <p>Built with CER App</p>
13
+ </footer>
14
+ `
15
+ })
@@ -0,0 +1,17 @@
1
+ component('page-index', () => {
2
+ return html`
3
+ <div>
4
+ <h1>Welcome to {{projectName}}</h1>
5
+ <p>Edit <code>app/pages/index.ts</code> to get started.</p>
6
+ </div>
7
+ `
8
+ })
9
+
10
+ // Export page metadata for SSG
11
+ export const meta = {
12
+ layout: 'default',
13
+ ssg: {
14
+ // No dynamic paths needed for the index page
15
+ paths: async () => [],
16
+ },
17
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vite-plugin-cer-app'
2
+
3
+ export default defineConfig({
4
+ mode: 'ssg',
5
+ ssg: {
6
+ routes: 'auto',
7
+ concurrency: 4,
8
+ },
9
+ ssr: {
10
+ dsd: true,
11
+ },
12
+ autoImports: { components: true, composables: true, directives: true, runtime: true },
13
+ })
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{projectName}}</title>
7
+ </head>
8
+ <body>
9
+ <cer-layout-view></cer-layout-view>
10
+ <script type="module" src="/app/app.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "cer-app dev",
7
+ "build": "cer-app build",
8
+ "generate": "cer-app generate",
9
+ "preview": "cer-app preview"
10
+ },
11
+ "dependencies": {
12
+ "@jasonshimmy/custom-elements-runtime": "^3.1.1"
13
+ },
14
+ "devDependencies": {
15
+ "vite": "^5.0.0",
16
+ "vite-plugin-cer-app": "^0.1.0",
17
+ "typescript": "^5.4.0"
18
+ }
19
+ }
@@ -0,0 +1,74 @@
1
+ import '@jasonshimmy/custom-elements-runtime/css'
2
+ import 'virtual:cer-components'
3
+ import routes from 'virtual:cer-routes'
4
+ import layouts from 'virtual:cer-layouts'
5
+ import plugins from 'virtual:cer-plugins'
6
+ import { hasLoading, loadingTag } from 'virtual:cer-loading'
7
+ import { hasError, errorTag } from 'virtual:cer-error'
8
+ import {
9
+ component,
10
+ ref,
11
+ useOnConnected,
12
+ useOnDisconnected,
13
+ registerBuiltinComponents,
14
+ } from '@jasonshimmy/custom-elements-runtime'
15
+ import { initRouter } from '@jasonshimmy/custom-elements-runtime/router'
16
+ import { enableJITCSS } from '@jasonshimmy/custom-elements-runtime/jit-css'
17
+ import { createDOMJITCSS } from '@jasonshimmy/custom-elements-runtime/dom-jit-css'
18
+
19
+ registerBuiltinComponents()
20
+ enableJITCSS()
21
+
22
+ const router = initRouter({ routes })
23
+
24
+ const isNavigating = ref(false)
25
+ const currentError = ref(null)
26
+ ;(globalThis as any).resetError = () => {
27
+ currentError.value = null
28
+ router.replace(router.getCurrent().path)
29
+ }
30
+
31
+ const _push = router.push.bind(router)
32
+ const _replace = router.replace.bind(router)
33
+ router.push = async (path) => {
34
+ isNavigating.value = true
35
+ currentError.value = null
36
+ try { await _push(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false }
37
+ }
38
+ router.replace = async (path) => {
39
+ isNavigating.value = true
40
+ currentError.value = null
41
+ try { await _replace(path) } catch (err) { currentError.value = err instanceof Error ? err.message : String(err) } finally { isNavigating.value = false }
42
+ }
43
+
44
+ component('cer-layout-view', () => {
45
+ const current = ref(router.getCurrent())
46
+ let unsub: (() => void) | undefined
47
+ useOnConnected(() => { unsub = router.subscribe((s: typeof current.value) => { current.value = s }) })
48
+ useOnDisconnected(() => { unsub?.(); unsub = undefined })
49
+
50
+ if (currentError.value !== null) {
51
+ if (hasError && errorTag) return { tag: errorTag, props: { attrs: { error: String(currentError.value) } }, children: [] }
52
+ return { tag: 'div', props: { attrs: { style: 'padding:2rem;font-family:monospace' } }, children: [String(currentError.value)] }
53
+ }
54
+ if (isNavigating.value && hasLoading && loadingTag) return { tag: loadingTag, props: {}, children: [] }
55
+
56
+ const matched = router.matchRoute(current.value.path)
57
+ const layoutName = (matched?.route as any)?.meta?.layout ?? 'default'
58
+ const layoutTag = (layouts as Record<string, string>)[layoutName]
59
+ const routerView = { tag: 'router-view', props: {}, children: [] }
60
+ return layoutTag ? { tag: layoutTag, props: {}, children: [routerView] } : routerView
61
+ })
62
+
63
+ for (const plugin of plugins) {
64
+ if (plugin && typeof plugin.setup === 'function') {
65
+ await plugin.setup({ router, provide: (key, value) => { (globalThis as any)[key] = value }, config: {} })
66
+ }
67
+ }
68
+
69
+ if (typeof window !== 'undefined') {
70
+ await router.replace(window.location.pathname + window.location.search + window.location.hash)
71
+ createDOMJITCSS().mount()
72
+ }
73
+
74
+ export { router }
@@ -0,0 +1,15 @@
1
+ component('layout-default', () => {
2
+ return html`
3
+ <header>
4
+ <nav>
5
+ <router-link to="/">Home</router-link>
6
+ </nav>
7
+ </header>
8
+ <main>
9
+ <slot></slot>
10
+ </main>
11
+ <footer>
12
+ <p>Built with CER App</p>
13
+ </footer>
14
+ `
15
+ })
@@ -0,0 +1,8 @@
1
+ component('page-index', () => {
2
+ return html`
3
+ <div>
4
+ <h1>Welcome to {{projectName}}</h1>
5
+ <p>Edit <code>app/pages/index.ts</code> to get started.</p>
6
+ </div>
7
+ `
8
+ })
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vite-plugin-cer-app'
2
+
3
+ export default defineConfig({
4
+ mode: 'ssr',
5
+ ssr: {
6
+ dsd: true,
7
+ streaming: true,
8
+ },
9
+ autoImports: { components: true, composables: true, directives: true, runtime: true },
10
+ })