Home > OS >  Svelte - Carbon component import breaks debugging
Svelte - Carbon component import breaks debugging

Time:10-14

I've setup a Svelte and Electron that uses enter image description here

However, if I open my svelte.config.js, which initially look:

import sveltePreprocess from 'svelte-preprocess'
import { optimizeImports } from "carbon-preprocess-svelte";

export default {
  preprocess: [ sveltePreprocess(), optimizeImports() ]
}

And remove the optimizeImports() call, then breakpoints work correctly.

Does anyone have any clue why this is happening? Clearly it's something to do with the carbon-preprocess-svelte library. I created a basic project that reproduces the issue: https://github.com/troncoso/carbon-svelte-bug

CodePudding user response:

TL;DR: The inline source map is kinda broken, it's a bug in carbon-preprocess-svelte.


When you use: import { Tile } from 'carbon-components-svelte', the default module resolution will import the named export Tile from a big umbrella file at carbon-components-svelte/lib/index.js, which is a big minified code bundle. Clearly this is not optimal.

optimizeImports from carbon-preprocess-svelte is a preprocessor that tries to optimize it by reading your import code then rewriting it into sth like import Tile from "carbon-components-svelte/src/Tile/Tile.svelte".

Obviously there's some kind of bug in this preprocessor, that produces a broken source map. To be precise, it produces a source map that misses out some mapping positions. Chrome devtool relies on these mapping positions to set a breakpoint. When it's missing, it cannot set one.

When you manually rewrite the import, you skip this preprocessor, thus you avoid the wrong behavior. This is consistent to your current finding.

We might rest our case here and conclude that you should avoid using optimizeImports for now, and just report the bug to carbon team. Below will dive into more details.


This is the inline source map of the bad case:

//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FDQSxJQUFBLE1BQUEsK0NBQUE7Ozs7Ozs7Ozs7Ozs7O2FBUThCLFVBQ2xCO3VCQUFDLEdBQUs7Ozs7O0dBRGhCLFVBRVE7Ozs7O3dEQUZVLEdBQVM7Ozs7O3VEQUNoQixHQUFLOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQVJsQixLQUFBLEdBQUEsQ0FBQTs7T0FDQSxTQUFBO2tCQUNBLEtBQUEsSUFBQSxDQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7IiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkNvdW50ZXIuc3ZlbHRlIl0sInNvdXJjZXNDb250ZW50IjpbIjxzY3JpcHQgbGFuZz1cInRzXCI XG4gIGltcG9ydCBUaWxlIGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLXN2ZWx0ZS9zcmMvVGlsZS9UaWxlLnN2ZWx0ZSdcbiAgbGV0IGNvdW50OiBudW1iZXIgPSAwXG4gIGNvbnN0IGluY3JlbWVudCA9ICgpID0 IHtcbiAgICBjb3VudCArPSAxXG4gIH1cbjwvc2NyaXB0PlxuXG48VGlsZT5cbiAgPGJ1dHRvbiBvbjpjbGljaz17aW5jcmVtZW50fT5cbiAgICBDbGlja3M6IHtjb3VudH1cbiAgPC9idXR0b24 XG48L1RpbGU XG5cbjxzdHlsZT5cbiAgYnV0dG9uIHtcbiAgICBmb250LWZhbWlseTogaW5oZXJpdDtcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgcGFkZGluZzogMWVtIDJlbTtcbiAgICBjb2xvcjogI2ZmM2UwMDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMSk7XG4gICAgYm9yZGVyLXJhZGl1czogMmVtO1xuICAgIGJvcmRlcjogMnB4IHNvbGlkIHJnYmEoMjU1LCA2MiwgMCwgMCk7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICB3aWR0aDogMjAwcHg7XG4gICAgZm9udC12YXJpYW50LW51bWVyaWM6IHRhYnVsYXItbnVtcztcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gIH1cblxuICBidXR0b246Zm9jdXMge1xuICAgIGJvcmRlcjogMnB4IHNvbGlkICNmZjNlMDA7XG4gIH1cblxuICBidXR0b246YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMik7XG4gIH1cbjwvc3R5bGU XG4iXX0=

And here's the one of the good case:

