· 12 min read

Svelte Summit 2020 Takeaways

This article was auto-translated from Chinese. Some nuances may be lost in translation.

Introduction

Svelte is one of my favorite frontend frameworks. I really love its simple syntax, flexibility, the creator’s philosophy, and how animations and transitions are handled. I’ve previously written several posts sharing my thoughts on Svelte:

Svelte Summit took place on October 18, 2020. Due to the pandemic, it was held entirely as a live stream, totaling 7 hours and 17 talks. Here are my notes on some of the talks I found interesting, along with my own thoughts.

The Zen of Svelte

This talk explores the various “philosophies” embedded within Svelte, whose design shares similarities with the Zen of Python.

Svelte approaches things from a syntax perspective, minimizing the learning curve as much as possible so that even non-frontend developers or complete beginners can pick it up easily. You can catch a glimpse of this from the official documentation: alongside the tutorial text, there is a REPL right next to it where you can directly tweak the code and observe the live results.

Svelte official tutorial documentation

The creator, Rich Harris, once mentioned in his talk Rethinking Reactivity:

Rich Harris - Rethinking reactivity

Frameworks are not tools for organizing your code, frameworks are tools for organizing your mind. — Rich Harris

For instance, the emergence of React revolutionized frontend development with concepts like Components, Immutability, Reactivity, and State. Many subsequent frameworks were built upon this foundation, completely transforming frontend development paradigms. More important than a framework’s “syntax” itself are the concepts and design philosophies it aims to convey.

Rich also mentioned that the advent of tools like jQuery allowed people like him—who didn’t come from a CS or programming background—to become part of web development. This gives us a good look into his vision for Svelte.

Note: I discussed more about this in this article; feel free to check it out if you’re interested.

harris-jquery

If you know HTML, CSS, and JavaScript, you know Svelte—and vice versa. Unlike traditional template engines, Svelte compiles differently. Template engines often pair with a backend, passing variables into the template engine to produce HTML strings. In Svelte, all your code is compiled into corresponding JavaScript (in non-SSR mode) and can be executed dynamically.

I love this philosophy: writing code doesn’t mean you have to become a software engineer, just like cooking doesn’t mean you have to be a chef. Sometimes, you just want to solve an everyday problem yourself.

From another angle, some might ask: is it a good idea to skip JavaScript fundamentals and learn Svelte directly? My answer is: “It depends on your goal.”

If your goal is to become a qualified frontend engineer, then at some point you inevitably need to understand the underlying mechanics. But if you just want to build a webpage to solve your own problems, it doesn’t matter if you lack deep fundamentals.

The talk also mentioned the article The Zen of Just Writing CSS. In Svelte, you can write styles directly inside the component, bringing HTML, CSS, and JavaScript together in one place. Svelte hashes the styles for you, effortlessly avoiding naming collisions. In React, we often use CSS-in-JS solutions to avoid these issues, but is there a better way to approach styling?

For example, in styled-components, we can write:

const Component = styled.div`
  padding: ${props => props.padding}px;
`

// 搭配 theme
const ThemeComponent = styled.div`
  background-color: ${props => props.theme.mainColor};
`;

This is a very convenient and interesting approach. We can define a theme in the context and dynamically access it when declaring components. However, precisely because of dynamic declarations, these styles must run at runtime since there’s no way to know in advance what props might be passed in, meaning styles can’t be generated entirely statically.

In Svelte, however, you can directly render a separate stylesheet via SSR:

result: {
	js,
	css,
	ast,
	warnings,
	vars,
	stats
} = svelte.compile(source: string, options?: {...})

Styles declared in a component are extracted into css, neatly separating styles from logic. Honestly, whether this is good or bad is subjective—for things like shared constants for colors or fonts, it might not be as convenient as styled-components.

Prototyping with Svelte

Svelte’s built-in directives like transition and animation are extremely handy, allowing even designers to quickly build prototypes to validate ideas. With the REPL, you can quickly see the results. Highly recommended for designers who want to prove engineers wrong when they say “it can’t be done.”

How does Svelte’s crossfade function work

crossfade is a very useful transition. What is crossfade? It’s when an element animates its movement between two different containers/locations.

In this talk, the speaker explains how crossfade is implemented in Svelte and how it is actually used in their product.

crossfade itself leverages the concept of keys in Svelte. Each time it runs, it locates nodes with matching keys, calculates the relative positions between them, and applies a transition animation. Because it can be applied via Svelte’s built-in transition directive, it is remarkably easy to use. (Example from the official tutorial)

Svelte Animation

Svelte has a built-in directive called animate. When using an each loop, if elements within the list change, animate is triggered. It is used like this:

