/* global window, document */ import * as svelteInternal from 'svelte/internal' // NOTE from 3.38.3 (or so), insert was carrying the hydration logic, that must // be used because DOM elements are reused more (and so insertion points are not // necessarily added in order); then in 3.40 the logic was moved to // insert_hydration, which is the one we must use for HMR const svelteInsert = svelteInternal.insert_hydration || svelteInternal.insert if (!svelteInsert) { throw new Error( 'failed to find insert_hydration and insert in svelte/internal' ) } import ErrorOverlay from './overlay.js' const removeElement = el => el && el.parentNode && el.parentNode.removeChild(el) export const adapter = class ProxyAdapterDom { constructor(instance) { this.instance = instance this.insertionPoint = null this.afterMount = this.afterMount.bind(this) this.rerender = this.rerender.bind(this) this._noOverlay = !!instance.hotOptions.noOverlay } // NOTE overlay is only created before being actually shown to help test // runner (it won't have to account for error overlay when running assertions // about the contents of the rendered page) static getErrorOverlay(noCreate = false) { if (!noCreate && !this.errorOverlay) { this.errorOverlay = ErrorOverlay() } return this.errorOverlay } // TODO this is probably unused now: remove in next breaking release static renderCompileError(message) { const noCreate = !message const overlay = this.getErrorOverlay(noCreate) if (!overlay) return overlay.setCompileError(message) } dispose() { // Component is being destroyed, detaching is not optional in Svelte3's // component API, so we can dispose of the insertion point in every case. if (this.insertionPoint) { removeElement(this.insertionPoint) this.insertionPoint = null } this.clearError() } // NOTE afterMount CAN be called multiple times (e.g. keyed list) afterMount(target, anchor) { const { instance: { debugName }, } = this if (!this.insertionPoint) { this.insertionPoint = document.createComment(debugName) } svelteInsert(target, this.insertionPoint, anchor) } rerender() { this.clearError() const { instance: { refreshComponent }, insertionPoint, } = this if (!insertionPoint) { throw new Error('Cannot rerender: missing insertion point') } refreshComponent(insertionPoint.parentNode, insertionPoint) } renderError(err) { if (this._noOverlay) return const { instance: { debugName }, } = this const title = debugName || err.moduleName || 'Error' this.constructor.getErrorOverlay().addError(err, title) } clearError() { if (this._noOverlay) return const overlay = this.constructor.getErrorOverlay(true) if (!overlay) return overlay.clearErrors() } } // TODO this is probably unused now: remove in next breaking release if (typeof window !== 'undefined') { window.__SVELTE_HMR_ADAPTER = adapter } // mitigate situation with Snowpack remote source pulling latest of runtime, // but using previous version of the Node code transform in the plugin // see: https://github.com/rixo/svelte-hmr/issues/27 export default adapter