|
import { log, logCompilerWarnings } from './utils/log.js'; |
|
import { toRollupError } from './utils/error.js'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options) { |
|
if (!cache.has(svelteRequest)) { |
|
|
|
log.debug( |
|
`handleHotUpdate called before initial transform for ${svelteRequest.id}`, |
|
undefined, |
|
'hmr' |
|
); |
|
return; |
|
} |
|
const { read, server, modules } = ctx; |
|
|
|
const cachedJS = cache.getJS(svelteRequest); |
|
const cachedCss = cache.getCSS(svelteRequest); |
|
|
|
const content = await read(); |
|
|
|
let compileData; |
|
try { |
|
compileData = await compileSvelte(svelteRequest, content, options); |
|
cache.update(compileData); |
|
} catch (e) { |
|
cache.setError(svelteRequest, e); |
|
throw toRollupError(e, options); |
|
} |
|
|
|
const affectedModules = [...modules]; |
|
|
|
const cssIdx = modules.findIndex((m) => m.id === svelteRequest.cssId); |
|
if (cssIdx > -1) { |
|
const cssUpdated = cssChanged(cachedCss, compileData.compiled.css); |
|
if (!cssUpdated) { |
|
log.debug(`skipping unchanged css for ${svelteRequest.cssId}`, undefined, 'hmr'); |
|
affectedModules.splice(cssIdx, 1); |
|
} |
|
} |
|
const jsIdx = modules.findIndex((m) => m.id === svelteRequest.id); |
|
if (jsIdx > -1) { |
|
const jsUpdated = jsChanged(cachedJS, compileData.compiled.js, svelteRequest.filename); |
|
if (!jsUpdated) { |
|
log.debug(`skipping unchanged js for ${svelteRequest.id}`, undefined, 'hmr'); |
|
affectedModules.splice(jsIdx, 1); |
|
|
|
logCompilerWarnings(svelteRequest, compileData.compiled.warnings, options); |
|
} |
|
} |
|
|
|
|
|
const ssrModulesToInvalidate = affectedModules.filter((m) => !!m.ssrTransformResult); |
|
if (ssrModulesToInvalidate.length > 0) { |
|
log.debug( |
|
`invalidating modules ${ssrModulesToInvalidate.map((m) => m.id).join(', ')}`, |
|
undefined, |
|
'hmr' |
|
); |
|
ssrModulesToInvalidate.forEach((moduleNode) => server.moduleGraph.invalidateModule(moduleNode)); |
|
} |
|
if (affectedModules.length > 0) { |
|
log.debug( |
|
`handleHotUpdate for ${svelteRequest.id} result: ${affectedModules |
|
.map((m) => m.id) |
|
.join(', ')}`, |
|
undefined, |
|
'hmr' |
|
); |
|
} |
|
return affectedModules; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function cssChanged(prev, next) { |
|
return !isCodeEqual(prev?.code, next?.code); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function jsChanged(prev, next, filename) { |
|
const prevJs = prev?.code; |
|
const nextJs = next?.code; |
|
const isStrictEqual = isCodeEqual(prevJs, nextJs); |
|
if (isStrictEqual) { |
|
return false; |
|
} |
|
const isLooseEqual = isCodeEqual(normalizeJsCode(prevJs), normalizeJsCode(nextJs)); |
|
if (!isStrictEqual && isLooseEqual) { |
|
log.debug( |
|
`ignoring compiler output js change for ${filename} as it is equal to previous output after normalization`, |
|
undefined, |
|
'hmr' |
|
); |
|
} |
|
return !isLooseEqual; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function isCodeEqual(prev, next) { |
|
if (!prev && !next) { |
|
return true; |
|
} |
|
if ((!prev && next) || (prev && !next)) { |
|
return false; |
|
} |
|
return prev === next; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeJsCode(code) { |
|
if (!code) { |
|
return code; |
|
} |
|
return code.replace(/\s*\badd_location\s*\([^)]*\)\s*;?/g, ''); |
|
} |
|
|