Spaces:
Runtime error
Runtime error
/* eslint-env browser */ | |
import { createProxy, hasFatalError } from './proxy.js' | |
const logPrefix = '[HMR:Svelte]' | |
// eslint-disable-next-line no-console | |
const log = (...args) => console.log(logPrefix, ...args) | |
const domReload = () => { | |
// eslint-disable-next-line no-undef | |
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 | |
// svelte-xxx-style => svelte-xxx | |
const previousClass = previousId.slice(0, -6) | |
const newClass = newId.slice(0, -6) | |
// eslint-disable-next-line no-undef | |
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 | |
// eslint-disable-next-line no-undef | |
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, | |
// normalized hot API (must conform to rollup-plugin-hot) | |
hot, | |
hotOptions, | |
Component, | |
acceptable, // some types of components are impossible to HMR correctly | |
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 => { | |
// handle previous fatal errors | |
if (needsReload || hasFatalError()) { | |
if (hotOptions && hotOptions.noReload) { | |
log('Full reload required') | |
} else { | |
reload() | |
} | |
} | |
// 2020-09-21 Snowpack master doesn't pass data as arg to dispose handler | |
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 || {} | |
// NOTE Snowpack registers accept handlers only once, so we can NOT rely | |
// on the surrounding scope variables -- they're not the last version! | |
const { cssId: newCssId, previousCssId } = r.current | |
const cssChanged = newCssId !== previousCssId | |
// ensure old style sheet has been removed by now | |
if (!emitCss && cssChanged) removeStylesheet(previousCssId) | |
// guard: css only change | |
if ( | |
// NOTE bubbled is provided only by rollup-plugin-hot, and we | |
// can't safely assume a CSS only change without it... this means we | |
// can't support CSS only injection with Nollup or Webpack currently | |
bubbled === false && // WARNING check false, not falsy! | |
r.current.cssOnly && | |
(!cssChanged || replaceCss(previousCssId, newCssId)) | |
) { | |
return | |
} | |
const success = await r.reload() | |
if (hasFatalError() || (!success && !hotOptions.optimistic)) { | |
needsReload = true | |
} | |
}) | |
} | |
// well, endgame... we won't be able to render next updates, even successful, | |
// if we don't have proxies in svelte's tree | |
// | |
// since we won't return the proxy and the app will expect a svelte component, | |
// it's gonna crash... so it's best to report the real cause | |
// | |
// full reload required | |
// | |
const proxyOk = r && r.proxy | |
if (!proxyOk) { | |
throw new Error(`Failed to create HMR proxy for Svelte component ${id}`) | |
} | |
return r.proxy | |
} | |