Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimize(cli): should cleanup global pollution after render #261

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/real-badgers-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@pintora/cli': patch
---

should cleanup global pollution after render
14 changes: 14 additions & 0 deletions packages/pintora-cli/src/__tests__/render.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,18 @@ describe('render', () => {
expect(config.themeConfig.theme).toBe(oldTheme)
expect(config.core.useMaxWidth).toBe(oldUseMaxWidth)
})

it('should cleanup global pollution after render', async () => {
const fakeDom = {}
;(globalThis as any).document = fakeDom

await render({
code: EXAMPLES.er.code,
mimeType: SVG_MIME_TYPE,
})
expect(global.window).toBeUndefined()
expect((globalThis as any).document).toBe(fakeDom) // should not mess with existing globals

delete (globalThis as any).document
})
})
51 changes: 43 additions & 8 deletions packages/pintora-cli/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,31 @@ export type CLIRenderOptions = {
width?: number
}

/**
* records how many globals we have patched,
* need to restore them later to prevent polluting the global environment
*/
class GlobalPatcher {
private records: any = {}
set<K extends keyof typeof globalThis>(k: K, v: any) {
const prevValue = globalThis[k]
this.records[k] = {
prevValue,
value: v,
}

globalThis[k] = v
}

restore() {
for (const k in this.records) {
if ((globalThis as any)[k] === this.records[k].value) {
;(globalThis as any)[k] = this.records[k].prevValue
}
}
}
}

function renderPrepare(opts: CLIRenderOptions) {
const { code, backgroundColor, pintoraConfig } = opts
const devicePixelRatio = opts.devicePixelRatio || 2
Expand All @@ -33,10 +58,11 @@ function renderPrepare(opts: CLIRenderOptions) {
container.id = 'pintora-container'

// setup the env for renderer
global.window = dom.window as any
global.document = document
const patcher = new GlobalPatcher()
patcher.set('window', dom.window)
patcher.set('document', document)
patcher.set('CanvasPattern', CanvasPattern)
;(dom.window as any).devicePixelRatio = devicePixelRatio
;(global as any).CanvasPattern = CanvasPattern

return {
container,
Expand All @@ -51,7 +77,7 @@ function renderPrepare(opts: CLIRenderOptions) {
config = pintoraStandalone.configApi.gnernateNewConfig({ core: { useMaxWidth: true } })
}

return new Promise<IRenderer>((resolve, reject) => {
return new Promise<{ renderer: IRenderer; cleanup(): void }>((resolve, reject) => {
pintoraStandalone.renderTo(code, {
container,
renderer: renderOpts.renderer || 'canvas',
Expand All @@ -69,10 +95,16 @@ function renderPrepare(opts: CLIRenderOptions) {
return ir
},
onRender(renderer) {
resolve(renderer)
resolve({
renderer,
cleanup() {
patcher.restore()
},
})
},
onError(e) {
console.error('onError', e)
patcher.restore()
reject(e)
},
})
Expand All @@ -96,10 +128,12 @@ export function render(opts: CLIRenderOptions) {
function renderToSvg() {
return new Promise<string>((resolve, reject) => {
pintorRender({ renderer: 'svg' })
.then(renderer => {
.then(({ renderer, cleanup }) => {
const rootElement = renderer.getRootElement() as SVGSVGElement
rootElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
resolve(rootElement.outerHTML)
const html = rootElement.outerHTML
cleanup()
resolve(html)
})
.catch(reject)
})
Expand All @@ -109,9 +143,10 @@ export function render(opts: CLIRenderOptions) {
function renderToImageBuffer() {
return new Promise<Buffer>((resolve, reject) => {
pintorRender({ renderer: 'canvas' })
.then(renderer => {
.then(({ renderer, cleanup }) => {
setTimeout(() => {
const buf = getBuf(renderer.getRootElement() as HTMLCanvasElement)
cleanup()
resolve(buf)
}, 20)
})
Expand Down
Loading