(() => { const APP_BLOCK = "app-block", APP_EMBED_BLOCK = "app-embed-block"; function querySelectHotReloadElements(handle) { // Gets all blocks (app and embed) with specified handle TODO: add app ID check here const blocks = Array.from( document.querySelectorAll(`[data-block-handle$='${handle}']`) ); if (blocks.length) { const queryString = "shopify-section-template"; const is_section = blocks[0].closest(`[id^=${queryString}]`) !== null; if (is_section) return [ blocks.map((block) => block.closest(`[id^=${queryString}]`)), APP_BLOCK, ]; return [blocks, APP_EMBED_BLOCK]; } return [[], null]; } function isRefreshRequired(files) { if (HotReload.isFullPageReloadMode()) { return true; } return files.some( (file) => !HotReload.isCSSFile(file) && !isBlockFile(file) ); } function refreshFile(file) { if (HotReload.isCSSFile(file)) { HotReload.reloadCssFile(file); return; } let block = new Block(file); // minimize DOM queries if (block.valid()) return block.refresh(); } function refreshPage(files) { HotReload.setHotReloadCookie(files); console.log("[HotReload] Refreshing entire page"); window.location.reload(); } function handleUpdate(data) { const modifiedFiles = data.modified; if (modifiedFiles === undefined) { return; } if (isRefreshRequired(modifiedFiles)) { refreshPage(modifiedFiles); } else { modifiedFiles.forEach(refreshFile); } } function isBlockFile(filename) { return new Block(filename).valid(); } class Block { constructor(filename) { this.filename = filename; this.name = filename.split("/").pop().replace(".liquid", ""); const [elements, type] = querySelectHotReloadElements(this.name); this.elements = elements; this.type = type; this.refreshElement = this.refreshElement.bind(this); this.refresh = this.refresh.bind(this); this.valid = this.valid.bind(this); } valid() { return this.filename.startsWith("blocks/") && this.elements.length > 0; } async refreshElement(element) { const url = new URL(window.location.href); let regex, key; if (this.type === APP_BLOCK) { regex = /^shopify-section-/; key = "section_id"; } else { regex = /^shopify-block-/; key = "app_block_id"; } const elementId = element.id.replace(regex, ""); url.searchParams.append(key, elementId); HotReload.setHotReloadCookie([this.filename]); const response = await fetch(url); try { element.outerHTML = await response.text(); } catch (e) { console.log( `[HotReload] Failed to reload ${this.name} ${this.type}: ${e.message}` ); } } async refresh() { console.log(`[HotReload] Reloaded ${this.name} ${this.type}s`); this.elements.forEach(this.refreshElement); } } if (HotReload.isReloadModeActive()) { let client = new SSEClient("/hot-reload", handleUpdate); client.connect(); } })();