-
-
Notifications
You must be signed in to change notification settings - Fork 39
/
ssr.ts
64 lines (55 loc) 路 2.16 KB
/
ssr.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { isSSR, render } from './core.ts'
import { documentSSR } from './regexDom.ts'
import { _state } from './state.ts'
import { detectSSR } from './helpers.ts'
// functions that should only be available on the server-side
const ssrTricks = {
isWebComponent: (tagNameOrComponent: any) => {
return (
typeof tagNameOrComponent === 'string' &&
tagNameOrComponent.includes('-') &&
_nano.customElements.has(tagNameOrComponent)
)
},
renderWebComponent: (tagNameOrComponent: any, props: any, children: any, _render: any) => {
const customElement = _nano.customElements.get(tagNameOrComponent)
const component = _render({ component: customElement, props: { ...props, children: children } })
// get the html tag and the innerText from string
// match[1]: HTMLTag
// match[2]: innerText
const match = component.toString().match(/^<(?<tag>[a-z]+)>(.*)<\/\k<tag>>$/)
if (match) {
const element = document.createElement(match[1])
element.innerText = match[2]
// eslint-disable-next-line no-inner-declarations
function replacer(match: string, p1: string, _offset: number, _string: string): string {
return match.replace(p1, '')
}
// remove events like onClick from DOM
element.innerText = element.innerText.replace(/<\w+[^>]*(\s(on\w*)="[^"]*")/gm, replacer)
return element
} else {
return null
}
}
}
const initGlobalVar = () => {
const isSSR = detectSSR() === true ? true : undefined
const location = { pathname: '/' }
const document = isSSR ? documentSSR() : window.document
globalThis._nano = { isSSR, location, document, customElements: new Map(), ssrTricks }
}
initGlobalVar()
export const initSSR = (pathname: string = '/') => {
_nano.location = { pathname }
globalThis.document = _nano.document = isSSR() ? documentSSR() : window.document
}
export const renderSSR = (component: any, options: { pathname?: string; clearState?: boolean } = {}) => {
const { pathname, clearState = true } = options
initSSR(pathname)
if (clearState) _state.clear()
return render(component, null, true).join('') as string
}
export const clearState = () => {
_state.clear()
}