//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FDQSxJQUFBLE1BQUEsK0NBQUE7Ozs7Ozs7Ozs7Ozs7O2FBUThCLFVBQ2xCO3VCQUFDLEdBQUs7Ozs7O0dBRGhCLFVBRVE7Ozs7O3dEQUZVLEdBQVM7Ozs7O3VEQUNoQixHQUFLOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQVJsQixLQUFBLEdBQUEsQ0FBQTs7T0FDQSxTQUFBO2tCQUNBLEtBQUEsSUFBQSxDQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7IiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkNvdW50ZXIuc3ZlbHRlIl0sInNvdXJjZXNDb250ZW50IjpbIjxzY3JpcHQgbGFuZz1cInRzXCI XG4gIGltcG9ydCBUaWxlIGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLXN2ZWx0ZS9zcmMvVGlsZS9UaWxlLnN2ZWx0ZSdcbiAgbGV0IGNvdW50OiBudW1iZXIgPSAwXG4gIGNvbnN0IGluY3JlbWVudCA9ICgpID0 IHtcbiAgICBjb3VudCArPSAxXG4gIH1cbjwvc2NyaXB0PlxuXG48VGlsZT5cbiAgPGJ1dHRvbiBvbjpjbGljaz17aW5jcmVtZW50fT5cbiAgICBDbGlja3M6IHtjb3VudH1cbiAgPC9idXR0b24 XG48L1RpbGU XG5cbjxzdHlsZT5cbiAgYnV0dG9uIHtcbiAgICBmb250LWZhbWlseTogaW5oZXJpdDtcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgcGFkZGluZzogMWVtIDJlbTtcbiAgICBjb2xvcjogI2ZmM2UwMDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMSk7XG4gICAgYm9yZGVyLXJhZGl1czogMmVtO1xuICAgIGJvcmRlcjogMnB4IHNvbGlkIHJnYmEoMjU1LCA2MiwgMCwgMCk7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICB3aWR0aDogMjAwcHg7XG4gICAgZm9udC12YXJpYW50LW51bWVyaWM6IHRhYnVsYXItbnVtcztcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gIH1cblxuICBidXR0b246Zm9jdXMge1xuICAgIGJvcmRlcjogMnB4IHNvbGlkICNmZjNlMDA7XG4gIH1cblxuICBidXR0b246YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMik7XG4gIH1cbjwvc3R5bGU XG4iXX0=

They're base64 encoded json, if we decoded them, we get:

bad case:

{
  "version": 3,
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;OAAiB,IAAA,MAAA, CAAA;;;;;;;;;;;;;;aASa,UAClB;uBAAC,GAAK;;;;;GADhB,UAEQ;;;;;wDAFU,GAAS;;;;;uDAChB,GAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
  "names": [],
  "sources": ["Counter.svelte"],
  "sourcesContent": [
    "<script lang=\"ts\">\n  import { Tile } from 'carbon-components-svelte'\n  let count: number = 0\n  const increment = () => {\n    count  = 1\n  }\n</script>\n\n<Tile>\n  <button on:click={increment}>\n    Clicks: {count}\n  </button>\n</Tile>\n\n<style>\n  button {\n    font-family: inherit;\n    font-size: inherit;\n    padding: 1em 2em;\n    color: #ff3e00;\n    background-color: rgba(255, 62, 0, 0.1);\n    border-radius: 2em;\n    border: 2px solid rgba(255, 62, 0, 0);\n    outline: none;\n    width: 200px;\n    font-variant-numeric: tabular-nums;\n    cursor: pointer;\n  }\n\n  button:focus {\n    border: 2px solid #ff3e00;\n  }\n\n  button:active {\n    background-color: rgba(255, 62, 0, 0.2);\n  }\n</style>\n"
  ]
}

good case:

{
  "version": 3,
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;OACA,IAAA,MAAA, CAAA;;;;;;;;;;;;;;aAQ8B,UAClB;uBAAC,GAAK;;;;;GADhB,UAEQ;;;;;wDAFU,GAAS;;;;;uDAChB,GAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KARlB,KAAA,GAAA,CAAA;;OACA,SAAA;kBACA,KAAA,IAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
  "names": [],
  "sources": ["Counter.svelte"],
  "sourcesContent": [
    "<script lang=\"ts\">\n  import Tile from 'carbon-components-svelte/src/Tile/Tile.svelte'\n  let count: number = 0\n  const increment = () => {\n    count  = 1\n  }\n</script>\n\n<Tile>\n  <button on:click={increment}>\n    Clicks: {count}\n  </button>\n</Tile>\n\n<style>\n  button {\n    font-family: inherit;\n    font-size: inherit;\n    padding: 1em 2em;\n    color: #ff3e00;\n    background-color: rgba(255, 62, 0, 0.1);\n    border-radius: 2em;\n    border: 2px solid rgba(255, 62, 0, 0);\n    outline: none;\n    width: 200px;\n    font-variant-numeric: tabular-nums;\n    cursor: pointer;\n  }\n\n  button:focus {\n    border: 2px solid #ff3e00;\n  }\n\n  button:active {\n    background-color: rgba(255, 62, 0, 0.2);\n  }\n</style>\n"
  ]
}

