vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.21k stars 6.04k forks source link

SSR source map merging fails on empty file segments (Error: No element indexed by 0) #2391

Closed GrygrFlzr closed 3 years ago

GrygrFlzr commented 3 years ago

Describe the bug

The following source map merging:

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

Given an empty input will throw an error:

Dev mode log ```bash $ pnpm dev > sourcemap-repro@1.0.0 dev C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro > node server Error: No element indexed by 0 at ArraySet$2.ArraySet_at [as at] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:24278:9) at BasicSourceMapConsumer. (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25193:67) at Array.map () at BasicSourceMapConsumer.SourceMapConsumer_eachMapping [as eachMapping] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25192:14) at merge (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:26656:18) at ssrTransform (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61382:15) at transformRequest (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61650:48) at async instantiateModule (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:67994:10) Error: No element indexed by 0 at ArraySet$2.ArraySet_at [as at] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:24278:9) at BasicSourceMapConsumer. (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25193:67) at Array.map () at BasicSourceMapConsumer.SourceMapConsumer_eachMapping [as eachMapping] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25192:14) at merge (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:26656:18) at ssrTransform (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61382:15) at transformRequest (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61650:48) at async instantiateModule (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:67994:10) Error: No element indexed by 0 at ArraySet$2.ArraySet_at [as at] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:24278:9) at BasicSourceMapConsumer. (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25193:67) at Array.map () at BasicSourceMapConsumer.SourceMapConsumer_eachMapping [as eachMapping] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25192:14) at merge (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:26656:18) at ssrTransform (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61382:15) at transformRequest (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61650:48) at async instantiateModule (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:67994:10) Error: No element indexed by 0 at ArraySet$2.ArraySet_at [as at] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:24278:9) at BasicSourceMapConsumer. (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25193:67) at Array.map () at BasicSourceMapConsumer.SourceMapConsumer_eachMapping [as eachMapping] (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:25192:14) at merge (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:26656:18) at ssrTransform (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61382:15) at transformRequest (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:61650:48) at async instantiateModule (C:\Users\GrygrFlzr\Documents\projects\sourcemap-repro\node_modules\.pnpm\vite@2.0.5\node_modules\vite\dist\node\chunks\dep-e0f09032.js:67994:10) ```

Important to note here that merge is an import from merge-source-map, which has not been maintained since December 2017. A somewhat (?) related bug report from May 2018 was already filed on its repo: keik/merge-source-map#6, but with no response. This is why I am bringing up the issue in the vite repository instead, as I do not think it is solvable on the upstream dependency.

Reproduction

https://github.com/GrygrFlzr/vite-sourcemap-repro

git clone https://github.com/GrygrFlzr/vite-sourcemap-repro.git
cd vite-sourcemap-repro
pnpm install
pnpm dev
# load the page on http://localhost:3000

System Info

GrygrFlzr commented 3 years ago

I've further tracked this down to empty segments of files.

That is to say, not only do all loaded files need to be not-empty, in a .svelte file's case a <script> tag section must exist and not be empty.

This will error:

<span>Hello world!</span>

And so will this:

<script>
    // just a comment here
</script>
Hello world

This will succeed:

<script>
    let name = 'world';
</script>
<span>Hello {name}!</span>

It must have some proper content (i.e. not just comments, not compiled down to nothing) or it will trigger the bug.

milahu commented 3 years ago

merge is an import from merge-source-map, which has not been maintained since December 2017

svelte uses ampproject/remapping which is up to date

see function combine_sourcemaps in svelte/src/compiler/utils/mapped_code.ts

GrygrFlzr commented 3 years ago

I've gotten some progress on this issue - it's not necessarily empty segments but any static file that does not involve JS processsing. Vite's current code does not handle blank sourcemaps at all. Problem is, when I tried to look at prior art:

Sourcemaps are always properly generated with .svelte files 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}

<!-- this doesn't, cause it's just HTML -->
<h1>Hello world</h1>
rmunn commented 3 years ago

Until #2441 is merged into Vite, anyone running into this can apply the following workaround. WARNING: This is massively hacky and not a good long-term solution. This is intended mostly for people trying out Svelte-Kit via npm init svelte@next who don't want to wait for #2441 to be merged.

WARNING WARNING WARNING: If you use pnpm, applying the patch below will change not just the copy of Vite in your project's node_modules directory, but (since pnpm uses hardlinks to de-duplicate packages) it will also modify the copy of Vite in your $HOME/.pnpm-store/ directory. This means that every project on your hard disk that uses the same version of Vite (2.0.5, in my case) will also have this patch applied to it. That may be a good thing from your perspective if you're trying to run multiple small test projects trying out svelte@next, but you should be aware of this fact.

If you use pnpm and want to REMOVE this hacky workaround, all you need to do is run pnpm install vite again from an empty folder, and pnpm will notice that the Vite package no longer matches its checkums and will overwrite the mutated copy with a fresh copy that does not have this hacky patch applied. Or from your existing project folder, you can do rm -rf node_modules/.pnpm/vite@2.0.5 (substituting a different version number if required) and then run pnpm install, which will re-download and reinstall Vite.

Okay, if you haven't been scared off by the warnings above, here's the hacky workaround. After running pnpm install (or npm install or yarn install), save the patch below to fix-source-map-merging.patch in the root of your project and then run patch -p1 -i fix-source-map-merging.patch. Now run pnpm run dev and your Svelte-Kit project should compile.

--- a/node_modules/vite/dist/node/chunks/dep-e0f09032.js    2021-03-03 02:27:15.000000000 +0700
+++ b/node_modules/vite/dist/node/chunks/dep-e0f09032.js    2021-03-03 02:27:15.000000000 +0700
@@ -25190,7 +25190,12 @@

     var sourceRoot = this.sourceRoot;
     mappings.map(function (mapping) {
-      var source = mapping.source === null ? null : this._sources.at(mapping.source);
+      var source;
+      try {
+        source = mapping.source === null ? null : this._sources.at(mapping.source);
+      } catch (e) {
+        source = null;
+      }
       source = util.computeSourceURL(sourceRoot, source, this._sourceMapURL);
       return {
         source: source,

NOTE: This works on Vite 2.0.5, but future Vite releases will probably use a different filename. If a new Vite release comes out before #2441 gets merged in, you'll have to tweak this patch by hand. The file you need to patch is the largest file in the node_modules/vite/dist/node/chunks/ directory. If the line numbers change too much and patch can't find the file, search the file for the text mapping.source === null and that should be the line you need to patch. I repeat: this is a massively hacky workaround, and you should not need this once a new Vite release comes out that includes #2441.