const globalName = '___SVELTE_HMR_HOT_API'
const globalAdapterName = '___SVELTE_HMR_HOT_API_PROXY_ADAPTER'
const defaultHotOptions = {
// preserve all local state
preserveLocalState: false,
// escape hatchs from preservation of local state
//
// disable preservation of state for this component
noPreserveStateKey: ['@hmr:reset', '@!hmr'],
// enable preservation of state for all variables in this component
preserveAllLocalStateKey: '@hmr:keep-all',
// enable preservation of state for a given variable (must be inline or
// above the target variable or variables; can be repeated)
preserveLocalStateKey: '@hmr:keep',
// don't reload on fatal error
noReload: false,
// try to recover after runtime errors during component init
// defaults to false because some runtime errors are fatal and require a full reload
optimistic: false,
// auto accept modules of components that have named exports (i.e. exports
// from context="module")
acceptNamedExports: true,
// auto accept modules of components have accessors (either accessors compile
// option, or ) -- this means that if you
// set accessors compile option globally, you must also set this option to
// true, or no component will be hot reloaded (but there are a lot of edge
// cases that HMR can't support correctly with accessors)
acceptAccessors: true,
// only inject CSS instead of recreating components when only CSS changes
injectCss: false,
// to mitigate FOUC between dispose (remove stylesheet) and accept
cssEjectDelay: 100,
// Svelte Native mode
native: false,
// name of the adapter import binding
importAdapterName: globalAdapterName,
// disable runtime error overlay
noOverlay: false,
// set to true on systems that supports them, to avoid useless caught /
// managed (but still...) exceptions, by using Svelte's current_component
// instead of get_current_component
allowLiveBinding: false,
// use acceptExports instead of accept, to fix support of context:module
partialAccept: false,
}
const defaultHotApi = 'hot-api-esm.js'
const json = JSON.stringify
const posixify = file => file.replace(/[/\\]/g, '/')
const renderApplyHmr = ({
id,
cssId,
nonCssHash,
hotOptions: {
injectCss,
partialAccept,
_accept = partialAccept ? "acceptExports(['default'])" : 'accept()',
},
hotOptionsJson,
hotApiImport,
adapterImport,
importAdapterName,
meta,
acceptable,
preserveLocalState,
emitCss,
imports = [
`import * as ${globalName} from ${JSON.stringify(hotApiImport)}`,
`import { adapter as ${importAdapterName} } from ${JSON.stringify(adapterImport)}`,
],
}) =>
// this silly formatting keeps all original characters in their position,
// thus saving us from having to provide a sourcemap
//
// NOTE the `if (false) accept()` line is for tools that wants to see the
// accept call in the actual accepted module to enable HMR (Vite and, I
// believe, Snowpack 3)
//
`${imports.join(';')};${`
if (${meta} && ${meta}.hot) {
${acceptable ? `if (false) ${meta}.hot.${_accept};` : ''};
$2 = ${globalName}.applyHmr({
m: ${meta},
id: ${json(id)},
hotOptions: ${hotOptionsJson},
Component: $2,
ProxyAdapter: ${importAdapterName},
acceptable: ${json(acceptable)},
preserveLocalState: ${json(preserveLocalState)},
${cssId ? `cssId: ${json(cssId)},` : ''}
${nonCssHash ? `nonCssHash: ${json(nonCssHash)},` : ''}
emitCss: ${json(emitCss)},
});
}
`
.split('\n')
.map(x => x.trim())
.filter(Boolean)
.join(' ')}
export default $2;
${
// NOTE when doing CSS only voodoo, we have to inject the stylesheet as soon
// as the component is loaded because Svelte normally do that when a component
// is instantiated, but we might already have instances in the large when a
// component is loaded with HMR
cssId && injectCss && !emitCss
? `
if (typeof add_css !== 'undefined' && !document.getElementById(${json(
cssId
)})) add_css();`
: ``
}
`
// replace from last occurrence of the splitter
const replaceLast = (string, splitter, regex, replacer) => {
const lastIndex = string.lastIndexOf(splitter)
return (
string.slice(0, lastIndex) +
string.slice(lastIndex).replace(regex, replacer)
)
}
// https://github.com/darkskyapp/string-hash/blob/master/index.js
// (via https://github.com/sveltejs/svelte/blob/91d758e35b2b2154512ddd11e6b6d9d65708a99e/src/compiler/compile/utils/hash.ts#L2)
const stringHashcode = str => {
let hash = 5381
let i = str.length
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i)
return (hash >>> 0).toString(36)
}
const normalizeJsCode = (code, cssHash) =>
code
// ignore css hashes in the code (that have changed, necessarily)
.replace(new RegExp('\\b' + cssHash + '\\b', 'g'), '')
// Svelte now adds locations in dev mode, code locations can change when
// CSS change, but we're unaffected (not real behaviour changes)
.replace(/\badd_location\s*\([^)]*\)\s*;?/g, '')
const parseCssId = (code, compileOptions = {}, parseHash, originalCode) => {
// the regex matching is very pretty conservative 'cause I don't want to
// match something else by error... I'm probably make it more lax if I have
// to fix it 3 times in a single week ¯\_(ツ)_/¯
let match = /^function add_css\(\) \{[\s\S]*?^}/m.exec(code)
if (!match) {
// guard: injectCss is off, no need to compute hashes
if (!parseHash) return {}
// guard: compile.css is true, so we should have found the add_css function,
// something unexpected is unraveling here, fall back to caution
if (compileOptions.css) return {}
// trying to get CSS id the same way as Svelte does it
match = /