@jasonshimmy/vite-plugin-cer-app 0.23.1 → 0.24.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 (397) hide show
  1. package/dist/cli/checks/lighthouse.d.ts +26 -0
  2. package/dist/cli/checks/lighthouse.d.ts.map +1 -0
  3. package/dist/cli/checks/lighthouse.js +121 -0
  4. package/dist/cli/checks/lighthouse.js.map +1 -0
  5. package/dist/cli/checks/links.d.ts +12 -0
  6. package/dist/cli/checks/links.d.ts.map +1 -0
  7. package/dist/cli/checks/links.js +89 -0
  8. package/dist/cli/checks/links.js.map +1 -0
  9. package/dist/cli/checks/performance.d.ts +17 -0
  10. package/dist/cli/checks/performance.d.ts.map +1 -0
  11. package/dist/cli/checks/performance.js +61 -0
  12. package/dist/cli/checks/performance.js.map +1 -0
  13. package/dist/cli/commands/check.d.ts +3 -0
  14. package/dist/cli/commands/check.d.ts.map +1 -0
  15. package/dist/cli/commands/check.js +85 -0
  16. package/dist/cli/commands/check.js.map +1 -0
  17. package/dist/cli/commands/preview.d.ts.map +1 -1
  18. package/dist/cli/commands/preview.js +37 -4
  19. package/dist/cli/commands/preview.js.map +1 -1
  20. package/dist/cli/create/index.d.ts +11 -1
  21. package/dist/cli/create/index.d.ts.map +1 -1
  22. package/dist/cli/create/index.js +135 -65
  23. package/dist/cli/create/index.js.map +1 -1
  24. package/dist/cli/create/templates/spa/package.json.tpl +5 -3
  25. package/dist/cli/create/templates/ssg/cer.config.ts.tpl +2 -0
  26. package/dist/cli/create/templates/ssg/package.json.tpl +5 -3
  27. package/dist/cli/create/templates/ssr/package.json.tpl +5 -3
  28. package/dist/cli/index.js +2 -0
  29. package/dist/cli/index.js.map +1 -1
  30. package/dist/index.d.ts +3 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/plugin/build-ssg.d.ts +22 -4
  33. package/dist/plugin/build-ssg.d.ts.map +1 -1
  34. package/dist/plugin/build-ssg.js +273 -13
  35. package/dist/plugin/build-ssg.js.map +1 -1
  36. package/dist/plugin/content/parser.d.ts.map +1 -1
  37. package/dist/plugin/content/parser.js +54 -10
  38. package/dist/plugin/content/parser.js.map +1 -1
  39. package/dist/plugin/dev-server.d.ts +6 -1
  40. package/dist/plugin/dev-server.d.ts.map +1 -1
  41. package/dist/plugin/dev-server.js.map +1 -1
  42. package/dist/plugin/dts-generator.d.ts.map +1 -1
  43. package/dist/plugin/dts-generator.js +50 -8
  44. package/dist/plugin/dts-generator.js.map +1 -1
  45. package/dist/plugin/generated-dir.d.ts +2 -0
  46. package/dist/plugin/generated-dir.d.ts.map +1 -1
  47. package/dist/plugin/generated-dir.js +17 -6
  48. package/dist/plugin/generated-dir.js.map +1 -1
  49. package/dist/plugin/html-post-process.d.ts +35 -0
  50. package/dist/plugin/html-post-process.d.ts.map +1 -0
  51. package/dist/plugin/html-post-process.js +112 -0
  52. package/dist/plugin/html-post-process.js.map +1 -0
  53. package/dist/plugin/index.d.ts +9 -0
  54. package/dist/plugin/index.d.ts.map +1 -1
  55. package/dist/plugin/index.js +89 -14
  56. package/dist/plugin/index.js.map +1 -1
  57. package/dist/plugin/transforms/auto-import.d.ts.map +1 -1
  58. package/dist/plugin/transforms/auto-import.js +7 -0
  59. package/dist/plugin/transforms/auto-import.js.map +1 -1
  60. package/dist/plugin/transforms/prune-runtime-css.d.ts +8 -0
  61. package/dist/plugin/transforms/prune-runtime-css.d.ts.map +1 -0
  62. package/dist/plugin/transforms/prune-runtime-css.js +40 -0
  63. package/dist/plugin/transforms/prune-runtime-css.js.map +1 -0
  64. package/dist/runtime/app-template.d.ts +1 -4
  65. package/dist/runtime/app-template.d.ts.map +1 -1
  66. package/dist/runtime/app-template.js +211 -40
  67. package/dist/runtime/app-template.js.map +1 -1
  68. package/dist/runtime/composables/index.d.ts +4 -0
  69. package/dist/runtime/composables/index.d.ts.map +1 -1
  70. package/dist/runtime/composables/index.js +2 -0
  71. package/dist/runtime/composables/index.js.map +1 -1
  72. package/dist/runtime/composables/use-active-headings.d.ts +24 -0
  73. package/dist/runtime/composables/use-active-headings.d.ts.map +1 -0
  74. package/dist/runtime/composables/use-active-headings.js +112 -0
  75. package/dist/runtime/composables/use-active-headings.js.map +1 -0
  76. package/dist/runtime/composables/use-content-page.d.ts +45 -0
  77. package/dist/runtime/composables/use-content-page.d.ts.map +1 -0
  78. package/dist/runtime/composables/use-content-page.js +179 -0
  79. package/dist/runtime/composables/use-content-page.js.map +1 -0
  80. package/dist/runtime/composables/use-content-search.d.ts.map +1 -1
  81. package/dist/runtime/composables/use-content-search.js +1 -5
  82. package/dist/runtime/composables/use-content-search.js.map +1 -1
  83. package/dist/runtime/composables/use-fetch.d.ts +2 -1
  84. package/dist/runtime/composables/use-fetch.d.ts.map +1 -1
  85. package/dist/runtime/composables/use-fetch.js +112 -43
  86. package/dist/runtime/composables/use-fetch.js.map +1 -1
  87. package/dist/runtime/composables/use-head.d.ts.map +1 -1
  88. package/dist/runtime/composables/use-head.js +30 -6
  89. package/dist/runtime/composables/use-head.js.map +1 -1
  90. package/dist/runtime/composables/use-route.d.ts.map +1 -1
  91. package/dist/runtime/composables/use-route.js +39 -11
  92. package/dist/runtime/composables/use-route.js.map +1 -1
  93. package/dist/runtime/content/client.js +2 -2
  94. package/dist/runtime/content/client.js.map +1 -1
  95. package/dist/runtime/entry-server-template.d.ts +16 -1
  96. package/dist/runtime/entry-server-template.d.ts.map +1 -1
  97. package/dist/runtime/entry-server-template.js +120 -13
  98. package/dist/runtime/entry-server-template.js.map +1 -1
  99. package/dist/types/config.d.ts +53 -4
  100. package/dist/types/config.d.ts.map +1 -1
  101. package/dist/types/config.js.map +1 -1
  102. package/dist/types/middleware.d.ts +2 -2
  103. package/dist/types/middleware.d.ts.map +1 -1
  104. package/package.json +22 -19
  105. package/.github/copilot-instructions.md +0 -169
  106. package/.github/workflows/publish.yml +0 -257
  107. package/.nvmrc +0 -1
  108. package/CHANGELOG.md +0 -232
  109. package/CLAUDE.md +0 -113
  110. package/commits.txt +0 -1
  111. package/cypress.config.ts +0 -16
  112. package/docs/authentication.md +0 -285
  113. package/docs/cli.md +0 -324
  114. package/docs/components.md +0 -237
  115. package/docs/composables.md +0 -907
  116. package/docs/configuration.md +0 -667
  117. package/docs/content.md +0 -570
  118. package/docs/data-loading.md +0 -336
  119. package/docs/getting-started.md +0 -237
  120. package/docs/head-management.md +0 -212
  121. package/docs/i18n.md +0 -159
  122. package/docs/layouts.md +0 -224
  123. package/docs/middleware.md +0 -234
  124. package/docs/plugins.md +0 -170
  125. package/docs/rendering-modes.md +0 -377
  126. package/docs/routing.md +0 -485
  127. package/docs/server-api.md +0 -253
  128. package/docs/testing.md +0 -455
  129. package/docs/use-fetch.md +0 -183
  130. package/e2e/cypress/e2e/api.cy.ts +0 -123
  131. package/e2e/cypress/e2e/async-component.cy.ts +0 -27
  132. package/e2e/cypress/e2e/component-splitting.cy.ts +0 -50
  133. package/e2e/cypress/e2e/content.cy.ts +0 -425
  134. package/e2e/cypress/e2e/cookie.cy.ts +0 -85
  135. package/e2e/cypress/e2e/data.cy.ts +0 -158
  136. package/e2e/cypress/e2e/error-boundary.cy.ts +0 -88
  137. package/e2e/cypress/e2e/fouc.cy.ts +0 -254
  138. package/e2e/cypress/e2e/group-meta.cy.ts +0 -36
  139. package/e2e/cypress/e2e/head.cy.ts +0 -89
  140. package/e2e/cypress/e2e/i18n.cy.ts +0 -79
  141. package/e2e/cypress/e2e/interactive.cy.ts +0 -137
  142. package/e2e/cypress/e2e/isr-nested-runtime.cy.ts +0 -102
  143. package/e2e/cypress/e2e/jit-css-custom-colors.cy.ts +0 -43
  144. package/e2e/cypress/e2e/middleware-chain.cy.ts +0 -89
  145. package/e2e/cypress/e2e/middleware-status.cy.ts +0 -30
  146. package/e2e/cypress/e2e/middleware.cy.ts +0 -45
  147. package/e2e/cypress/e2e/navigate.cy.ts +0 -39
  148. package/e2e/cypress/e2e/observability.cy.ts +0 -77
  149. package/e2e/cypress/e2e/per-route-error.cy.ts +0 -42
  150. package/e2e/cypress/e2e/per-route-render.cy.ts +0 -70
  151. package/e2e/cypress/e2e/preview-hardening.cy.ts +0 -88
  152. package/e2e/cypress/e2e/routes.cy.ts +0 -128
  153. package/e2e/cypress/e2e/seo-meta.cy.ts +0 -108
  154. package/e2e/cypress/e2e/server-middleware.cy.ts +0 -46
  155. package/e2e/cypress/e2e/session-rotation.cy.ts +0 -25
  156. package/e2e/cypress/e2e/session.cy.ts +0 -73
  157. package/e2e/cypress/e2e/ssr-render-error.cy.ts +0 -68
  158. package/e2e/cypress/e2e/synthetic-404.cy.ts +0 -45
  159. package/e2e/cypress/e2e/use-page-data.cy.ts +0 -122
  160. package/e2e/cypress/e2e/use-state.cy.ts +0 -138
  161. package/e2e/cypress/support/commands.ts +0 -120
  162. package/e2e/cypress/support/e2e.ts +0 -10
  163. package/e2e/cypress/tsconfig.json +0 -14
  164. package/e2e/kitchen-sink/app/components/ks-badge.ts +0 -8
  165. package/e2e/kitchen-sink/app/composables/useKsCounter.ts +0 -9
  166. package/e2e/kitchen-sink/app/error.ts +0 -18
  167. package/e2e/kitchen-sink/app/layouts/admin.ts +0 -13
  168. package/e2e/kitchen-sink/app/layouts/default.ts +0 -25
  169. package/e2e/kitchen-sink/app/layouts/group.ts +0 -9
  170. package/e2e/kitchen-sink/app/layouts/minimal.ts +0 -7
  171. package/e2e/kitchen-sink/app/loading.ts +0 -9
  172. package/e2e/kitchen-sink/app/middleware/auth.ts +0 -9
  173. package/e2e/kitchen-sink/app/middleware/custom-log.ts +0 -4
  174. package/e2e/kitchen-sink/app/middleware/group-auth.ts +0 -7
  175. package/e2e/kitchen-sink/app/middleware/logger.ts +0 -14
  176. package/e2e/kitchen-sink/app/pages/(auth)/login.ts +0 -13
  177. package/e2e/kitchen-sink/app/pages/(auth)/protected.ts +0 -16
  178. package/e2e/kitchen-sink/app/pages/404.ts +0 -9
  179. package/e2e/kitchen-sink/app/pages/about.ts +0 -17
  180. package/e2e/kitchen-sink/app/pages/admin/_layout.ts +0 -1
  181. package/e2e/kitchen-sink/app/pages/admin/dashboard.ts +0 -11
  182. package/e2e/kitchen-sink/app/pages/async-component-error-test.ts +0 -18
  183. package/e2e/kitchen-sink/app/pages/async-component-test.ts +0 -18
  184. package/e2e/kitchen-sink/app/pages/blog/[slug].ts +0 -59
  185. package/e2e/kitchen-sink/app/pages/blog/index.ts +0 -51
  186. package/e2e/kitchen-sink/app/pages/content-blog.ts +0 -37
  187. package/e2e/kitchen-sink/app/pages/content-doc.ts +0 -42
  188. package/e2e/kitchen-sink/app/pages/content-fallback.ts +0 -36
  189. package/e2e/kitchen-sink/app/pages/content-guides.ts +0 -35
  190. package/e2e/kitchen-sink/app/pages/content-index.ts +0 -39
  191. package/e2e/kitchen-sink/app/pages/content-search.ts +0 -36
  192. package/e2e/kitchen-sink/app/pages/cookie-test.ts +0 -22
  193. package/e2e/kitchen-sink/app/pages/counter.ts +0 -17
  194. package/e2e/kitchen-sink/app/pages/group-auth-blocked.ts +0 -9
  195. package/e2e/kitchen-sink/app/pages/group-meta-test/_layout.ts +0 -6
  196. package/e2e/kitchen-sink/app/pages/group-meta-test/custom-mw.ts +0 -14
  197. package/e2e/kitchen-sink/app/pages/group-meta-test/page.ts +0 -9
  198. package/e2e/kitchen-sink/app/pages/group-meta-test/protected.ts +0 -8
  199. package/e2e/kitchen-sink/app/pages/head.ts +0 -20
  200. package/e2e/kitchen-sink/app/pages/i18n-test.ts +0 -14
  201. package/e2e/kitchen-sink/app/pages/index.ts +0 -27
  202. package/e2e/kitchen-sink/app/pages/isr-test.ts +0 -17
  203. package/e2e/kitchen-sink/app/pages/items/[id].ts +0 -20
  204. package/e2e/kitchen-sink/app/pages/jit-css-custom-colors-test.ts +0 -14
  205. package/e2e/kitchen-sink/app/pages/loader-error-test.ts +0 -13
  206. package/e2e/kitchen-sink/app/pages/loader-props-test.ts +0 -19
  207. package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +0 -13
  208. package/e2e/kitchen-sink/app/pages/middleware-chain-test.ts +0 -12
  209. package/e2e/kitchen-sink/app/pages/middleware-status-test.ts +0 -9
  210. package/e2e/kitchen-sink/app/pages/navigate-test.ts +0 -16
  211. package/e2e/kitchen-sink/app/pages/observability-test.ts +0 -25
  212. package/e2e/kitchen-sink/app/pages/per-route-error-test.error.ts +0 -13
  213. package/e2e/kitchen-sink/app/pages/per-route-error-test.ts +0 -15
  214. package/e2e/kitchen-sink/app/pages/plugin-dsd-test.ts +0 -10
  215. package/e2e/kitchen-sink/app/pages/render-error-test.ts +0 -12
  216. package/e2e/kitchen-sink/app/pages/render-server-test.ts +0 -12
  217. package/e2e/kitchen-sink/app/pages/render-spa-test.ts +0 -12
  218. package/e2e/kitchen-sink/app/pages/route-info.ts +0 -14
  219. package/e2e/kitchen-sink/app/pages/seo-test.ts +0 -23
  220. package/e2e/kitchen-sink/app/pages/session-rotation-test.ts +0 -25
  221. package/e2e/kitchen-sink/app/pages/use-state-test.ts +0 -37
  222. package/e2e/kitchen-sink/app/plugins/01.setup.ts +0 -7
  223. package/e2e/kitchen-sink/app/plugins/02.ks-plugin-components.ts +0 -27
  224. package/e2e/kitchen-sink/cer-auto-imports.d.ts +0 -51
  225. package/e2e/kitchen-sink/cer-env.d.ts +0 -35
  226. package/e2e/kitchen-sink/cer-tsconfig.json +0 -30
  227. package/e2e/kitchen-sink/cer.config.ts +0 -43
  228. package/e2e/kitchen-sink/content/01.guides/01.index.md +0 -8
  229. package/e2e/kitchen-sink/content/01.guides/02.intro.md +0 -8
  230. package/e2e/kitchen-sink/content/01.guides/10.advanced.md +0 -8
  231. package/e2e/kitchen-sink/content/blog/2026-04-01-hello.md +0 -26
  232. package/e2e/kitchen-sink/content/blog/2026-04-02-draft.md +0 -10
  233. package/e2e/kitchen-sink/content/blog/index.md +0 -8
  234. package/e2e/kitchen-sink/content/blog/no-frontmatter.md +0 -7
  235. package/e2e/kitchen-sink/content/docs/getting-started.md +0 -48
  236. package/e2e/kitchen-sink/content/index.md +0 -16
  237. package/e2e/kitchen-sink/server/api/echo.ts +0 -12
  238. package/e2e/kitchen-sink/server/api/health.ts +0 -3
  239. package/e2e/kitchen-sink/server/api/posts/[slug].ts +0 -11
  240. package/e2e/kitchen-sink/server/api/posts/index.ts +0 -5
  241. package/e2e/kitchen-sink/server/api/session.ts +0 -23
  242. package/e2e/kitchen-sink/server/data/posts.ts +0 -21
  243. package/e2e/kitchen-sink/server/middleware/01-headers.ts +0 -6
  244. package/e2e/kitchen-sink/server/middleware/02-status-test.ts +0 -10
  245. package/e2e/kitchen-sink/tsconfig.json +0 -3
  246. package/e2e/scripts/clean.mjs +0 -14
  247. package/eslint.config.ts +0 -22
  248. package/src/__tests__/cli/adapters/cloudflare-worker.integration.test.ts +0 -132
  249. package/src/__tests__/cli/adapters/cloudflare.test.ts +0 -332
  250. package/src/__tests__/cli/adapters/netlify-bridge.integration.test.ts +0 -139
  251. package/src/__tests__/cli/adapters/netlify.test.ts +0 -286
  252. package/src/__tests__/cli/adapters/vercel-launcher.integration.test.ts +0 -129
  253. package/src/__tests__/cli/adapters/vercel.test.ts +0 -263
  254. package/src/__tests__/cli/preview-hardening.test.ts +0 -265
  255. package/src/__tests__/cli/preview-isr.test.ts +0 -320
  256. package/src/__tests__/index.test.ts +0 -21
  257. package/src/__tests__/plugin/app-template.test.ts +0 -112
  258. package/src/__tests__/plugin/build-ssg-render.test.ts +0 -155
  259. package/src/__tests__/plugin/build-ssg.test.ts +0 -598
  260. package/src/__tests__/plugin/build-ssr.test.ts +0 -192
  261. package/src/__tests__/plugin/cer-app-plugin.test.ts +0 -552
  262. package/src/__tests__/plugin/content/emitter.test.ts +0 -117
  263. package/src/__tests__/plugin/content/loader.test.ts +0 -154
  264. package/src/__tests__/plugin/content/parser.test.ts +0 -381
  265. package/src/__tests__/plugin/content/path-utils.test.ts +0 -69
  266. package/src/__tests__/plugin/content/search.test.ts +0 -119
  267. package/src/__tests__/plugin/dev-server.test.ts +0 -813
  268. package/src/__tests__/plugin/dts-generator.test.ts +0 -394
  269. package/src/__tests__/plugin/entry-server-template.test.ts +0 -385
  270. package/src/__tests__/plugin/generated-dir.test.ts +0 -144
  271. package/src/__tests__/plugin/path-utils.test.ts +0 -411
  272. package/src/__tests__/plugin/resolve-config.test.ts +0 -200
  273. package/src/__tests__/plugin/scanner.test.ts +0 -186
  274. package/src/__tests__/plugin/transforms/auto-import.test.ts +0 -510
  275. package/src/__tests__/plugin/transforms/head-inject.test.ts +0 -178
  276. package/src/__tests__/plugin/virtual/composables.test.ts +0 -57
  277. package/src/__tests__/plugin/virtual/content-components.test.ts +0 -66
  278. package/src/__tests__/plugin/virtual/error.test.ts +0 -71
  279. package/src/__tests__/plugin/virtual/layouts.test.ts +0 -70
  280. package/src/__tests__/plugin/virtual/loading.test.ts +0 -72
  281. package/src/__tests__/plugin/virtual/middleware.test.ts +0 -83
  282. package/src/__tests__/plugin/virtual/plugins.test.ts +0 -129
  283. package/src/__tests__/plugin/virtual/routes.test.ts +0 -884
  284. package/src/__tests__/plugin/virtual/server-api.test.ts +0 -164
  285. package/src/__tests__/plugin/virtual/server-middleware.test.ts +0 -102
  286. package/src/__tests__/runtime/app-template.test.ts +0 -198
  287. package/src/__tests__/runtime/define-middleware.test.ts +0 -64
  288. package/src/__tests__/runtime/define-server-middleware.test.ts +0 -54
  289. package/src/__tests__/runtime/entry-client-template.test.ts +0 -61
  290. package/src/__tests__/runtime/isr-handler.test.ts +0 -338
  291. package/src/__tests__/runtime/oauth/handler.test.ts +0 -358
  292. package/src/__tests__/runtime/oauth/providers.test.ts +0 -47
  293. package/src/__tests__/runtime/oauth-index.test.ts +0 -43
  294. package/src/__tests__/runtime/use-auth.test.ts +0 -169
  295. package/src/__tests__/runtime/use-content-search-composable.test.ts +0 -405
  296. package/src/__tests__/runtime/use-content-search.test.ts +0 -163
  297. package/src/__tests__/runtime/use-content.test.ts +0 -226
  298. package/src/__tests__/runtime/use-cookie.test.ts +0 -277
  299. package/src/__tests__/runtime/use-fetch-component.test.ts +0 -214
  300. package/src/__tests__/runtime/use-fetch.test.ts +0 -377
  301. package/src/__tests__/runtime/use-head.test.ts +0 -266
  302. package/src/__tests__/runtime/use-inject-client.test.ts +0 -67
  303. package/src/__tests__/runtime/use-inject.test.ts +0 -66
  304. package/src/__tests__/runtime/use-locale.test.ts +0 -152
  305. package/src/__tests__/runtime/use-navigate.test.ts +0 -121
  306. package/src/__tests__/runtime/use-page-data.test.ts +0 -298
  307. package/src/__tests__/runtime/use-route.test.ts +0 -156
  308. package/src/__tests__/runtime/use-runtime-config.test.ts +0 -182
  309. package/src/__tests__/runtime/use-seo-meta.test.ts +0 -109
  310. package/src/__tests__/runtime/use-session.test.ts +0 -320
  311. package/src/__tests__/runtime/use-state.test.ts +0 -340
  312. package/src/__tests__/types/config.test.ts +0 -18
  313. package/src/cli/adapters/cloudflare.ts +0 -335
  314. package/src/cli/adapters/netlify.ts +0 -326
  315. package/src/cli/adapters/vercel.ts +0 -311
  316. package/src/cli/commands/adapt.ts +0 -84
  317. package/src/cli/commands/build.ts +0 -165
  318. package/src/cli/commands/dev.ts +0 -125
  319. package/src/cli/commands/generate.ts +0 -91
  320. package/src/cli/commands/preview-isr.ts +0 -172
  321. package/src/cli/commands/preview.ts +0 -489
  322. package/src/cli/create/index.ts +0 -275
  323. package/src/cli/create/templates/shared/.gitignore.tpl +0 -25
  324. package/src/cli/create/templates/shared/app/layouts/default.ts.tpl +0 -15
  325. package/src/cli/create/templates/shared/app/pages/index.ts.tpl +0 -8
  326. package/src/cli/create/templates/shared/index.html.tpl +0 -12
  327. package/src/cli/create/templates/shared/tsconfig.json.tpl +0 -6
  328. package/src/cli/create/templates/spa/cer.config.ts.tpl +0 -6
  329. package/src/cli/create/templates/spa/package.json.tpl +0 -18
  330. package/src/cli/create/templates/ssg/cer.config.ts.tpl +0 -10
  331. package/src/cli/create/templates/ssg/package.json.tpl +0 -19
  332. package/src/cli/create/templates/ssr/cer.config.ts.tpl +0 -6
  333. package/src/cli/create/templates/ssr/package.json.tpl +0 -18
  334. package/src/cli/index.ts +0 -22
  335. package/src/index.ts +0 -20
  336. package/src/plugin/build-ssg.ts +0 -336
  337. package/src/plugin/build-ssr.ts +0 -134
  338. package/src/plugin/content/emitter.ts +0 -50
  339. package/src/plugin/content/index.ts +0 -233
  340. package/src/plugin/content/parser.ts +0 -259
  341. package/src/plugin/content/path-utils.ts +0 -55
  342. package/src/plugin/content/scanner.ts +0 -26
  343. package/src/plugin/content/search.ts +0 -28
  344. package/src/plugin/dev-server.ts +0 -377
  345. package/src/plugin/dts-generator.ts +0 -273
  346. package/src/plugin/generated-dir.ts +0 -121
  347. package/src/plugin/index.ts +0 -553
  348. package/src/plugin/path-utils.ts +0 -186
  349. package/src/plugin/scanner.ts +0 -65
  350. package/src/plugin/transforms/auto-import.ts +0 -206
  351. package/src/plugin/transforms/head-inject.ts +0 -161
  352. package/src/plugin/virtual/composables.ts +0 -28
  353. package/src/plugin/virtual/content-components.ts +0 -83
  354. package/src/plugin/virtual/error.ts +0 -34
  355. package/src/plugin/virtual/layouts.ts +0 -41
  356. package/src/plugin/virtual/loading.ts +0 -32
  357. package/src/plugin/virtual/middleware.ts +0 -45
  358. package/src/plugin/virtual/plugins.ts +0 -46
  359. package/src/plugin/virtual/routes.ts +0 -514
  360. package/src/plugin/virtual/server-api.ts +0 -85
  361. package/src/plugin/virtual/server-middleware.ts +0 -44
  362. package/src/runtime/app-template.ts +0 -380
  363. package/src/runtime/composables/define-middleware.ts +0 -17
  364. package/src/runtime/composables/define-server-middleware.ts +0 -18
  365. package/src/runtime/composables/index.ts +0 -27
  366. package/src/runtime/composables/use-auth.ts +0 -125
  367. package/src/runtime/composables/use-content-search.ts +0 -205
  368. package/src/runtime/composables/use-content.ts +0 -146
  369. package/src/runtime/composables/use-cookie.ts +0 -135
  370. package/src/runtime/composables/use-fetch.ts +0 -438
  371. package/src/runtime/composables/use-head.ts +0 -212
  372. package/src/runtime/composables/use-inject.ts +0 -49
  373. package/src/runtime/composables/use-locale.ts +0 -109
  374. package/src/runtime/composables/use-navigate.ts +0 -58
  375. package/src/runtime/composables/use-page-data.ts +0 -93
  376. package/src/runtime/composables/use-route.ts +0 -71
  377. package/src/runtime/composables/use-runtime-config.ts +0 -123
  378. package/src/runtime/composables/use-seo-meta.ts +0 -80
  379. package/src/runtime/composables/use-session.ts +0 -186
  380. package/src/runtime/composables/use-state.ts +0 -92
  381. package/src/runtime/content/client.ts +0 -168
  382. package/src/runtime/entry-client-template.ts +0 -39
  383. package/src/runtime/entry-server-template.ts +0 -493
  384. package/src/runtime/isr-handler.ts +0 -184
  385. package/src/runtime/oauth/handler.ts +0 -407
  386. package/src/runtime/oauth/index.ts +0 -49
  387. package/src/runtime/oauth/providers.ts +0 -38
  388. package/src/types/api.ts +0 -40
  389. package/src/types/config.ts +0 -371
  390. package/src/types/content.ts +0 -66
  391. package/src/types/index.ts +0 -7
  392. package/src/types/middleware.ts +0 -63
  393. package/src/types/page.ts +0 -117
  394. package/src/types/plugin.ts +0 -34
  395. package/tsconfig.build.json +0 -10
  396. package/tsconfig.json +0 -19
  397. package/vitest.config.ts +0 -33
