Svelte - Carbon component import breaks debugging - google-chrome
I've setup a Svelte and Electron that uses Carbon Components. I have it working for the most part, but I'm stuck at debugging.
Here's a sample component I'm using for testing:
<script lang="ts">
import { Tile } from 'carbon-components-svelte'
let name = 'John Doe'
function test() {
console.log('You clicked me!')
}
</script>
<div>
<Tile>
<h2>{name}</h2>
<button on:click={test}>Click me</button>
</Tile>
</div>
When I load the component into a dev environment, I can't set breakpoints in Chrome's dev tools:
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
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
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
Customize font-size depending on locale in Vue3/Laravel8?
I am working on a Vue3/Laravel8 app, that has to support english and arabic languages. Problem is that there is a huge font-size difference between the en and ar locales: I've been looking for a while now for a way to change the arabic font-size but it doesn't seem simple. First I tried finding a way in vue-i18n without success. It would be most convenient if that is possible. Then I tried going the CSS route, using the :lang(ar) selector but it depends on html or in my case laravel.blade and controlling project language seems to be a hassle, creating middleware and controllers. Is there a convenient way to do that?
Vue 3.2 introduced some new features for single file components (SFC): https://v3.vuejs.org/api/sfc-style.html#state-driven-dynamic-css So in your case you could try something like this (untested): <template> <div class="text">hello</div> </template> <script> export default { data() { return { lang: 'en', }, }, computed() { fontSize() { if (this.lang === 'ar') { return '1.5em'; } return '1em'; }, }, } </script> <style> .text { font-size: v-bind(fontSize); } </style>
show legend by default on a kepler gl point map
I would like to export my point map done using kepler gl to an interactive html file. This interactive html file should have a legend (colour key) visible by default. What I mean is i shouldn't click on the show legend button to see the meaning of colours on the map - the show legend should be visible and fixed by default after exporting. Is this possible? Can anyone please guide me on how to achive this?
I am not sure about html exporting thing, and I am also not sure if you mean how to do it with the demo, basically using a front-end (GUI), or by the API components. Since I made the legend open by default using react, I'll talk about it. /* store.js */ // some of your import import { createStore, applyMiddleware } from "redux"; import keplerGlReducer, { uiStateUpdaters } from 'kepler.gl/reducers'; import { taskMiddleware } from "react-palm/tasks"; // rest of them const customizedKeplerGlReducer = keplerGlReducer .initialState({ uiState: { mapControls: { ...uiStateUpdaters.DEFAULT_MAP_CONTROLS, mapLegend: { show: true, active: false }, /* another map controls */ //toggle3d: { // show: true //}, } } }); export default createStore(customizedKeplerGlReducer, {}, applyMiddleware(taskMiddleware)); This way your legend will be open (clicked) by default, unless this is not what you asked for. Full example by kepler.gl
How to use html code to design front end in react native?
Our design team has shared some HTML code with us, based on which I have to build the UI in React Native. There are some tags like: <link rel="Stylesheet" type="text/css" href="vendor/bootstrap/css/bootstrap.min.css" /> If I want to adapt these to React Native, how should it be? Or should I develop a React Native app separately without taking any reference from the HTML?
You can use react-native-css-transformer module install : yarn add --dev react-native-css-transformer For React Native v0.57 or newer / Expo SDK v31.0.0 or newer Add this to metro.config.js in your project's root (create the file if it does not exist already): const { getDefaultConfig } = require("metro-config"); module.exports = (async () => { const { resolver: { sourceExts } } = await getDefaultConfig(); return { transformer: { babelTransformerPath: require.resolve("react-native-css-transformer") }, resolver: { sourceExts: [...sourceExts, "css"] } }; })(); Example App.css .myClass { color: blue; } .myOtherClass { color: red; } .my-dashed-class { color: green; } Usage import styles from "./App.css"; <MyElement style={styles.myClass} /> <MyElement style={styles["my-dashed-class"]} /> Documention : react-native-css-transformer
You can't use HTML tags directly in react native projects, So you have got two options - Re write code with React Native elements such View etc.. Import those parts as individual stand by own webviews, https://github.com/react-native-community/react-native-webview/blob/master/README.md
How to add a label over slider selector
How can I get a little label telling me what number I have selected on a slider in Dash for python? I am using dash_core_components.Slider(). I essentially want to have something with the little blue "500" label shown on the first slider here.
Update on this issue: always-visible tooltips (i.e. value labels) are now available for dcc.Slider() and dcc.RangeSlider() as of Dash 1.0 with the argument tooltip: import dash import dash_core_components as dcc ... dcc.Slider(..., tooltip = { 'always_visible': True }) You can install Dash >=1.0 with pip install dash The latest version of Dash is 1.9.1
The first example given here shows how to update a label according to the value of the slider. I have modified it a bit in the code below to use a Slider as you wanted (instead of RangeSlider), and to update the label while dragging (instead of on mouse-up): import dash import dash_html_components as html import dash_core_components as dcc external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'] app = dash.Dash(__name__, external_stylesheets=external_stylesheets) app.layout = html.Div(id='slider-wrapper', children=[ dcc.Slider( id='my-slider', min=0, max=20, step=0.5, value=5, updatemode='drag', ), html.Div(id='output-container-range-slider'), # Need onload script: $('#slider-wrapper .rc-slider-handle').appendChild($('#output-container-range-slider')); ]) #app.callback( dash.dependencies.Output('output-container-range-slider', 'children'), [dash.dependencies.Input('my-slider', 'value')]) def update_output(value): return str(value) if __name__ == '__main__': app.run_server(debug=True) Unfortunately, this does not place the label as a small flag above the slider as you wanted. There is no simple solution for that, but you could use JavaScript to make the label div follow the slider handle, and execute it on page load. You can add your own CSS and JavaScript to dash apps, so add the following snippets: CSS: #slider-wrapper { margin-top: 100px; } #output-container-range-slider { position: absolute; left: -12px; top: -40px; background-color: #428BCA; color: #FFFFFF; font-weight: bold; height: 35px; padding: 5px; width: 34px; text-align: center; display: none; /* Hide flag until it is moved */ } JS: function appendToSlider() { var flag = document.getElementById('output-container-range-slider'); document.querySelector('#slider-wrapper .rc-slider-handle').appendChild(flag); flag.style.display = 'block'; // Make visible after moving } setTimeout(appendToSlider, 2000); Notice the workaround using setTimeout - ideally you want the appendToSlider function to get executed right after the slider is rendered, if there was such an event to attach it to. I could not find a way to that, but that is an issue for a separate thread.
Creating Sankey Diagram using ggplot2, plotly and ggplotly
I want to create a sankey diagram using ggplot2 and plotly and call using ggplotly. I would require some good working examples with some crucial links.I have implemented one in plotly and this is the snap I achieved. Please help and thanks. Editing the script: library(googleVis) datSK <- data.frame(From=c(rep("r1","r2","r3","r4","r5","r6","r7")), To=c(rep(c("Blood Test", "Check Out", "Discuss Results","MRI SCAN", "Registration","Triage and Assessment","XRay"))), Weight=c(237,492,495,236,500,500,261)) Sankey <- gvisSankey(datSK, from="From", to="To", weight="Weight", options=list( sankey="{link: {color: { fill: '#d799ae' } }, node: { color: { fill: '#a61d4c' }, label: { color: '#871b47' } }}")) plot(Sankey)
This question is extremely old now and this answer wasn't around then, but the ggforce package now allows for sankey diagrams to be plotted in ggplot. There is currently no ggplotly support (and as such no interactablilty) but for simple sankeys it is now the best option I have found in that it works with the tidy data framework.