Svelte 3 Under the hood
With the recent release of Svelte v3, it seemed a good time to dive under the hood and explain exactly what it is doing. For those that don’t know, Svelte is a js library that takes a very different approach than what I have used before. Let’s see how Svelte describes itself:
Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.
We are going to look at a simple compoment, and break down the code that is generated by Svelte.
Our first component
Svelte components are different to other frameworks, in that it combines the HTML, CSS and JS all in one file. Here is a simple hello world example:
Our component
1<script>
2 let name = 'world';
3</script>
4
5<h1>Hello {name}!</h1>
Despite its simplicity, we are going to break down exactly what it is.
1let name = 'world';
All we are doing here is declaring a variable name
with a default value of world
. Behind the scenes however, this becomes
a value that can be used throughout the Svelte component.
1<h1>Hello {name}!</h1>
Here, we have a standard h1
tag that is saying a friendly hello to the world. With this,
we now have a component that will automatically update the dom whenever name
changes.
To use this component, we would then simply make a new
instance of it and supply it with some options.
Component initialization
1new SimpleComponent({
2 target: '.simple',
3});
The target defines the location in the html to mount the component. There are many more options, but we will keep it simple for now.
Under the hood
Now that we have a component, let’s dive into what Svelte is doing with this component once compiled. It’s important to note that we may not dive into all of Svelte’s internal functions, instead focusing on the core components that make up our output.
Svelte output
1/* App.svelte generated by Svelte v3.2.2 */
2import {
3 SvelteComponent,
4 append,
5 detach,
6 element,
7 init,
8 insert,
9 noop,
10 safe_not_equal,
11 text
12} from "svelte/internal";
13
14function create_fragment(ctx) {
15 var h1, t0, t1, t2;
16
17 return {
18 c() {
19 h1 = element("h1");
20 t0 = text("Hello ");
21 t1 = text(name);
22 t2 = text("!");
23 },
24
25 m(target, anchor) {
26 insert(target, h1, anchor);
27 append(h1, t0);
28 append(h1, t1);
29 append(h1, t2);
30 },
31
32 p: noop,
33 i: noop,
34 o: noop,
35
36 d(detaching) {
37 if (detaching) {
38 detach(h1);
39 }
40 }
41 };
42}
43
44let name = 'world';
45
46class App extends SvelteComponent {
47 constructor(options) {
48 super();
49 init(this, options, null, create_fragment, safe_not_equal, []);
50 }
51}
52
53export default App;
Although this file may seem daunting, we will do our best to point out the genius simplicity of the output. Let’s focus on the imports first.
Generated imports
1import {
2 SvelteComponent,
3 append,
4 detach,
5 element,
6 init,
7 insert,
8 noop,
9 safe_not_equal,
10 text
11} from "svelte/internal";
One of the genius elements of Svelte is the use of it’s internal package. This allows for performant bundles
through the use of tree-shaking and code-splitting. These imports provide wide ranging functionality, from creating
HTML elements (element
) to doing… nothing (noop
).
Let’s jump down the end of the file, before we work through the more complex areas.
Generated class
1let name = 'world';
2
3class App extends SvelteComponent {
4 constructor(options) {
5 super();
6 init(this, options, null, create_fragment, safe_not_equal, []);
7 }
8}
Wait, that’s interesting. Our simple name
variable declaration has been almost copied over to the output.
This is another wonderful advantage to the Svelte 3 design. The use of standard JS syntax means our compiled code
can try it’s hardest to re-use as much as possible. The rest of this section is defining a simple class
, using the
filename as the class name. It extends from SvelteComponent
to get all of the required functionality, then implements
a simple constructor to initialize the component.
The options
argument of the constructor consists of the same arguments we passed in earlier.
1{
2 target: '.simple'
3}
With a more advanced component, this would contain the component’s properties and many other options. The init
function call
is doing all of the heavy lifting here. It will create our fragment, mount the component onto the page and a lot more.
The create_fragment
function is the last generated piece of code for our simple component. Let’s take another look at it.
Generated create_fragment
1function create_fragment(ctx) {
2 var h1, t0, t1, t2;
3
4 return {
5 c() {
6 h1 = element("h1");
7 t0 = text("Hello ");
8 t1 = text(name);
9 t2 = text("!");
10 },
11
12 m(target, anchor) {
13 insert(target, h1, anchor);
14 append(h1, t0);
15 append(h1, t1);
16 append(h1, t2);
17 },
18
19 p: noop,
20 i: noop,
21 o: noop,
22
23 d(detaching) {
24 if (detaching) {
25 detach(h1);
26 }
27 }
28 };
29}
Confusing, right? The purpose of this function is supply a bunch of helpers for managing our component. Let’s take a look at the first one and break down it’s purpose.
Generated constructor
1c() {
2 h1 = element("h1");
3 t0 = text("Hello ");
4 t1 = text(name);
5 t2 = text("!");
6}
Much easier to break down. We can see the content of our component being built up here.
A h1 tag, and our hello message. This function c
, is shorthand for create
.
Onto the next one:
Generated mount call
1m(target, anchor) {
2 insert(target, h1, anchor);
3 append(h1, t0);
4 append(h1, t1);
5 append(h1, t2);
6}
In this case, m
is shorthand for mount
. It’s simply inserting top level elements and building their node tree as expected.
We will skip p
, i
, and o
for this tutorial, due to them being unused. This means there is only one more piece of the code to look at!
Generated destroy call
1d(detaching) {
2 if (detaching) {
3 detach(h1);
4 }
5}
Again when looked at in isolation is quite self-explanatory. d
is for destroy
, and is called when the component is being destroyed. It
simply checks if it’s detaching, and calls detach. Simple!
That’s it! Obviously, the more complex the component the more complex the generated code. Hopefully this gives some insight into the underlying beauty of Svelte. If you want to read more, here are some helpful links to get you started: