Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell if a Svelte component is entirely static content?

I'm working on a static site generator where I'd like to be able to support both reactive JavaScript interaction and standard load-a-fresh-page-into-the-browser hyperlinks. It occurred to me that something like Svelte might be a good fit for this; I could use the server-side rendering support to generate HTML for all my pages, and then I could compile and ship JavaScript components with hydratable: true to support the dynamic features.

One issue I thought of with this approach is that most of my project's components will be entirely static content: just HTML and hyperlinks, without any state or event handlers, and I won't change the props except when I generate a new HTML file for a different page. If I naively generate JavaScript to hydrate all those components at page load time, I could end up with a much larger bundle (and more work done at runtime) than I actually need.

Does Svelte offer any way to optimize this situation? Can I somehow check if a component is a pure function of its props so I can avoid hydrating it if I don't need to? Or is the compiler smart enough to do that for me?

like image 453
Carter Sande Avatar asked Apr 28 '19 23:04

Carter Sande


1 Answers

This is a good question that we don't currently have a simple answer for.

It is possible to determine whether an individual component has values that can change — svelte.compile(...) returns an object with a vars property, which is an array of all the values inside the component. Inspecting this array will tell you which values are never reassigned to or mutated. (It won't tell you if a component has event handlers that have side-effects but which don't affect state, which would also be necessary to determine whether a component is entirely static. That's information that we could add in a future 3.x release.)

But it's only half the story. Consider a component that declares a name prop...

<script>
  export let name;
</script>

<h1>Hello {name}!</h1>

...and which is used in your app like so:

<Greeting name="world"/>

As far as the compiler is concerned when it compiles the <Greeting> component, the name value could change at any moment, so it's unsafe to treat it as entirely static. But if it could understand your app more holistically, it would be able to replace {name} with world, which would have various benefits.

When hydrating, Svelte assumes that there could be a discrepancy between the existing DOM and what's supposed to be there. In many situations it would be safe to assume otherwise, and skip checking subtrees it knew to be static, which would obviate the need to include them in the generated JS.

As a compiler, Svelte is unusually well-positioned to be able to take advantage of these techniques, but it's work that we haven't undertaken yet. Ideally we'll be able to upgrade the compiler in such a way that your apps will get smaller without anything needing to change. If you're keen to start experimenting with what's possible in the meantime, then the vars property returned from svelte.compile(...) (and also the ast property, I suppose) is the place to start.

like image 163
Rich Harris Avatar answered Sep 18 '22 03:09

Rich Harris