import { getEventSourceWrapper } from './error-overlay/eventsource' export default function initializeBuildWatcher(toggleCallback) { const shadowHost = document.createElement('div') shadowHost.id = '__next-build-watcher' // Make sure container is fixed and on a high zIndex so it shows shadowHost.style.position = 'fixed' shadowHost.style.bottom = '10px' shadowHost.style.right = '20px' shadowHost.style.width = 0 shadowHost.style.height = 0 shadowHost.style.zIndex = 99999 document.body.appendChild(shadowHost) let shadowRoot let prefix = '' if (shadowHost.attachShadow) { shadowRoot = shadowHost.attachShadow({ mode: 'open' }) } else { // If attachShadow is undefined then the browser does not support // the Shadow DOM, we need to prefix all the names so there // will be no conflicts shadowRoot = shadowHost prefix = '__next-build-watcher-' } // Container const container = createContainer(prefix) shadowRoot.appendChild(container) // CSS const css = createCss(prefix) shadowRoot.appendChild(css) // State let isVisible = false let isBuilding = false let timeoutId = null // Handle events const evtSource = getEventSourceWrapper({ path: '/_next/webpack-hmr' }) evtSource.addMessageListener((event) => { // This is the heartbeat event if (event.data === '\uD83D\uDC93') { return } try { handleMessage(event) } catch {} }) function handleMessage(event) { const obj = typeof event === 'string' ? { action: event } : JSON.parse(event.data) // eslint-disable-next-line default-case switch (obj.action) { case 'building': timeoutId && clearTimeout(timeoutId) isVisible = true isBuilding = true updateContainer() break case 'built': case 'sync': isBuilding = false // Wait for the fade out transtion to complete timeoutId = setTimeout(() => { isVisible = false updateContainer() }, 100) updateContainer() break } } toggleCallback(handleMessage) function updateContainer() { if (isBuilding) { container.classList.add(`${prefix}building`) } else { container.classList.remove(`${prefix}building`) } if (isVisible) { container.classList.add(`${prefix}visible`) } else { container.classList.remove(`${prefix}visible`) } } } function createContainer(prefix) { const container = document.createElement('div') container.id = `${prefix}container` container.innerHTML = `