Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript Error: No element indexed by 0 #424

Closed
GrygrFlzr opened this issue Mar 2, 2021 · 26 comments · Fixed by #544
Closed

TypeScript Error: No element indexed by 0 #424

GrygrFlzr opened this issue Mar 2, 2021 · 26 comments · Fixed by #544
Labels

Comments

@GrygrFlzr
Copy link
Member

GrygrFlzr commented Mar 2, 2021

This is caused by Vite's source map handling on .svelte files that are not dynamic files.
As a temporary workaround, make sure to have src/routes/$layout.svelte with at least some "dynamic" content, e.g.

<slot />
{''}

Describe the bug
As long as svelte-preprocess is used in svelte.config.cjs, attempting to run dev mode results in internal errors.

Logs
With TypeScript, the page is a plaintext error:

Error: No element indexed by 0
    at ArraySet_at [as at] (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:24278:9)
    at BasicSourceMapConsumer.<anonymous> (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:25193:67)
    at Array.map (<anonymous>)
    at BasicSourceMapConsumer.SourceMapConsumer_eachMapping [as eachMapping] (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:25192:14)
    at merge (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:26656:18)
    at ssrTransform (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:61375:15)
    at transformRequest (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:61643:48)
    at async instantiateModule (C:\Users\GrygrFlzr\Documents\projects\sk-36\node_modules\vite\dist\node\chunks\dep-1bdbec90.js:67986:10)

To Reproduce

npm init svelte@next
# enable typescript
npm install
npm run dev

Expected behavior
No errors out of the box.

Information about your SvelteKit Installation:

  npmPackages:
    @sveltejs/kit: next => 1.0.0-next.36
    svelte: ^3.29.0 => 3.35.0

Severity
Unusable dev mode.

@Conduitry
Copy link
Member

I can reproduce the issue in TS mode, but not the one in JS mode - although I'm not testing this on Windows. I'll try that next.

@Conduitry
Copy link
Member

Yep, I can also see the issue in JS mode when running everything in Windows (and the TS one as well).

@Rich-Harris
Copy link
Member

Looks like two separate issues — from the stack trace, the TS thing looks like it might be a bug in Vite's sourcemap handling

@benmccann benmccann added this to the public beta milestone Mar 3, 2021
@GrygrFlzr GrygrFlzr changed the title Starter template dev mode fails with internal errors Starter TypeScript template dev mode fails with internal errors Mar 5, 2021
@GrygrFlzr
Copy link
Member Author

Switching this issue to the TS-specific one. I'll open a separate issue for the JS one later.

I dug a bit into this by pointing kit to use a local build of vite and found that these lines are the culprit:

https://github.com/vitejs/vite/blob/6fae0b7d119cf97904ae276176f8bb4374aee300/packages/vite/src/node/ssr/ssrTransform.ts#L182-L186

When it attempts to handle the following:

const oldMap = {
  version: 3,
  file: null,
  sources: [ null ],
  sourcesContent: [ null ],
  names: [],
  mappings: 'AAAA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;AAC3D;AACvD;AACA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,0CAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AACH;AACA,8BAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC'
};
const newMap = {
  version: 3,
  mappings: ';;;;;;;',
  names: [],
  sources: [],
  sourcesContent: []
};

Unfortunately, that means the issue is actually deeper in vite's dependency on merge-source-map, which has not been maintained since December 2017. There's even an open issue on its repo - keik/merge-source-map#6.

I am unsure how to produce a minimal reproduction to submit as an issue to vite beyond submitting a repo making use of the public version of kit which depends on an older version of vite (2.0.4); nor if there's a modern replacement for merge-source-map that's still being maintained to suggest as a PR.

@GrygrFlzr
Copy link
Member Author

Okay, I managed to track down the source of the issue: it dies on empty source files (in this case, our empty $layout.svelte). I've made a minimal repro and reported the issue at vitejs/vite#2391.

@GrygrFlzr
Copy link
Member Author