{#each list as item (item.id)}
  <div animate:flip>
    ...
  </div>
{/each}

Svelte comes with a built-in animation called flip, which stands for First, Last, Invert, Play—a classic animation technique. First, we record the element’s position before and after the change (First, Last), then calculate the difference between the two (width, height, offsets, etc.), and finally play the animation. For more details, check out the Tech Bridge article — FLIP Technique Review.

Svelte wraps this entire series of calculations into flip ready out-of-the-box. When paired with crossfade, it looks like this:

Every movement has a transition, which feels so much smoother, right?

Unlocking The Power of Svelte action

This talk covers action in Svelte, which feels somewhat like hooks. In Svelte, you can write:

<div use:keyboard={{shortcut}} class="player-container">
</div>

Here, use is the Svelte action directive. The subsequent keyboard is a custom function with a signature like:

function keyboard(node, options) {}

This function can return an object containing update and destroy, representing the update function when parameters change and the cleanup function executed when destroyed, respectively. Because the first argument is the DOM node itself, performing DOM-related operations is extremely convenient.

The speaker shares their experience using Svelte Actions in the video—definitely worth watching.

Demystifying Svelte Transitions

This talk explains how Svelte Transitions are implemented, breaking down the source code step by step. It’s fantastic! Svelte’s transition mechanism is very interesting—it doesn’t rely on dynamic JavaScript manipulation throughout the animation.

When using animations in jQuery, jQuery adds inline styles to elements based on the parameters you provide, like:

$('.div').animate({
  ...
})

jQuery continuously updates inline CSS properties until the animation stops. In other words, the internal implementation looks roughly like this (pseudocode):

while (!stop) {
  updateCSS()
}

setTimeout(() => stop = true, duration);

This means JavaScript runs code continuously throughout the duration, which noticeably impacts performance as the application grows larger.

How do conventional frameworks implement this? In Vue and React, you can write:

// vue
<transition name="fade">
    <p v-if="show">hello</p>
</transition>

// React
<CSSTransition in={inProp} timeout={200} classNames="fade">
  <div>
		
  </div>
</CSSTransition>

Vue injects corresponding class names like fade-leave-active, fade-enter-active, and fade-enter at appropriate timings; React follows a similar principle, injecting class names like fade-enter, fade-active, fade-exit, and fade-exit-active. However, the transition itself must be defined in CSS by you.

While this avoids performance issues caused by JavaScript calculations, doing animations purely in CSS can sometimes be cumbersome. Is there a way to combine the dynamic calculation power of JavaScript with the performance benefits of CSS animations? Yes! Svelte achieves this.

When you declare the following code:

<div transition:scale={{duration: 1000}}>
</div>

Svelte does several things:

  1. transition means the same transition behavior is applied to both intro and outro.
  2. Svelte calculates how many frames are needed for this animation. Assuming the duration is 1000ms, the calculation is 1000 / 16, which is 62.5 frames. Here, 16 is used because at a 60Hz refresh rate, each frame takes approximately 16ms (1000 / 60).
  3. Svelte treats the start of the animation as 0 and the end as 1, using the variable t, and applies an easing function to interpolate t.
  4. Svelte dynamically creates a CSS @keyframes rule and applies this animation to the element.
  5. It dynamically injects the style into the current document using stylesheet.insertRule.

Let’s look at the source code:

// src/runtime/internal/style_manager.ts
export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b: number, duration: number, delay: number, ease: (t: number) => number, fn: (t: number, u: number) => string, uid: number = 0) {
	const step = 16.666 / duration;
	let keyframes = '{\\n';

	for (let p = 0; p <= 1; p += step) {
		const t = a + (b - a) * ease(p);
		keyframes += p * 100 + `%{${fn(t, 1 - t)}}\\n`;
	}

	const rule = keyframes + `100% {${fn(b, 1 - b)}}\\n}`;
	const name = `__svelte_${hash(rule)}_${uid}`;
	const doc = node.ownerDocument as ExtendedDoc;
	active_docs.add(doc);
	const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = doc.head.appendChild(element('style') as HTMLStyleElement).sheet as CSSStyleSheet);
	const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});

	if (!current_rules[name]) {
		current_rules[name] = true;
		stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
	}

	const animation = node.style.animation || '';
	node.style.animation = `${animation ? `${animation}, ` : ``}${name} ${duration}ms linear ${delay}ms 1 both`;

	active += 1;
	return name;
}

When this function executes, it generates CSS similar to the following:

@keyframes __svelte__dynamic_hash_name {
  0% {
    transform: scale(0);
  }
  1.6% {
    transform: scale(0);  
  }
  ...
  100% {
    transform: scale(1);
  }
}

The above is illustrative code; the actual output depends on the duration and easing function. Svelte not only creates the transitions for you, but it also manages them. For instance, if a transition is interrupted halfway through, Svelte removes the animation, halts it, and manages the various lifecycle states for you.

This achieves the performance of CSS animations while retaining the flexibility of dynamic JavaScript control.

If you’d like to learn more, definitely watch the video—the speaker explains it brilliantly!

Futuristic Web Development

Rich Harris himself takes the stage to talk about the evolving workflows of next-generation web development. However, none of this was finalized at the time, so take it with an open mind and a sense of excitement.

Traditionally, we bundled assets using tools like Rollup or Webpack, updating them through their dependency tracking mechanisms. The bottleneck back then was that browsers generally didn’t understand ES6 syntax or import mechanisms, so these tools emerged to help developers better manage their code. Now that browser support has matured, more and more applications rely directly on native ES Modules. For example, recent tools like VuePress and Snowpack run directly on native ES Modules. The biggest advantage is that we no longer need to wait so long to see changes; modules are imported directly via browser mechanisms, eliminating the need to wait for bundlers to compile everything. Svelte also plans to adopt snowpack in the future—worth keeping an eye on!

Afterword

For this year’s iT Home Ironman Contest, I recorded a series of tutorial videos on Svelte, covering its various features, advanced patterns, common UI implementations, Svelte’s inner workings, and finally building a simplified version of Svelte from scratch. Feel free to check it out if you’re interested.

I will also be adapting the video content into articles for easier reading later on, so stay tuned to my blog or subscribe to the RSS feed directly!

Related Posts

Explore Other Topics