Skip to content

Commit

Permalink
feat: auto-unmount prod version when dev version is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
EnixCoda committed Jan 30, 2025
1 parent 0c9acf7 commit dfc6311
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 14 deletions.
54 changes: 40 additions & 14 deletions src/content.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,66 @@
import { Gitako } from 'components/Gitako'
import { IN_PRODUCTION_MODE } from 'env'
import React, { useCallback } from 'react'
import { createRoot } from 'react-dom/client'
import { insertMountPoint, insertSideBarMountPoint } from 'utils/DOMHelper'
import { useAfterRedirect } from 'utils/hooks/useFastRedirect'
import { waitForNext } from 'utils/waitForNextEvent'
import './content.scss'

if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init)
} else {
init()
}

async function init() {
await injectStyles(browser.runtime.getURL('content.css'))
const renderReact = () => {
const mountPoint = insertSideBarMountPoint()
const MountPointWatcher = () => {
useAfterRedirect(useCallback(() => insertMountPoint(() => mountPoint), []))
return null
}

createRoot(mountPoint).render(
const root = createRoot(mountPoint)
root.render(
<>
<MountPointWatcher />
<Gitako />
</>,
)

return () => {
root.unmount()
}
}

// injects a copy of stylesheets so that other extensions(e.g. dark reader) could read
// resolves when style is loaded to prevent render without proper styles
async function injectStyles(url: string) {
return new Promise<void>(resolve => {
const injectStyles = (url: string) =>
new Promise<() => void>(resolve => {
const linkElement = document.createElement('link')
linkElement.setAttribute('rel', 'stylesheet')
linkElement.setAttribute('href', url)
linkElement.onload = () => resolve()
const unload = () => {
linkElement.remove()
}
linkElement.onload = () => resolve(unload)
document.head.appendChild(linkElement)
})
}

const GitakoExclusiveEventType = 'GITAKO_EXCLUSIVE_EVENT'
const GitakoMountedEventType = 'GITAKO_MOUNTED_EVENT'

Promise.resolve()
.then(() =>
document.readyState === 'loading' ? waitForNext.documentEvent('DOMContentLoaded') : null,
)
.then(() =>
Promise.all([injectStyles(browser.runtime.getURL('content.css')), renderReact()]).then(
([unmountStyles, unmountReact]) =>
() =>
Promise.all([unmountStyles(), unmountReact()]),
),
)
.then(unmount => {
document.dispatchEvent(new CustomEvent(GitakoMountedEventType))
if (IN_PRODUCTION_MODE) {
waitForNext.documentEvent(GitakoExclusiveEventType).then(unmount)
} else {
waitForNext
.documentEvent(GitakoMountedEventType)
.then(() => document.dispatchEvent(new CustomEvent(GitakoExclusiveEventType)))
}
})
28 changes: 28 additions & 0 deletions src/utils/waitForNextEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const waitForNextDocumentEvent = <K extends keyof DocumentEventMap>(
type: EnumString<K>,
options?: boolean | AddEventListenerOptions,
) =>
new Promise(resolve => {
const listener = (ev: DocumentEventMap[K] | Event) => {
document.removeEventListener(type, listener, options)
resolve(ev)
}
document.addEventListener(type, listener, options)
})

export const waitForNextWindowEvent = <K extends keyof WindowEventMap>(
type: EnumString<K>,
options?: boolean | AddEventListenerOptions,
) =>
new Promise(resolve => {
const listener = (ev: WindowEventMap[K] | Event) => {
window.removeEventListener(type, listener, options)
resolve(ev)
}
window.addEventListener(type, listener, options)
})

export const waitForNext = {
documentEvent: waitForNextDocumentEvent,
windowEvent: waitForNextWindowEvent,
}

0 comments on commit dfc6311

Please sign in to comment.