Joshua's Cheatsheets - Svelte JS - Cheatsheet and Misc Notes (WIP)
Light
help

Resources

What & Link Type
Svelte - Official Docs Official Docs
Svelte - Official Tutorials
- Use menu to quickly switch between
Tutorials
Svelte - Quick Start Guide Guide
Svelte - v2 vs v3 Cheatsheet Cheatsheet

Misc / How Do I...

  • Pass through arbitrary attributes on a custom component, from parent to child?

    • You could use {...$$restProps} in the child to spread the props received, but not declared with export (however, this is recommended against, for optimization reasons)
  • Pass through class names?

    • This is a littler tricker than it may seem, due to Svelte's style scoping and class optimization. You can use any of:

      • In the child, use:

        <script>
        	let classStr = '';
        	export {classStr as class};
        </script>
        
        <div class={classStr}></div>
        • Problem: If you have styles in the parent that are scoped to the class (e.g. myClass passed via classStr (as class prop) they will be optimized out since the compiler thinks the class is unused within the parent

          • Trick: You can use :global(.myClass) {} in the parent to preserve myClass. The downside is that it "pollutes" that component tree; if that class is used in any sub-components, the styles will also be applied...
      • In the child, use class="{$$props.class || ''}"

        • This is not recommended due to optimization issues with $$props
      • For more tips and discussion, see Issue #2870
  • Use CSS variables in style sections?

    • Go for it! You can totally use CSS variables in style blocks. But... keep in mind that Svelte's "scoping" will not magically scope your variables if you do something like :root { --myVar: ... }
    • It is often safer to dynamically build the CSS and deliver it through an inline style="" attribute

      • You can even inline CSS variable declarations!
  • Have an HTML attribute only output in the DOM if the JS variable being assigned to it is == true (e.i. do not output my-attribute="false")

    • For example, for data-selected={selected}, you might want the data-selected to only show up in the DOM if selected === true - if it is false, the attribute should just not be there. However, this is not the default behavior of Svelte, unless the attribute you are using is A) a native HTML attribute it knows about and B) it knows is a boolean attribute
    • The docs call this out; you need to use a nullish instead of a falsy value if you want the attribute to not show

      • Easy approach: my-attr={myVar || null} (or my-attr={!!myVar || null}, if you want to force boolean coercion).
  • How to pass methods up through the component tree? (aka expose and call a function in a child component)

    • Best practice is to export the method in the child via export function myFunction(){} or export const myFunc = () => {}, and then use bind:this={variableToExportsFromChild} in the parent (component binding)

      • See stackoverflow.com/a/61334528/
      • ⚠ You will not be able to access the component variable until the component is mounted / rendered, so you might want to wrap in onMount() if trying to use immediately.
    • You could use dispatched events as an alternative, although that requires more boilerplate. However, dispatched events can also travel downwards in addition to upwards.
  • How to make a prop optional

    • Assign a default value when exporting it (e.g. export let myProp = 5)
  • How to move components between places (e.g. from one parent to another), with animation in-between?

    • Svelte actually makes this so easy compared to a lot of other systems! You can use the send and receive transitions, combined with the crossfade function
    • Details:

  • Use static assets (images, svgs, etc.)?

    • One way is to simply place those assets in /public, and then reference them via relative (or absolute without domain) paths / URLs

      • This will not catch typos, or optimize unused assets out of production
    • Another way is to use the processing power of Rollup, which is being used as the default bundler anyways. You can use any number of plugins to accomplish various import tasks, such as letting you import svg files as strings to use directly in code

      • See github.com/rollup/plugins
      • This is better than placing in /public, because Rollup can make sure only imported assets are included in the final bundle, and it should also catch typos / incorrect imports

Passing Data Around

When passing data around your application, you typically have 4 main options

Props are fairly easy to understand, especially if you are coming from another framework like React or Vue, so I won't cover them in detail here (just use the Svelte docs, they are great!). However, context and store are a little more advanced.

Context vs Store

There are quite a few differences between context and store, although at a first glance they might not be clear. I've just started learning Svelte, so take this with a grain of salt, but I think this is a fair comparison:

