Skip to content

Instantly share code, notes, and snippets.

@hmmhmmhm
Created June 20, 2021 09:41
Show Gist options
  • Select an option

  • Save hmmhmmhm/6a2aa63daf3524c680169890aad7d1fb to your computer and use it in GitHub Desktop.

Select an option

Save hmmhmmhm/6a2aa63daf3524c680169890aad7d1fb to your computer and use it in GitHub Desktop.
JSDOM CSR 렌더링 예시
import 'isomorphic-unfetch'
import axios from 'redaxios'
import { JSDOM, CookieJar, VirtualConsole, ResourceLoader } from 'jsdom'
interface JSDOMCookie {
key: string
value: string
domain: string
path: string
hostOnly: boolean
pathIsDefault: boolean
creation: string
lastAccessed: string
}
const renderCSR = async (
url: string,
cookie?: JSDOMCookie[],
option = {
timeout: 1000,
}
) => {
return new Promise<{
html: string
cookies: JSDOMCookie[]
}>(async (resolve, reject) => {
const userAgent =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
const virtualConsole = new VirtualConsole()
const cookieJar = cookie
? (CookieJar.fromJSON as any)({
storeType: 'MemoryCookieStore',
rejectPublicSuffixes: false,
cookies: [],
})
: new CookieJar()
let onIdle
let isPromiseDone = false
let requestHandler: NodeJS.Timeout | null = null
let fetchCount = 0
const resources: ResourceLoader & { _fetch } = new ResourceLoader() as any
resources._fetch = resources.fetch
resources.fetch = (url, options) => {
fetchCount++
const result = resources._fetch(url, options)!
result.then(() => {
if (!isPromiseDone && --fetchCount === 0) {
if (requestHandler) clearTimeout(requestHandler)
requestHandler = setTimeout(() => {
if (typeof onIdle === 'function') onIdle()
isPromiseDone = true
requestHandler = null
}, option.timeout)
}
})
return result
}
try {
const { data: plainHtml } = await axios.get<string>(url)
const { window } = new JSDOM(plainHtml, {
url,
resources,
runScripts: 'dangerously',
userAgent,
cookieJar,
virtualConsole,
beforeParse: (window: any) => {
const noop = () => {}
window.alert = noop
window.matchMedia = noop
window.scrollTo = noop
window.PerformanceObserver = noop
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query) => ({
matches: false,
media: query,
onchange: null,
addListener: noop,
removeListener: noop,
addEventListener: noop,
removeEventListener: noop,
dispatchEvent: noop,
}),
})
},
})
const finish = () => {
const html = window.document.body.innerHTML
const cookies = cookieJar.toJSON().cookies
window.close()
resolve({
html,
cookies,
})
}
window.addEventListener('load', () => {
const isFinishable = fetchCount === 0 && requestHandler === null
if (isFinishable) {
finish()
} else {
onIdle = finish
}
})
} catch (e) {
reject(e)
}
})
}
const main = async () => {
const { html, cookies } = await renderCSR('https://google.com')
console.log(html.length)
console.log(cookies)
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment