sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.04k stars 4.08k forks source link

[Svelte 5] Enabling Runes mode via compilerOptions incorrectly enforces it for external libraries #9632

Closed AgarwalPragy closed 9 months ago

AgarwalPragy commented 9 months ago

Describe the bug

Non backwards-compatible Runes mode can be enabled via compilerOptions in svelte.config.js https://svelte-5-preview.vercel.app/docs/runes#how-to-opt-in

export default {
  compilerOptions: {
    runes: true
  }
};

However, doing this enforces the runes mode even for external libraries. This means that any libraries written in svelte-4.x cannot be imported.

Ideally, runes mode should only be enforced for the current app and not the external libaries

Reproduction

https://github.com/AgarwalPragy/svelte-issue-9632

src/routes/+page.svelte

<script>
  import { Markdown } from 'svelte-exmarkdown';
</script>

<Markdown md='hello' />

Logs

> svelte-issue-9632@0.0.1 dev .
> vite dev "--" "--open"

3:52:50 PM [vite-plugin-svelte] svelte 5 support in v-p-s is experimental, breaking changes can occur in any release until this notice is removed
3:52:50 PM [vite-plugin-svelte] svelte 5 does not support svelte-inspector yet, disabling it
3:52:50 PM [vite-plugin-svelte] svelte 5 does not support hmr api yet, disabling it for now

Port 5173 is in use, trying another one...

  VITE v4.5.0  ready in 309 ms

  ➜  Local:   http://localhost:5174/
  ➜  Network: use --host to expose
  ➜  press h to show help
node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Transparent.svelte:1:8 Cannot use $$props in runes mode
node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Renderer.svelte:7:0 Cannot use `export let` in runes mode — use $props instead
node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Markdown.svelte:7:0 Cannot use `export let` in runes mode — use $props instead
3:52:51 PM [vite] Error when evaluating SSR module /node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/index.js: failed to import "/node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Markdown.svelte"
|- CompileError: Cannot use `export let` in runes mode — use $props instead
    at error (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/errors.js:569:8)
    at ExportNamedDeclaration (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/2-analyze/validation.js:678:3)
    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:49:5)
    at visitor (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:64:4)
    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:49:5)
    at visitor (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:64:4)
    at Object.next (file://node_modules/.pnpm/zimmerframe@1.1.0/node_modules/zimmerframe/src/walk.js:106:21)
    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:45:29)
    at next (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:55:7)
    at _ (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/scope.js:661:4)

3:52:51 PM [vite] Error when evaluating SSR module /src/routes/+page.svelte: failed to import "/node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/index.js"
|- CompileError: Cannot use `export let` in runes mode — use $props instead
    at error (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/errors.js:569:8)
    at ExportNamedDeclaration (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/2-analyze/validation.js:678:3)
    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:49:5)
    at visitor (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:64:4)
    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:49:5)
    at visitor (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:64:4)
    at Object.next (file://node_modules/.pnpm/zimmerframe@1.1.0/node_modules/zimmerframe/src/walk.js:106:21)
    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:45:29)
    at next (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:55:7)
    at _ (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/scope.js:661:4)

{
  name: 'CompileError',
  id: 'node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Markdown.svelte',
  message: 'node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Markdown.svelte:7:0 Cannot use `export let` in runes mode — use $props instead',
  frame: '4  |  } from "./contexts";\n' +
    '5  |  import Renderer from "./Renderer.svelte";\n' +
    '6  |  import { createParser, nonNullable } from "./utils";\n' +
    '   |                                                       ^\n' +
    '7  |  export let md;\n' +
    '8  |  export let plugins = [];',
  code: 'invalid-legacy-export',
  stack: 'CompileError: Cannot use `export let` in runes mode — use $props instead\n' +
    '    at error (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/errors.js:569:8)\n' +
    '    at ExportNamedDeclaration (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/2-analyze/validation.js:678:3)\n' +
    '    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:49:5)\n' +
    '    at visitor (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:64:4)\n' +
    '    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:49:5)\n' +
    '    at visitor (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:64:4)\n' +
    '    at Object.next (file://node_modules/.pnpm/zimmerframe@1.1.0/node_modules/zimmerframe/src/walk.js:106:21)\n' +
    '    at go (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:45:29)\n' +
    '    at next (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/visitors.js:55:7)\n' +
    '    at _ (file://node_modules/.pnpm/svelte@5.0.0-next.11/node_modules/svelte/src/compiler/phases/scope.js:661:4)',
  loc: {
    line: 7,
    column: 0,
    file: 'node_modules/.pnpm/svelte-exmarkdown@3.0.1_svelte@5.0.0-next.11/node_modules/svelte-exmarkdown/dist/Markdown.svelte'
  },
  plugin: 'vite-plugin-svelte',
  pluginCode: '<script>import {\n' +
    '  createComponentsContextValue,\n' +
    '  setComponentsContext\n' +
    '} from "./contexts";\n' +
    'import Renderer from "./Renderer.svelte";\n' +
    'import { createParser, nonNullable } from "./utils";\n' +
    'export let md;\n' +
    'export let plugins = [];\n' +
    'let parse;\n' +
    '$:\n' +
    '  parse = createParser(plugins);\n' +
    'const componentsContextValue = createComponentsContextValue({});\n' +
    '$:\n' +
    '  componentsContextValue.set({\n' +
    '    ...plugins.map((plugin) => plugin.renderer).filter(nonNullable).reduce((acc, cur) => ({ ...acc, ...cur }), {})\n' +
    '  });\n' +
    'setComponentsContext(componentsContextValue);\n' +
    'let result;\n' +
    '$:\n' +
    '  result = parse(md);\n' +
    '</script>\n' +
    '\n' +
    '<Renderer astNode={result} />\n'
}

System Info

System:
    OS: macOS 13.5.1
    CPU: (8) arm64 Apple M2
    Memory: 47.34 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 21.1.0 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 10.2.0 - /opt/homebrew/bin/npm
    pnpm: 8.10.2 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 119.0.6045.159
    Safari: 16.6
  npmPackages:
    svelte: ^5.0.0-next.1 => 5.0.0-next.11

Severity

blocking an upgrade

dummdidumm commented 9 months ago

@dominikg I believe this is something that needs to happen at the bundler plugin level, right?

AgarwalPragy commented 9 months ago

Temporary workaround provided by @dominikg via discord

with vite-plugin-svelte you can use dynamicCompileOptions to change it by file. https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#dynamiccompileoptions for vite 5/vite-plugin-svelte 3

// svelte.config.js
export default {
  //...
  vitePlugin:{
    dynamicCompileOptions({filename}){
      if(filename.includes('node_modules'){
        return {runes: undefined} // or false, check what works
      }
    }
  }
}

for sveltekit you have to add it as vitePlugin.experimental.dynamicCompileOptions

Rich-Harris commented 9 months ago

This is working as expected. The dynamicCompileOptions solution isn't a temporary workaround, it's explicitly the mechanism for having different compile options for different files

AgarwalPragy commented 9 months ago

@Rich-Harris Setting dynamicCompileOptions correctly to handle various libraries (svelte-4 and svelte-5) would be non-trivial for the users.

@dominikg mentioned the following via Discord.

workaround, we'll have to think about how this is supposed to work, there will be libraries for svelte4, svelte5 and both, and in the svelte5 case some might use runes while others might not. Optimal case is we have a declaration or heuristic so the bundler plugin knows which mode to use.

dominikg commented 9 months ago

we may be able to pass more info into dynamicCompileOptions too. hopefully this is just needed for a transition period until libraries have been updated to support 5