Created
June 20, 2021 09:41
-
-
Save hmmhmmhm/6a2aa63daf3524c680169890aad7d1fb to your computer and use it in GitHub Desktop.
JSDOM CSR 렌더링 예시
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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