I've gotten some progress on this issue. Vite's current code does not handle blank sourcemaps at all. Problem is, when I tried to look at prior art:

  • Vite's Vue starter template does not generate any sourcemaps when dynamic parts are ripped out (e.g. file with no <script> tags) and just serves the unmapped generated JavaScript component. This is why they're not hitting the issue.
  • React is, well, React, and since it's always in some sort of JavaScript-related file it always avoids the problem.
  • Sapper does not generate any sourcemaps nor does it show the generated JavaScript component when dynamic parts are ripped out (no <script> tags, no {#each} block, etc).
  • Vanilla Svelte with TypeScript behaves the same as Sapper.

At the moment I am able to make Vite + Svelte generate the unmapped generated JavaScript component.

Sourcemaps are always properly generated with .svelte that do some JS process:

<!-- this works -->
Hello {'world'}

<!-- this works -->
Hello world
{''}

<!-- this works -->
<script>
  let blah = true;
</script>
Hello world

<!-- this works -->
{#each [1, 2, 3] as num}
  {num}
{/each}

@dominikg Are static file sourcemaps potentially something that can be supported at the vite-plugin-svelte level, or would I need to dive into svelte-preprocess instead?

@Rich-Harris Any potential insight here? I'd love to get sourcemaps for static Svelte files, but the empty sourcemaps currently being sent to Vite seems to indicate that this might need support from either the svelte codebase or the svelte-preprocess codebase?

@benmccann
Copy link
Member

You tested Vanilla Svelte with TypeScript. What about Vanilla Svelte without TypeScript? I think that would narrow down whether it's Svelte core or svelte-prepeocess

@GrygrFlzr
Copy link
Member Author

Oh, not sure why I didn't think of that. Vanilla Svelte also does the same thing, so I guess it's part of svelte.

@benmccann
Copy link
Member

Thanks for your PR over in the Vite repo! vitejs/vite#2441

@dominikg
Copy link
Member

dominikg commented Mar 9, 2021

fwiw vite-plugin-svelte uses the logic from rollup-plugin-svelte for sourcemaps: https://github.com/svitejs/svite/blob/c5cb875a007ad5fd4dfff1a33c9aaba61eab291c/packages/vite-plugin-svelte/src/utils/compile.ts#L36

and i ran into this gem on vites css transform last night: https://github.com/vitejs/vite/blob/5ec13d8b3fe1632f793c7ad22b21c43a13d71141/packages/vite/src/node/plugins/css.ts#L197
looks like an easy fix though, the map is returned by compileCSS. 🤷‍♂️

@GrygrFlzr
Copy link
Member Author

Actually, now that I've dug this deep, why is this bug even specific to the TS template? From what we know so far, this should theoretically also trigger on the JS template, but I can't even replicate it on the JS template with a blank $layout.svelte file or one with just <slot /> in it.

In fact, source maps for static .svelte components work with the JS template!
image

If it's not svelte-preprocess, I'm totally confounded on why it's only triggering when we have some sort of preprocessing involved.

@GrygrFlzr
Copy link
Member Author

I see now in @dominikg's links that vite-plugin-svelte behaves differently when a preprocess step is involved:

let preprocessed
if (options.preprocess) {
    preprocessed = await preprocess(code, options.preprocess, { filename })
    if (preprocessed.dependencies)
    dependencies.push(...preprocessed.dependencies)
    if (preprocessed.map) finalCompilerOptions.sourcemap = preprocessed.map
}

So I guess I'm taking a look at either svelte-preprocess or rollup-plugin-svelte tonight.

@GrygrFlzr
Copy link
Member Author

Okay, I can in fact replicate this on a JS+CSS starter kit template by just adding svelte-preprocess to the dev dependencies and modifying svelte.config.cjs to use it without having to add any other preprocessors:

const sveltePreprocess = require('svelte-preprocess');

module.exports = {
	preprocess: sveltePreprocess(),
	// ...

I also tried building a local copy of vite-plugin-svelte which ignores the preprocessed sourcemap:

let preprocessed
if (options.preprocess) {
    preprocessed = await preprocess(code, options.preprocess, { filename })
    if (preprocessed.dependencies)
    dependencies.push(...preprocessed.dependencies)
    // if (preprocessed.map) finalCompilerOptions.sourcemap = preprocessed.map
}

Which successfully shows the unprocessed map.

I also tried to change if (preprocessed.map) to if (preprocessed.map && code !== preprocessed.code), but that only works for the most trivial cases (e.g. the default layout <slot></slot>), whereas any file containing a <style> tag will at least get an extra newline before the closing tag after base preprocessing.

I'm starting to delve into svelte to see if the root issue is there, but it's difficult due to the dependency tree having multiple uses of svelte.

@arxpoetica
Copy link
Member

FWIW, this bug showed up for me when I chose SASS on npm init svelte@next, but the bug goes away if I choose CSS. I'm sure you already knew this. Just adding a data point.

@dominikg
Copy link
Member

fyi
I started experimenting with a custom preprocessor that delegates to vite transforms.

https://github.com/svitejs/svite/tree/feat/preprocess-with-vite/packages/playground/preprocess-with-vite

there is an option you need to enable in Vite config and its not released, but this could help if the issue is within svelte-preprocess

@dummdidumm
Copy link
Member

I don't think we should side step svelte-preprocess. I'm also quite confused how this happens since when using roll-up you get the correct source maps which you can use to debug your Svelte-with-Typescript code in the Browser.

@GrygrFlzr
Copy link
Member Author

@dummdidumm to be clear, I'm not advocating sidestepping svelte-preprocess - I'm demonstrating that it's at that point that it goes through the preprocessor that sourcemaps for static components are mangled.

@GrygrFlzr GrygrFlzr changed the title Starter TypeScript template dev mode fails with internal errors Templates with preprocessing dev mode fails with internal errors Mar 11, 2021
@dominikg
Copy link
Member

I think @dummdidumm was talking about my last comment regarding the vite based preprocessor. We should discuss this elsewhere, i was merely offering another option to narrow down the issue.

It's very possible the way how vite-plugin-svelte reads the svelte config or how the preprocessors+map are applied in compile is at fault here. (though i took the latter bits from rollup-plugin-svelte)

@benmccann benmccann pinned this issue Mar 12, 2021
@benmccann benmccann changed the title Templates with preprocessing dev mode fails with internal errors TypeScript Error: No element indexed by 0 Mar 12, 2021
@dummdidumm
Copy link
Member

dummdidumm commented Mar 12, 2021

I dug into this at well and I'm suspecting the Svelte compiler now and how it handles incoming sourcemap, or how that sourcemap is produced by Svelte's preprocessor.

I noticed that when you run a preprocessor before compiling

  • the js.map is a class SourceMap instead of a JSON
  • that class has empty sources and sourcesContent arrays, whereas without preprocessing they are set and filled

EDIT: The reason is the empty sources. If I add the full file path to it manually before handing the map to vite, it works. The Svelte compiler seems to trip up there and not fill it if sourcemap is set. Or sourcemap contains a wrong sources content, which means the compiler's preprocess function is at fault.

@dummdidumm
Copy link
Member

dummdidumm commented Mar 14, 2021

Dug deeper. The problem is that inside the function combine_sourcemaps mappings go in, and then one mapping comes out without sources set. If I add this to the bottom

if (!map.sources.length) {
   map.sources = [filename];
}

It works. This could be a quick fix while we investigate why this even happens. Either the library which we use to combine source mappings is at fault, or we give it faulty input.

@GrygrFlzr
Copy link
Member Author

Hm, should I update my Vite PR then? It was largely based on the existing svelte code for combine_sourcemaps.

@Conduitry
Copy link
Member

I haven't been following this closely, but do we need that Vite PR at all if we change this on the Svelte side? Or do you think that's something their API should be able to handle anyway?

@dummdidumm
Copy link
Member

dummdidumm commented Mar 14, 2021

Not sure. I think the PR over at Vite makes sense either way. To me it looks like the remapping library trips up when the first source map is empty. So if I want to merge this

[
  {
    version: 3,
    names: [],
    sources: [ 'C:/repos/svelte/kit-testsourcemaps/src/routes/$layout.svelte' ],
    sourcesContent: [ '' ],
    mappings: ';;;;;;;'
  },
  SourceMap {
    version: 3,
    mappings: '',
    names: [],
    sources: [ '$layout.svelte' ]
  }
]

It produces { version: 3, mappings: ';;;;;;;', names: [], sources: [] } (note the empty sources array).

Digging into the source code of that lib, I think that in this function the combination is done, and the line where sources is updated is never reached in case of empty mappings.

I created ampproject/remapping#116 , let's see what comes back. In the meantime we might add the workaround I posted earlier.

@benmccann
Copy link
Member

I guess the question on the Svelte side would be whether Svelte should be returning empty source maps when there's no script tag. Should we have an issue in Svelte core for that?

dummdidumm pushed a commit to dummdidumm/svelte that referenced this issue Mar 15, 2021
When source maps are combined and the leading map is empty, sources is not set. Add the filename to the empty array in this case.
Related sveltejs/kit#424
@benmccann benmccann mentioned this issue Mar 15, 2021
@benmccann benmccann unpinned this issue Mar 15, 2021
@dummdidumm
Copy link
Member

Postmortem analysis: I think the reason why both the change to Svelte core (adding sources) and the Vite PR solve this on their own is that

  • if Vite used its old merge-sourcemaps it would work if Svelte core would set the sources array, avoiding the empty source map crash
  • now that Vite is updated to use the new merge-sourcemaps, it can handle empty sources.

Ultimately I does not matter what comes out in the end because those source maps are empty either way, so it was just a matter of preventing a crash along the way

@GrygrFlzr
Copy link
Member Author

Yeah, I already figured that to fix the crash, all you'd need to do is fix it at one end. That's why later on I focused on "disappearing sourcemaps for non-dynamic files", which I guess should be a separate issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants