create-fullstack-scaffold 0.5.3 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fullstack-scaffold",
3
- "version": "0.5.3",
3
+ "version": "0.5.6",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-fullstack-scaffold": "dist/cli/index.js"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "biomimic-todo-app",
3
3
  "private": true,
4
- "version": "0.5.3",
4
+ "version": "0.5.6",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "biomimic": "./dist/cli/index.js"
@@ -17,7 +17,23 @@ import { logger } from '../utils/logger'
17
17
  import { createApp } from '../app'
18
18
  import { getDb, runMigrations } from '../db'
19
19
  import { createISRCache, isISRRoute } from '@server/core/isr-cache'
20
- import { renderPage } from '@server/core/ssr-renderer'
20
+ import { renderISRPage } from '@server/core/isr-renderer'
21
+ // @client/entry-server 仅含 client 的 preset 存在;cli-only 会因静态
22
+ // 导入悬空(verify 链已拦过一次)。运行时按需加载,缺省回退壳渲染。
23
+ type RenderSSRFn = (pathname: string, data: never) => { html: string }
24
+
25
+ async function loadRenderSSR(): Promise<RenderSSRFn | null> {
26
+ try {
27
+ // 变量说明符:tsc 不做模块解析(cli-only 无 client 目录时字面量
28
+ // 动态导入也会被 tsc 拦——与 vitest.config 的 react 插件同法)
29
+ const mod = '@client/entry-server'
30
+ const m = (await import(/* @vite-ignore */ mod)) as { renderSSR: RenderSSRFn }
31
+ return m.renderSSR
32
+ } catch {
33
+ return null
34
+ }
35
+ }
36
+ import { isrRegistry, type ISRRouterContext } from '@server/core/isr-registry'
21
37
  import { setISRCache } from '@server/core/isr-invalidation'
22
38
  import { setRuntimeAdapter } from '@server/core/runtime'
23
39
  import { getNodeRuntimeAdapter } from '@server/core/runtime-node'
@@ -130,11 +146,13 @@ app.get('*', async c => {
130
146
  }
131
147
 
132
148
  if (result.status === 'stale' && result.html) {
133
- renderPage(pathname)
134
- .then(rendered => {
135
- isrCache.store(pathname, rendered.html).catch(e => {
136
- console.warn('ISR cache store (background revalidation) failed:', e)
137
- })
149
+ renderISRForRoute(pathname)
150
+ .then(html => {
151
+ if (html) {
152
+ isrCache.store(pathname, html).catch(e => {
153
+ console.warn('ISR cache store (background revalidation) failed:', e)
154
+ })
155
+ }
138
156
  })
139
157
  .catch(e => {
140
158
  console.warn('ISR background render failed:', e)
@@ -142,11 +160,14 @@ app.get('*', async c => {
142
160
  return c.html(result.html)
143
161
  }
144
162
 
145
- const rendered = await renderPage(pathname)
146
- isrCache.store(pathname, rendered.html).catch(e => {
147
- console.warn('ISR cache store failed:', e)
148
- })
149
- return c.html(rendered.html)
163
+ const html = await renderISRForRoute(pathname)
164
+ if (html) {
165
+ isrCache.store(pathname, html).catch(e => {
166
+ console.warn('ISR cache store failed:', e)
167
+ })
168
+ return c.html(html)
169
+ }
170
+ return c.html(indexHtml)
150
171
  }
151
172
 
152
173
  return c.html(indexHtml)
@@ -191,6 +212,34 @@ export async function createServer() {
191
212
  return { server, port: config.port }
192
213
  }
193
214
 
215
+ /**
216
+ * 真 ISR 渲染(与 CF 入口同管线):registry fetch 数据 → renderSSR
217
+ * 页面级渲染 → renderISRPage 注入 body + meta + __SSR_DATA__。
218
+ * 返回 null 表示无注册路由/渲染失败,调用方回退 SPA index.html。
219
+ */
220
+ async function renderISRForRoute(pathname: string): Promise<string | null> {
221
+ const entry = isrRegistry.match(pathname)
222
+ if (!entry) return null
223
+ const ctx: ISRRouterContext = { db: await getDb(), env: {} }
224
+ let data: unknown = {}
225
+ let meta = { title: 'App', description: '' }
226
+ try {
227
+ data = await entry.fetch(pathname, ctx)
228
+ meta = entry.meta(data, pathname)
229
+ } catch {
230
+ // DB 错误——回退默认 meta 继续渲染壳
231
+ }
232
+ const renderSSR = await loadRenderSSR()
233
+ if (!renderSSR) return null // 无 client(cli-only 等)——调用方回退 SPA
234
+ try {
235
+ const ssr = renderSSR(pathname, data as never)
236
+ return renderISRPage({ template: indexHtml, body: ssr.html, meta, data })
237
+ } catch (e) {
238
+ console.warn('ISR render failed:', e)
239
+ return null
240
+ }
241
+ }
242
+
194
243
  export async function startServer() {
195
244
  const bootstrapLog = logger.bootstrap()
196
245