svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Symbols in component `module` scripts are remade during HMR

Open ottomated opened this issue 7 months ago • 6 comments

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

ottomated avatar May 27 '25 19:05 ottomated

That is intended behavior, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for

Mr-Zero88 avatar May 27 '25 22:05 Mr-Zero88

@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.

ottomated avatar May 28 '25 01:05 ottomated

don't use script module use global.js or something

https://github.com/sveltejs/svelte/issues/14398#issue-2680780176

dm-de avatar May 28 '25 18:05 dm-de

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>

Rich-Harris avatar Jun 02 '25 12:06 Rich-Harris

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 avatar Jun 02 '25 13:06 Rich-Harris

@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.

ottomated avatar Jun 02 '25 18:06 ottomated