Problem lies in the mappings field. You can make sense of both files with the source map decoder then compare by clicking the dump button. You'll see that some mapping information are simply missing in the bad case file.

This article Anatomy of source maps, if it interests you, will guide you through the technical details of the js source map format (to understand the mysterious ;;OAAiB,IAAA,MAAA, CAAA;; part).

But for now let's simply read the human-friendly dump:

Counter.svelte,137,27,5,0,null

translates to:

position 137:27 from compiled file `Counter.js`
maps to 
position 5:0 from original source file `Counter.svelte`

And here's the dump for both files.

bad case mapping dump:

Counter.svelte,24,7,1,17,null
Counter.svelte,24,11,1,17,null
Counter.svelte,24,17,1,17,null
Counter.svelte,24,64,1,17,null
Counter.svelte,38,13,10,30,null
Counter.svelte,38,23,11,12,null
Counter.svelte,39,23,11,13,null
Counter.svelte,39,26,11,18,null
Counter.svelte,44,3,10,2,null
Counter.svelte,44,13,12,10,null
Counter.svelte,49,56,10,20,null
Counter.svelte,49,59,10,29,null
Counter.svelte,54,55,11,13,null
Counter.svelte,54,58,11,18,null

good case mapping dump:

Counter.svelte,24,7,2,0,null
Counter.svelte,24,11,2,0,null
Counter.svelte,24,17,2,0,null
Counter.svelte,24,64,2,0,null
Counter.svelte,38,13,10,30,null
Counter.svelte,38,23,11,12,null
Counter.svelte,39,23,11,13,null
Counter.svelte,39,26,11,18,null
Counter.svelte,44,3,10,2,null
Counter.svelte,44,13,12,10,null
Counter.svelte,49,56,10,20,null
Counter.svelte,49,59,10,29,null
Counter.svelte,54,55,11,13,null
Counter.svelte,54,58,11,18,null
Counter.svelte,134,5,3,0,null
Counter.svelte,134,10,3,0,null
Counter.svelte,134,13,3,0,null
Counter.svelte,134,14,3,0,null
Counter.svelte,136,7,4,0,null
Counter.svelte,136,16,4,0,null
Counter.svelte,137,18,5,0,null
Counter.svelte,137,23,5,0,null
Counter.svelte,137,27,5,0,null
Counter.svelte,137,28,5,0,null

CodePudding user response:

Read @hackape's answer for details. But ultimately it seems like a bug with carbon-preprocess-svelte, specifically the optimizeImports() plugin. I created an issue on that project: https://github.com/carbon-design-system/carbon-preprocess-svelte/issues/18

In the meantime, I came up with a solution that made sure the source maps work and I still get tree shaking. I created a carbon.ts file:

import { Button } from 'carbon-components-svelte/src/Button'
import { Tile, ClickableTile } from 'carbon-components-svelte/src/Tile'
import { StructuredList, StructuredListHead, StructuredListBody, StructuredListRow,
    StructuredListCell } from 'carbon-components-svelte/src/StructuredList'
import { Header, HeaderGlobalAction, HeaderUtilities, Content }
    from 'carbon-components-svelte/src/UIShell'
import { Theme } from 'carbon-components-svelte/src/Theme'
import { TooltipDefinition } from 'carbon-components-svelte/src/TooltipDefinition'

export  {
    Button,
    Tile,
    ClickableTile,
    StructuredList,
    StructuredListBody,
    StructuredListCell,
    StructuredListHead,
    StructuredListRow,
    Header,
    HeaderGlobalAction,
    HeaderUtilities,
    Theme,
    TooltipDefinition,
    Content
}

When I need a component, I just add it to this file. Then I import the component like this:

<script lang="ts">
    import { Button } from '@/components/carbon'
</script>

I know I could have just done the imports in the svelte files themselves, but this way when the bug is fixed I can much more easily find and replace all the imports. Just search for "@/components/carbon" and replace it with "carbon-components-svelte".

  • Related