Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 263d685

Browse files
author
Je
committed
fix: fix SSR interference
1 parent 3e16865 commit 263d685

File tree

4 files changed

+173
-113
lines changed

4 files changed

+173
-113
lines changed

context.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,15 @@ export const RouterContext = createContext<RouterURL>({
99
query: new URLSearchParams(),
1010
})
1111
RouterContext.displayName = 'RouterContext'
12+
13+
interface RendererCache {
14+
headElements: Map<string, { type: string, props: Record<string, any> }>
15+
scriptsElements: Map<string, { type: string, props: Record<string, any> }>
16+
}
17+
18+
export const RendererContext = createContext<{ cache: RendererCache }>({
19+
cache: {
20+
headElements: new Map(),
21+
scriptsElements: new Map()
22+
}
23+
})

head.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import React, { Children, createElement, isValidElement, PropsWithChildren, ReactElement, ReactNode, useEffect } from 'https://esm.sh/react'
1+
import React, { Children, createElement, isValidElement, PropsWithChildren, ReactElement, ReactNode, useContext, useEffect } from 'https://esm.sh/react'
2+
import { RendererContext } from './context.ts'
23
import util from './util.ts'
34

4-
export const serverHeadElements: Map<string, { type: string, props: Record<string, any> }> = new Map()
5-
export const serverScriptsElements: Map<string, { type: string, props: Record<string, any> }> = new Map()
65
export const serverStyles: Map<string, { css: string, asLink: boolean }> = new Map()
76