👇 Context Store
Observable? No Yes
Reactive? No* Yes
Can exchange data with ___ components Data is sent from parent, downwards
(must be in same tree)
Any!

Summarizing another way, the main use of context is to share data downwards, in a component tree. Since it is not reactive, often it is used to pass something that does not change, such as a theme object set by a parent component.

On the other hand, store can be used to share data across your entire app (even outside of components!), and you can use it reactively to have components respond to changes, or observe mutations. Although the data being global is usually a benefit, sometimes context might be desirable if you want data isolated to a specific component tree.

* = 💡 Another way to use context and store is actually to use them... together! By passing a store object through context, it can be shared among a component tree by a parent and provide reactivity to child components!

💡 Don't forget that you can prefix store variables with $ to use them reactively without needing to set up a subscription / observer. You can even use this feature with input bindings or on: event bindings!

If you are looking for more info on context and store, here are some more resources:

General Troubleshooting

  • UI is not updating after an array or object property is updated, which is used in template

    • Svelte's reactive binding is based on assignments; modifying arrays (or object properties) in-place will not trigger updates

  • My UI is not updating / re-rendering, when it should be!

    • For arrays and object properties, see above (those are special, since Svelte's reactivity is based on assignment)
    • Other than making sure that variables are getting updated by assignment, other things to look for are:

      • Incorrectly setting up computed properties

        • If you have a computed value that you want refactored into a top-level function (e.g. getImagePath), when using it inside the template having something like <img src={getImagePath()} /> will actually result in stale values if props change.
        • The correct way is usually to use reactive declarations, with the $: prefix syntax. For a complicated computed value, you can use braces to replace a function
  • My on:{evt} is not working on a custom component!

    • To attach event bindings to a custom component, you must use event forwarding
    • For on:click, and other DOM events, this is as easy as putting an empty on:{evt} on the element you want to forward from in the child (demo)
  • My component binding is not working (e.g. bind:this={component_instance})

    • component_instance will be undefined until the component is mounted / rendered. You can wrap with the onMount() lifecycle hook if you are trying to access during initialization

VSCode / IDE Support

  • Prettier is not playing nice with my .svelte files!

    • If you are using the recommended VSCode extension (Svelte for VSCode), try putting your prettier config in .prettierrc, instead of any other method (for example, in .vscode/settings.json)

      • You can use svelteSortOrder to control tag order
    • There is also a dedicated Prettier plugin - prettier-plugin-svelte

      • This comes bundled with the language server / VSCode plugin
    • Here is how the VSCode extension resolves Prettier formatting
    • After making or updating .prettierrc file, run Svelte: restart language server)

TypeScript

Make sure you follow the official guide on how to get setup with TS (mainly just running the TypeScript setup scripts / ejector).

TypeScript - Issues

💡 Tip: When something simple seems like it should be working, and it isn't, try running Svelte: restart language server. This often fixes things

  • Error: Type annotations can only be used in TypeScript files.

    • Make sure you don't have an explicit file association for *.svelte files in any (local or global) vscode settings.json files.

      • If you find one, remove it, then reload the entire window
    • Try restarting the language sever with the cmd: Svelte: restart language server
  • Svelte files not picking up global types (e.g. declared through ambient *.d.ts files)

    • If the file was just created, try restarting the language server
    • Make sure you have actually saved updates to the file, not just modified it. Unlike VSCode's JS/TS type checking system, which will use "dirty" files (unsaved modifications), the Svelte extension requires the file to be saved.
  • Error: (plugin typescript) Error: Could not load ___.ts (imported by ___.svelte): Debug Failure. False expression: Expected fileName to be present in command line

    • This is actually an error from rollup, which is the default bundler shipped with Svelte. Usually this means that the file you are trying to reference was not noticed by the "watcher" (tends to happen with brand new files that were created after the watcher was started)
    • If you are running in watch mode, just restart (kill & then run dev)
Markdown Source Last Updated:
Sun Oct 04 2020 12:09:35 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Wed Sep 30 2020 03:51:18 GMT+0000 (Coordinated Universal Time)
© 2020 Joshua Tzucker, Built with Gatsby