|
|
|
|
|
import { createProxy, hasFatalError } from './proxy.js' |
|
|
|
const logPrefix = '[HMR:Svelte]' |
|
|
|
|
|
const log = (...args) => console.log(logPrefix, ...args) |
|
|
|
const domReload = () => { |
|
|
|
const win = typeof window !== 'undefined' && window |
|
if (win && win.location && win.location.reload) { |
|
log('Reload') |
|
win.location.reload() |
|
} else { |
|
log('Full reload required') |
|
} |
|
} |
|
|
|
const replaceCss = (previousId, newId) => { |
|
if (typeof document === 'undefined') return false |
|
if (!previousId) return false |
|
if (!newId) return false |
|
|
|
const previousClass = previousId.slice(0, -6) |
|
const newClass = newId.slice(0, -6) |
|
|
|
document.querySelectorAll('.' + previousClass).forEach(el => { |
|
el.classList.remove(previousClass) |
|
el.classList.add(newClass) |
|
}) |
|
return true |
|
} |
|
|
|
const removeStylesheet = cssId => { |
|
if (cssId == null) return |
|
if (typeof document === 'undefined') return |
|
|
|
const el = document.getElementById(cssId) |
|
if (el) el.remove() |
|
return |
|
} |
|
|
|
const defaultArgs = { |
|
reload: domReload, |
|
} |
|
|
|
export const makeApplyHmr = transformArgs => args => { |
|
const allArgs = transformArgs({ ...defaultArgs, ...args }) |
|
return applyHmr(allArgs) |
|
} |
|
|
|
let needsReload = false |
|
|
|
function applyHmr(args) { |
|
const { |
|
id, |
|
cssId, |
|
nonCssHash, |
|
reload = domReload, |
|
|
|
hot, |
|
hotOptions, |
|
Component, |
|
acceptable, |
|
preserveLocalState, |
|
ProxyAdapter, |
|
emitCss, |
|
} = args |
|
|
|
const existing = hot.data && hot.data.record |
|
|
|
const canAccept = acceptable && (!existing || existing.current.canAccept) |
|
|
|
const r = |
|
existing || |
|
createProxy({ |
|
Adapter: ProxyAdapter, |
|
id, |
|
Component, |
|
hotOptions, |
|
canAccept, |
|
preserveLocalState, |
|
}) |
|
|
|
const cssOnly = |
|
hotOptions.injectCss && |
|
existing && |
|
nonCssHash && |
|
existing.current.nonCssHash === nonCssHash |
|
|
|
r.update({ |
|
Component, |
|
hotOptions, |
|
canAccept, |
|
nonCssHash, |
|
cssId, |
|
previousCssId: r.current.cssId, |
|
cssOnly, |
|
preserveLocalState, |
|
}) |
|
|
|
hot.dispose(data => { |
|
|
|
if (needsReload || hasFatalError()) { |
|
if (hotOptions && hotOptions.noReload) { |
|
log('Full reload required') |
|
} else { |
|
reload() |
|
} |
|
} |
|
|
|
|
|
data = data || hot.data |
|
|
|
data.record = r |
|
|
|
if (!emitCss && cssId && r.current.cssId !== cssId) { |
|
if (hotOptions.cssEjectDelay) { |
|
setTimeout(() => removeStylesheet(cssId), hotOptions.cssEjectDelay) |
|
} else { |
|
removeStylesheet(cssId) |
|
} |
|
} |
|
}) |
|
|
|
if (canAccept) { |
|
hot.accept(async arg => { |
|
const { bubbled } = arg || {} |
|
|
|
|
|
|
|
const { cssId: newCssId, previousCssId } = r.current |
|
const cssChanged = newCssId !== previousCssId |
|
|
|
if (!emitCss && cssChanged) removeStylesheet(previousCssId) |
|
|
|
if ( |
|
|
|
|
|
|
|
bubbled === false && |
|
r.current.cssOnly && |
|
(!cssChanged || replaceCss(previousCssId, newCssId)) |
|
) { |
|
return |
|
} |
|
|
|
const success = await r.reload() |
|
|
|
if (hasFatalError() || (!success && !hotOptions.optimistic)) { |
|
needsReload = true |
|
} |
|
}) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const proxyOk = r && r.proxy |
|
if (!proxyOk) { |
|
throw new Error(`Failed to create HMR proxy for Svelte component ${id}`) |
|
} |
|
|
|
return r.proxy |
|
} |
|
|