87
export default function Head(props: PropsWithChildren<{}>) {
8+
const renderer = useContext(RendererContext)
9+
910
if (window.Deno) {
10-
parse(props.children).forEach(({ type, props }, key) => serverHeadElements.set(key, { type, props }))
11+
parse(props.children).forEach(({ type, props }, key) => renderer.cache.headElements.set(key, { type, props }))
1112
}
1213

1314
useEffect(() => {
@@ -59,10 +60,12 @@ export default function Head(props: PropsWithChildren<{}>) {
5960
}
6061

6162
export function Scripts(props: PropsWithChildren<{}>) {
63+
const renderer = useContext(RendererContext)
64+
6265
if (window.Deno) {
6366
parse(props.children).forEach(({ type, props }, key) => {
6467
if (type === 'script') {
65-
serverScriptsElements.set(key, { type, props })
68+
renderer.cache.scriptsElements.set(key, { type, props })
6669
}
6770
})
6871
}

project.ts

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,6 @@ interface Dep {
3737
external?: boolean
3838
}
3939

40-
interface Renderer {
41-
renderPage: Function
42-
renderHead: Function
43-
renderScripts: Function
44-
}
45-
4640
interface RenderResult {
4741
url: RouterURL
4842
status: number
@@ -54,10 +48,11 @@ interface RenderResult {
5448

5549
/**
5650
* A Project to manage the Aleph.js appliaction.
57-
* features include:
58-
* - compile source codes
51+
* core functions include:
52+
* - compile source code
5953
* - manage deps
6054
* - apply plugins
55+
* - map page/API routes
6156
* - watch file changes
6257
* - call APIs
6358
* - SSR/SSG
@@ -73,7 +68,7 @@ export class Project {
7368
#routing: Routing = new Routing()
7469
#apiRouting: Routing = new Routing()
7570
#fsWatchListeners: Array<EventEmitter> = []
76-
#renderer: Renderer = { renderPage: () => void 0, renderHead: () => void 0, renderScripts: () => void 0 }
71+
#renderer: { renderPage: CallableFunction } = { renderPage: () => void 0 }
7772
#rendered: Map<string, Map<string, RenderResult>> = new Map()
7873
#postcssPlugins: Record<string, AcceptedPlugin> = {}
7974

@@ -296,7 +291,6 @@ export class Project {
296291
const html = createHtml({
297292
lang: defaultLocale,
298293
scripts: [
299-
customLoading?.data ? { type: 'application/json', innerText: JSON.stringify(customLoading?.data), id: 'ssr-data' } : '',
300294
{ src: util.cleanPath(`${baseUrl}/_aleph/main.${mainModule.hash.slice(0, hashShort)}.js`), type: 'module' },
301295
{ src: util.cleanPath(`${baseUrl}/_aleph/-/deno.land/x/aleph/nomodule.js${this.isDev ? '?dev' : ''}`), nomodule: true },
302296
],
@@ -635,8 +629,8 @@ export class Project {
635629
await this._compile('https://deno.land/x/aleph/renderer.ts', { forceTarget: 'es2020' })
636630
await this._createMainModule()
637631

638-
const { renderPage, renderHead, renderScripts } = await import('file://' + this.#modules.get('//deno.land/x/aleph/renderer.js')!.jsFile)
639-
this.#renderer = { renderPage, renderHead, renderScripts }
632+
const { renderPage } = await import('file://' + this.#modules.get('//deno.land/x/aleph/renderer.js')!.jsFile)
633+
this.#renderer = { renderPage }
640634

641635
log.info(colors.bold(`Aleph.js v${version}`))
642636
if (this.config.__file) {
@@ -1322,19 +1316,29 @@ export class Project {
13221316
}
13231317
})
13241318
await Promise.all(imports)
1325-
const [html, data] = await this.#renderer.renderPage(url, App, undefined, pageComponentTree)
1326-
const head = await this.#renderer.renderHead([
1327-
appModule ? this._lookupDeps(appModule.id).filter(dep => !!dep.isStyle) : [],
1328-
...pageModuleTree.map(({ id }) => this._lookupDeps(id).filter(dep => !!dep.isStyle)).flat()
1329-
].flat())
1319+
const {
1320+
head,
1321+
body,
1322+
data,
1323+
scripts
1324+
} = await this.#renderer.renderPage(
1325+
url,
1326+
App,
1327+
undefined,
1328+
pageComponentTree,
1329+
[
1330+
appModule ? this._lookupDeps(appModule.id).filter(dep => !!dep.isStyle) : [],
1331+
...pageModuleTree.map(({ id }) => this._lookupDeps(id).filter(dep => !!dep.isStyle)).flat()
1332+
].flat()
1333+
)
13301334
ret.head = head
1331-
ret.scripts = await Promise.all(this.#renderer.renderScripts().map(async (script: Record<string, any>) => {
1332-
if (!this.isDev && script.innerText) {
1335+
ret.scripts = await Promise.all(scripts.map(async (script: Record<string, any>) => {
1336+
if (script.innerText && !this.isDev) {
13331337
return { ...script, innerText: (await minify(script.innerText)).code }
13341338
}
13351339
return script
13361340
}))
1337-
ret.body = `<main>${html}</main>`
1341+
ret.body = `<main>${body}</main>`
13381342
ret.data = data
13391343
this.#rendered.get(url.pagePath)!.set(key, ret)
13401344
if (this.isDev) {
@@ -1354,18 +1358,28 @@ export class Project {
13541358
try {
13551359
const e404Module = this.#modules.get('/404.js')
13561360
const { default: E404 } = e404Module ? await import('file://' + e404Module.jsFile) : {} as any
1357-
const [html, data] = await this.#renderer.renderPage(url, undefined, E404, [])
1358-
const head = await this.#renderer.renderHead([
1359-
e404Module ? this._lookupDeps(e404Module.id).filter(dep => !!dep.isStyle) : []
1360-
].flat())
1361+
const {
1362+
head,
1363+
body,
1364+
data,
1365+
scripts
1366+
} = await this.#renderer.renderPage(
1367+
url,
1368+
undefined,
1369+
E404,
1370+
[],
1371+
[
1372+
e404Module ? this._lookupDeps(e404Module.id).filter(dep => !!dep.isStyle) : []
1373+
].flat()
1374+
)
13611375
ret.head = head
1362-
ret.scripts = await Promise.all(this.#renderer.renderScripts().map(async (script: Record<string, any>) => {
1363-
if (!this.isDev && script.innerText) {
1376+
ret.scripts = await Promise.all(scripts.map(async (script: Record<string, any>) => {
1377+
if (script.innerText && !this.isDev) {
13641378
return { ...script, innerText: (await minify(script.innerText)).code }
13651379
}
13661380
return script
13671381
}))
1368-
ret.body = `<main>${html}</main>`
1382+
ret.body = `<main>${body}</main>`
13691383
ret.data = data
13701384
} catch (err) {
13711385
ret.status = 500
@@ -1381,15 +1395,24 @@ export class Project {
13811395
const loadingModule = this.#modules.get('/loading.js')!
13821396
const { default: Loading } = await import('file://' + loadingModule.jsFile)
13831397
const url = { locale: this.config.defaultLocale, pagePath: '', pathname: '/', params: {}, query: new URLSearchParams() }
1384-
const [html, data] = await this.#renderer.renderPage(url, undefined, undefined, [{ id: '/loading.js', Component: Loading }])
1385-
const head = await this.#renderer.renderHead([
1386-
this._lookupDeps(loadingModule.id).filter(dep => !!dep.isStyle)
1387-
].flat())
1398+
1399+
const {
1400+
head,
1401+
body,
1402+
data
1403+
} = await this.#renderer.renderPage(
1404+
url,
1405+
undefined,
1406+
undefined,
1407+
[{ id: '/loading.js', Component: Loading }],
1408+
[
1409+
this._lookupDeps(loadingModule.id).filter(dep => !!dep.isStyle)
1410+
].flat()
1411+
)
13881412
return {
13891413
head,
1390-
body: html,
1391-
data,
1392-
} as RenderResult
1414+
body: `<main>${body}</main>`
1415+
} as Pick<RenderResult, 'head' | 'body'>
13931416
}
13941417
return null
13951418
}

0 commit comments

Comments
 (0)