Symbols in component `module` scripts are remade during HMR
Describe the bug
With the following component:
<script module lang="ts">
const KEY = Symbol('context-key');
export function set_context() {
setContext(KEY, /* ... */);
}
export function get_context() {
return getContext<T>(KEY);
}
</script>
<!-- ... -->
Every time HMR happens, KEY changes. This means that if set_context is called in a parent layout, all the children layouts will be unable to call get_context because the symbol is different.
This causes a hard-to-track-down error.
This might be impossible to solve outright, but a possible measure could be something like this:
export function getContext(key) {
const context_map = get_or_init_context_map('getContext');
if (DEV && typeof key === 'symbol') {
for (const existing_key of context_map.keys()) {
if (typeof existing_key !== 'symbol') continue;
if (key === existing_key) continue;
if (existing_key.description === key.description) {
// Log some kind of warning that two symbols with the same name are being used
}
}
}
const result = /** @type {T} */ (context_map.get(key));
return result;
}
Reproduction
REPL - will need to be ran locally because the playground doesn't support HMR.
Logs
N/A
System Info
System:
OS: Linux 6.14 Fedora Linux 41 (Forty One)
CPU: (32) x64 AMD Ryzen 9 5950X 16-Core Processor
Memory: 42.24 GB / 62.69 GB
Container: Yes
Shell: 3.7.1 - /bin/fish
Binaries:
Node: 22.15.1 - ~/.volta/tools/image/node/22.15.1/bin/node
Yarn: 4.3.1 - ~/.volta/tools/image/yarn/4.3.1/bin/yarn
npm: 10.9.2 - ~/.volta/tools/image/node/22.15.1/bin/npm
pnpm: 10.10.0 - ~/.volta/bin/pnpm
bun: 1.2.4 - ~/.bun/bin/bun
Browsers:
Chrome: 136.0.7103.92
npmPackages:
svelte: ^5.33.4 => 5.33.4
Severity
annoyance
That is intended behavior, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
@Mr-Zero88 I know how symbols work. I'm saying it's unintuitive that changing an unrelated area of your code leads to symbols changing and breaking things, and suggesting a DX improvement.
don't use script module use global.js or something
https://github.com/sveltejs/svelte/issues/14398#issue-2680780176
It would be very weird indeed to work around the normal behaviour of HMR in this one specific case. I suspect a better fix is to remove the import.meta.hot.accept call for components with a <script module>
In any case I can't seem to reproduce this locally. Editing Component.svelte causes anything that imports from that module to also be invalidated, which causes the components that read the context to be recreated. What are the steps?
@Rich-Harris After working out a bigger repro, it seems like there's some bug that causes HMR to not reload the layout when the module script is changed.