@@ -1,336 +0,0 @@
1
- # Data Loading
2
-
3
- Each page can export a `loader` function that runs on the server before the page renders. The data is serialized into the HTML response and rehydrated on the client without a second fetch.
4
-
5
- ---
6
-
7
- ## Defining a loader
8
-
9
- ```ts
10
- // app/pages/blog/[slug].ts
11
- import type { PageLoader } from '@jasonshimmy/vite-plugin-cer-app/types'
12
-
13
- component('page-blog-slug', () => {
14
- const data = usePageData<{ title: string; body: string }>()
15
-
16
- return html`
17
- <article>
18
- <h1>${data?.title ?? ''}</h1>
19
- <div>${data?.body ?? ''}</div>
20
- </article>
21
- `
22
- })
23
-
24
- export const loader: PageLoader = async ({ params }) => {
25
- const { data: post } = await useFetch(`https://api.example.com/posts/${params.slug}`)
26
- return { title: post?.title, body: post?.body }
27
- }
28
- ```
29
-
30
- The object returned by `loader` is made available via `usePageData()` in the page component. Primitive values (strings, numbers, booleans) are also forwarded as HTML element attributes so `useProps()` can read them.
31
-
32
- ---
33
-
34
- ## `PageLoader` signature
35
-
36
- ```ts
37
- type PageLoader<
38
- Params extends Record<string, string> = Record<string, string>,
39
- Data = Record<string, unknown>,
40
- > = (ctx: PageLoaderContext<Params>) => Promise<Data> | Data
41
-
42
- interface PageLoaderContext<P extends Record<string, string>> {
43
- params: P // URL path parameters
44
- query: Record<string, string> // Parsed query string
45
- req?: IncomingMessage // Raw Node.js request (present during SSR/SSG server render; absent during client-side navigation)
46
- }
47
- ```
48
-
49
- ---
50
-
51
- ## SSR data flow
52
-
53
- 1. A request arrives for `/blog/hello-world`
54
- 2. The router matches `app/pages/blog/[slug].ts`
55
- 3. The server calls `loader({ params: { slug: 'hello-world' }, query, req })`
56
- 4. The returned data is serialized as `window.__CER_DATA__` in a `<script>` tag in the HTML `<head>`:
57
- ```html
58
- <script>window.__CER_DATA__ = {"title":"Hello World","body":"..."}</script>
59
- ```
60
- 5. The server renders `<page-blog-slug>` directly into the layout using Declarative Shadow DOM
61
- 6. The full HTML (pre-rendered content + client scripts) is sent to the browser
62
-
63
- ---
64
-
65
- ## Client hydration flow
66
-
67
- 1. Browser receives the full HTML — content is immediately visible via Declarative Shadow DOM before any JS runs
68
- 2. Client JS boots; `usePageData()` reads `window.__CER_DATA__` and returns the hydrated values
69
- 3. After the initial `router.replace()` in `.cer/app.ts` completes, `.cer/app.ts` clears the loader data from `globalThis` so subsequent client-side navigations trigger a fresh fetch instead of reusing stale server data
70
- 4. Components that received SSR data skip their `useOnConnected` fetch — no duplicate request
71
-
72
- ---
73
-
74
- ## Client-side navigation and loaders
75
-
76
- Loaders run on the client too — before every navigation. This means `useProps()` and `usePageData()` both work correctly for client-side route transitions, not just on initial SSR/SSG load.
77
-
78
- When `router.push('/path')` is called:
79
- 1. The route module is dynamically imported
80
- 2. If the module exports a `loader`, it is called with `{ params, query }`
81
- 3. Primitive return values (strings, numbers, booleans) are set as HTML attributes on the page element so `useProps()` can read them
82
- 4. All return values are stored in `globalThis.__CER_DATA__` so `usePageData()` also returns them
83
- 5. The page component renders with the correct data immediately — no loading flash or re-render
84
-
85
- ```ts
86
- // app/pages/profile.ts
87
- component('page-profile', () => {
88
- // Works on initial load AND client navigation
89
- const props = useProps<{ username: string; bio: string }>({ username: '', bio: '' })
90
-
91
- return html`
92
- <h1>${props.username}</h1>
93
- <p>${props.bio}</p>
94
- `
95
- })
96
-
97
- export const loader = async ({ params }: { params: { id: string } }) => {
98
- const { data: user } = await useFetch(`/api/users/${params.id}`)
99
- return { username: user?.name, bio: user?.bio }
100
- }
101
- ```
102
-
103
- > **Note:** Only primitive values (strings, numbers, booleans) are forwarded as element attributes. Complex objects (arrays, nested objects) should be accessed via `usePageData()` instead of `useProps()`.
104
-
105
- ---
106
-
107
- ## Accessing loader data in components
108
-
109
- Use `usePageData()` to read loader data — it receives everything the loader returned (primitives and complex objects alike) and works in all modes: SSR, SSG, and client-side navigation.
110
-
111
- ```ts
112
- component('page-user', () => {
113
- const ssrData = usePageData<{ user: { id: string; name: string; email: string } }>()
114
- const user = ref(ssrData?.user ?? { id: '', name: '', email: '' })
115
-
116
- useOnConnected(async () => {
117
- if (ssrData) return // already hydrated
118
- const { data } = await useFetch(`/api/users/${user.value.id}`)
119
- if (data) user.value = data
120
- })
121
-
122
- return html`
123
- <h1>Hello, ${user.value.name}</h1>
124
- <p>${user.value.email}</p>
125
- `
126
- })
127
-
128
- export const loader: PageLoader<{ id: string }> = async ({ params }) => {
129
- const user = await fetchUser(params.id)
130
- return { user }
131
- }
132
- ```
133
-
134
- `useProps()` is an alternative for **primitive values only** (strings, numbers, booleans). It reads element HTML attributes rather than the loader payload directly, which means it also picks up attributes passed by parent components in the component tree — but it cannot receive arrays or objects.
135
-
136
- ```ts
137
- component('page-profile', () => {
138
- // Works for primitives only — use usePageData() if you need objects or arrays
139
- const props = useProps<{ username: string; bio: string }>({ username: '', bio: '' })
140
-
141
- return html`
142
- <h1>${props.username}</h1>
143
- <p>${props.bio}</p>
144
- `
145
- })
146
-
147
- export const loader = async ({ params }: { params: { id: string } }) => {
148
- const { data: user } = await useFetch(`/api/users/${params.id}`)
149
- return { username: user?.name, bio: user?.bio } // primitives only
150
- }
151
- ```
152
-
153
- > **Rule of thumb:** reach for `usePageData()` first. Only prefer `useProps()` when you specifically need the element attribute binding model — for example, when the same component is also used as a child that receives attributes from a parent.
154
-
155
- ---
156
-
157
- ## SSG and loaders
158
-
159
- In SSG mode, `loader` is called at build time for each generated path. The data is baked into the static HTML file and no server is required at runtime.
160
-
161
- ```ts
162
- // app/pages/blog/[slug].ts
163
- export const meta = {
164
- ssg: {
165
- paths: async () => [
166
- { params: { slug: 'hello-world' } },
167
- { params: { slug: 'second-post' } },
168
- ],
169
- },
170
- }
171
-
172
- export const loader: PageLoader<{ slug: string }> = async ({ params }) => {
173
- // Called once per path during `cer-app generate`
174
- const post = await fetchPost(params.slug)
175
- return { post }
176
- }
177
- ```
178
-
179
- ---
180
-
181
- ## Dev server behavior
182
-
183
- In `mode: 'ssr'` and `mode: 'ssg'`, the dev server runs the server entry module and calls your `loader` on every HTML request — matching production behaviour. Both `usePageData()` and `useProps()` receive real loader data during development.
184
-
185
- In `mode: 'spa'`, no loaders run in the dev server. `usePageData()` always returns `null` and `useProps()` returns its defaults. Use `useOnConnected` to fetch data client-side in SPA mode.
186
-
187
- ---
188
-
189
- ## Error handling in loaders
190
-
191
- When a `loader` throws, the SSR error boundary intercepts it:
192
-
193
- - If `app/error.ts` exists, the server renders the `page-error` component instead of the normal page and returns the appropriate HTTP status.
194
- - If `app/error.ts` does not exist, the error is logged to the server console and a blank 500 response is returned.
195
-
196
- To send a specific HTTP status code from a loader, attach a `status` property to the thrown error:
197
-
198
- ```ts
199
- export const loader: PageLoader<{ id: string }> = async ({ params }) => {
200
- const item = await db.item.findById(params.id)
201
- if (!item) {
202
- const err = Object.assign(new Error('Not Found'), { status: 404 })
203
- throw err
204
- }
205
- return { item }
206
- }
207
- ```
208
-
209
- Unhandled errors without a `status` property default to HTTP 500.
210
-
211
- ---
212
-
213
- ## Error boundary — `app/error.ts`
214
-
215
- Create `app/error.ts` to define a custom error page shown when navigation fails. The file must export a custom element named `page-error`:
216
-
217
- ```ts
218
- // app/error.ts
219
- component('page-error', () => {
220
- const props = useProps<{ error: string; status: string }>({
221
- error: 'An unexpected error occurred.',
222
- status: '500',
223
- })
224
-
225
- return html`
226
- <div style="padding:2rem">
227
- <h2 style="color:#c00">Error ${props.status}</h2>
228
- <p>${props.error}</p>
229
- <button @click="${() => (globalThis as any).resetError?.()}">
230
- Try again
231
- </button>
232
- </div>
233
- `
234
- })
235
- ```
236
-
237
- ### Props received by `page-error`
238
-
239
- | Prop | Type | Source |
240
- |------|------|--------|
241
- | `error` | `string` | Error message from the thrown value |
242
- | `status` | `string` | HTTP status code as a string (`"404"`, `"500"`, etc.) — **SSR only** |
243
-
244
- ### `resetError()`
245
-
246
- The framework exposes `globalThis.resetError()` as a global function. Calling it clears the error state and re-navigates to the current path, giving the user a way to recover without a full page reload.
247
-
248
- ```ts
249
- // Call from a button click handler inside page-error
250
- (globalThis as any).resetError?.()
251
- ```
252
-
253
- ### SSR vs. client-side behavior
254
-
255
- | Scenario | Behavior |
256
- |----------|----------|
257
- | **Loader throws during SSR** | Server renders `page-error` with `error` and `status` props; response uses the thrown status code |
258
- | **Navigation throws on the client** | `cer-layout-view` renders `page-error` with `error` prop only (no HTTP status in the browser) |
259
- | **No `app/error.ts` defined (SSR)** | Error is logged to the server console; blank 500 response |
260
- | **No `app/error.ts` defined (client)** | Raw error message rendered in a `<div>` |
261
-
262
- > **SPA mode:** There is no server-side error boundary in SPA mode. The `loader` function is never called server-side, so `page-error` is only rendered for client-side navigation errors. To handle loading failures in SPA, catch errors inside `useOnConnected` and render an error state manually.
263
-
264
- ---
265
-
266
- ## Loader vs. client-side fetching
267
-
268
- Use `loader` for data that:
269
- - Must be present on initial render (SEO, no loading spinner)
270
- - Is fetched from a database or internal service not accessible from the browser
271
- - Benefits from server-side caching or authentication via cookies
272
-
273
- Use client-side fetching (`fetch` or composables) for:
274
- - Data loaded after user interaction
275
- - Paginated or infinite-scroll content
276
- - Real-time updates
277
-
278
- ---
279
-
280
- ## TypeScript generics
281
-
282
- The `PageLoader` type accepts two generics:
283
-
284
- ```ts
285
- // PageLoader<Params, Data>
286
- export const loader: PageLoader<
287
- { id: string }, // URL params shape
288
- { user: User; posts: Post[] } // Return data shape
289
- > = async ({ params }) => {
290
- return { user: await fetchUser(params.id), posts: await fetchPosts(params.id) }
291
- }
292
- ```
293
-
294
- ---
295
-
296
- ## Multi-mode data loading (SPA fallback)
297
-
298
- When building a page that needs to work in **all three modes** — SSR/SSG (with a `loader`) and SPA (no server, no loader) — use the following pattern:
299
-
300
- 1. In SSR/SSG, the server runs `loader` and injects the data via `window.__CER_DATA__`. `usePageData()` returns it immediately; `useOnConnected` sees `ssrData` and skips the client fetch.
301
- 2. In SPA mode there is no server, so `ssrData` is `null`. The client tries the API first, then falls back to a direct module import.
302
-
303
- ```ts
304
- // app/pages/blog/index.ts
305
- component('page-blog-index', () => {
306
- const ssrData = usePageData<{ posts: Post[] }>()
307
- const posts = ref<Post[]>(ssrData?.posts ?? [])
308
-
309
- useOnConnected(async () => {
310
- if (ssrData) return // SSR/SSG: already hydrated, skip the fetch
311
-
312
- // SPA: try the API server first
313
- try {
314
- const r = await fetch('/api/posts')
315
- if (r.ok) {
316
- posts.value = await r.json()
317
- return
318
- }
319
- } catch { /* no API server in static preview */ }
320
-
321
- // SPA static fallback: import data directly from source
322
- const { posts: staticPosts } = await import('../data/posts')
323
- posts.value = staticPosts
324
- })
325
-
326
- return html`<ul>${posts.value.map(p => html`<li>${p.title}</li>`)}</ul>`
327
- })
328
-
329
- // loader runs in SSR and SSG only
330
- export const loader = async () => {
331
- const { data: posts } = await useFetch<Post[]>('/api/posts')
332
- return { posts: posts ?? [] }
333
- }
334
- ```
335
-
336
- The key rule: **always check `ssrData` before fetching on the client**. This prevents a redundant network request when the data was already serialized by the server.
@@ -1,237 +0,0 @@
1
- # Getting Started
2
-
3
- ## Prerequisites
4
-
5
- - Node.js 18+
6
- - `@jasonshimmy/custom-elements-runtime` ≥ 3.0.0
7
- - Vite ≥ 5.0.0
8
-
9
- ---
10
-
11
- ## Option A — Scaffold with `create-cer-app` (recommended)
12
-
13
- ```sh
14
- npx --package @jasonshimmy/vite-plugin-cer-app create-cer-app my-app
15
- ```
16
-
17
- The interactive prompt asks for a project name and rendering mode:
18
-
19
- ```
20
- Welcome to create-cer-app!
21
-
22
- Project name: my-app
23
- Select app mode:
24
- 1. spa — Single-Page App (client-side rendering)
25
- 2. ssr — Server-Side Rendering
26
- 3. ssg — Static Site Generation
27
- Mode [1/2/3]: 1
28
-
29
- Creating SPA project: my-app
30
- Directory: /path/to/my-app
31
-
32
- Project created! To get started:
33
-
34
- cd my-app
35
- npm install
36
- npm run dev
37
- ```
38
-
39
- You can also skip the prompts with flags:
40
-
41
- ```sh
42
- npx --package @jasonshimmy/vite-plugin-cer-app create-cer-app my-app --mode ssr
43
- ```
44
-
45
- ---
46
-
47
- ## Option B — Add to an existing Vite project
48
-
49
- ### 1. Install
50
-
51
- ```sh
52
- npm install -D @jasonshimmy/vite-plugin-cer-app
53
- npm install @jasonshimmy/custom-elements-runtime
54
- ```
55
-
56
- ### 2. Configure Vite
57
-
58
- ```ts
59
- // vite.config.ts
60
- import { defineConfig } from 'vite'
61
- import { cerApp } from '@jasonshimmy/vite-plugin-cer-app'
62
-
63
- export default defineConfig({
64
- plugins: [cerApp()],
65
- })
66
- ```
67
-
68
- Or use a separate `cer.config.ts` (picked up automatically by the CLI, and passed manually to `cerApp()` if using `vite.config.ts`):
69
-
70
- ```ts
71
- // cer.config.ts
72
- import { defineConfig } from '@jasonshimmy/vite-plugin-cer-app'
73
-
74
- export default defineConfig({
75
- mode: 'spa',
76
- })
77
- ```
78
-
79
- ```ts
80
- // vite.config.ts (when using cer.config.ts)
81
- import { defineConfig } from 'vite'
82
- import { cerApp } from '@jasonshimmy/vite-plugin-cer-app'
83
- import cerConfig from './cer.config.ts'
84
-
85
- export default defineConfig({
86
- plugins: [cerApp(cerConfig)],
87
- })
88
- ```
89
-
90
- ### 3. Create the app structure
91
-
92
- ```sh
93
- mkdir -p app/pages app/layouts app/components app/composables app/plugins app/middleware
94
- mkdir -p server/api server/middleware
95
- ```
96
-
97
- ### 4. Write your first page
98
-
99
- ```ts
100
- // app/pages/index.ts
101
- // No imports needed — component, html are auto-injected
102
- component('page-index', () => {
103
- return html`<h1>Hello, World!</h1>`
104
- })
105
- ```
106
-
107
- ### 5. Write a layout
108
-
109
- ```ts
110
- // app/layouts/default.ts
111
- component('layout-default', () => {
112
- return html`
113
- <header><h1>My App</h1></header>
114
- <main><slot></slot></main>
115
- `
116
- })
117
- ```
118
-
119
- ### 6. Create `index.html`
120
-
121
- ```html
122
- <!DOCTYPE html>
123
- <html lang="en">
124
- <head>
125
- <meta charset="UTF-8" />
126
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
127
- <title>My App</title>
128
- </head>
129
- <body>
130
- <cer-layout-view></cer-layout-view>
131
- <script type="module" src="/.cer/app.ts"></script>
132
- </body>
133
- </html>
134
- ```
135
-
136
- > **Note:** The framework bootstrap lives in `.cer/app.ts` and is regenerated automatically on every dev server start and build. You never edit or own this file — updates to the plugin propagate to it immediately, just like Nuxt's `.nuxt/` directory.
137
-
138
- ---
139
-
140
- ## TypeScript path aliases
141
-
142
- The framework automatically generates `.cer/tsconfig.json` with `~/` path aliases on every dev server start and build. To enable IDE autocomplete and type-checking for these aliases, extend it from your project `tsconfig.json`:
143
-
144
- ```json
145
- // tsconfig.json
146
- {
147
- "extends": "./.cer/tsconfig.json"
148
- }
149
- ```
150
-
151
- The generated aliases map:
152
-
153
- | Alias | Resolves to |
154
- |---|---|
155
- | `~/*` | `app/*` |
156
- | `~/pages/*` | `app/pages/*` |
157
- | `~/layouts/*` | `app/layouts/*` |
158
- | `~/components/*` | `app/components/*` |
159
- | `~/composables/*` | `app/composables/*` |
160
- | `~/plugins/*` | `app/plugins/*` |
161
- | `~/middleware/*` | `app/middleware/*` |
162
- | `~/assets/*` | `app/assets/*` |
163
-
164
- ```ts
165
- // Before — relative import
166
- import { useTheme } from '../../composables/useTheme'
167
-
168
- // After — alias import
169
- import { useTheme } from '~/composables/useTheme'
170
- ```
171
-
172
- > `.cer/tsconfig.json` is auto-generated — do not edit or commit it. It is regenerated on every `cer-app dev` and `cer-app build`. Add `.cer/` to `.gitignore`.
173
-
174
- ---
175
-
176
- ## Running the dev server
177
-
178
- ```sh
179
- # Using the CLI (reads cer.config.ts automatically)
180
- npx cer-app dev
181
-
182
- # Or via npm scripts (after scaffolding)
183
- npm run dev
184
- ```
185
-
186
- The dev server starts on `http://localhost:3000` by default.
187
-
188
- ---
189
-
190
- ## Building for production
191
-
192
- ```sh
193
- # SPA build
194
- npx cer-app build
195
-
196
- # SSR build (dual client + server bundles)
197
- npx cer-app build --mode ssr
198
-
199
- # SSG build (renders all routes to static HTML at build time)
200
- npx cer-app build --mode ssg
201
- # or equivalently:
202
- npx cer-app generate
203
- ```
204
-
205
- ### Build outputs
206
-
207
- | Mode | Output |
208
- |---|---|
209
- | `spa` | `dist/` — standard Vite client bundle |
210
- | `ssr` | `dist/client/` + `dist/server/server.js` |
211
- | `ssg` | `dist/<route>/index.html` per page + `dist/ssg-manifest.json` |
212
-
213
- ---
214
-
215
- ## Previewing the build
216
-
217
- ```sh
218
- # SPA / SSG (static file server)
219
- npx cer-app preview
220
-
221
- # SSR (loads dist/server/server.js as the request handler)
222
- npx cer-app preview --ssr
223
- ```
224
-
225
- Preview runs on `http://localhost:4173` by default.
226
-
227
- ---
228
-
229
- ## Scaffolded project scripts
230
-
231
- All three modes produce a `package.json` with these scripts:
232
-
233
- | Mode | `dev` | `build` | `preview` | `generate` |
234
- |---|---|---|---|---|
235
- | SPA | `cer-app dev` | `cer-app build` | `cer-app preview` | — |
236
- | SSR | `cer-app dev` | `cer-app build` | `cer-app preview --ssr` | — |
237
- | SSG | `cer-app dev` | `cer-app build` | `cer-app preview` | `cer-app generate` |