svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Whole-app optimisation

Open Rich-Harris opened this issue 7 years ago • 10 comments

I keep bringing this up as a thing-we-should-do but it's probably time we had an issue for it with specific ideas about what it means and how to get there.

I'll kick things off with a few ideas of things we could do:

Static properties

<!-- App.html -->
<Greeting name='world'/>

<!-- Greeting.html -->
<h1>Hello {{name}}!</h1>

Right now, this involves creating three separate text nodes inside the <h1> (which we could collapse into one — Scott Bedard had some good ideas in Gitter), and adding update code that waits for state.name to change. We could replace all that with

h1.textContent = 'Hello world!';

Static computed properties

As a corollary to the above, if you know the values of the inputs to a computed property, and know that the computed property function is pure, you can precompute the value.

Collapsing entire components

A 'component' is really two things — the main fragment, and the interface. In a lot of cases, such as the <Greeting> component above, we don't actually need the interface — we can statically determine that there are no lifecycle hooks or events, and no way that the user could get a reference to the component.

Optimising styles

Component-level unused style removal is cool, but if we had all your styles we could start to do Styletron-style optimisations.


Will add to this list as other things occur to me; please suggest others!

Rich-Harris avatar Jan 12 '18 20:01 Rich-Harris

This sort of fits in with the Static Properties section, but with modular-css-svelte I'm doing a really hacky thing to replace {{css.fooga}} reference with the modular-css output. It'd be pretty neat if static data replacements like that that were natively supported by the svelte compiler.

tivac avatar Jan 12 '18 20:01 tivac

Some half-baked thoughts on implementation:

The reason this is something of a tricky problem is that our tools are module-centric. The Svelte compiler operates on one component at a time, and module bundlers transform a single module at a time (the process of transformation from Svelte component/CSS file/whatever to JavaScript module, and the process of discovering the dependency graph, are linked — we generate JS, then we scan for import declarations).

Whole-app transformations do take place (minification and tree-shaking are two examples), but by the time we reach that stage, the deep knowledge of the structure of a component has been lost, and it's essentially impossible to go back and apply the aforementioned optimisations to the code that has already been generated.

I don't think Svelte is unique in this regard, and I sense that there's going to be a trend towards tools that operate more holistically. One idea I've been kicking around is changing Rollup's design so that graph discovery and transformation are separate:

function someCompiler(opts) {
  return {
    name: 'some-compiler-plugin-for-rollup',

    discover(code, id) {
      // ...the code is analysed...
      return {
        dependencies: ['./foo.js', 'Bar.html'],
        api: {
          reticulateSplines() {
            // this is a method that other modules could call in a later `transform`
            // function, to determine things about this module
          }
        }
      };
    },

    transform(code, id) {
      const capabilities = {};
      this.getDependents().forEach(module => {
        if (module.reticulateSplines()) {
          capabilities.reticulate = true;
        }
      });

      return compiler.compile(code, capabilities);
    }
  };
}

Example might be a bit abstract but you get the basic idea — we first do a discover pass, build the graph, then transform hooks are able to query their dependents to determine what capabilities the current module needs to expose.

(Existing plugins would continue to work — Rollup would just merge discover and transform, as it currently does.)

Meanwhile on the Svelte side, we would need to expose new functions that could do the necessary analysis ("draw the rest of the owl").

The nice thing about this is it's not a Svelte-specific solution. The bad thing is it is a Rollup-specific solution. (@TheLarkInn, feel free to ignore this but I'm tagging you in because we've talked about this briefly in the past and it's a place where bundlers should definitely be comparing notes.)


I was chatting to @guybedford about this stuff this week, and he had a suggestion that is a lot more down-to-earth: expose functions and let the treeshaker deal with it.

In other words, rather than not generating the update function for the {{name}} in the <Greeting> component above, we generate it but <App> doesn't import or call that function. I haven't quite wrapped my noggin around how that could work — it might not even be possible, and it's certainly less powerful (you couldn't generate h1.textContent = 'hello world!'), but it's definitely an appealing line of enquiry, given that treeshaking functions is something our tooling is getting pretty good at.

Rich-Harris avatar Jan 12 '18 21:01 Rich-Harris

Said this in Gitter, but posting here for convenience:

stuff like FOUC and time to render child components and CSS transitions comes to mind As far as a practical use case for app level optimization Also: preloading async optimization and general other loading stuff

arxpoetica avatar Jan 13 '18 00:01 arxpoetica

Relevant: https://twitter.com/tomdale/status/953365543213518848

Rich-Harris avatar Jan 17 '18 00:01 Rich-Harris

Only compute computed properties when used in view: https://svelte.technology/repl?version=1.54.1&gist=4faf8a9862d75b3dec0b3a6079051643

Only compute computed properties when accessed: https://svelte.technology/repl?version=1.54.1&gist=7b93771bb5f0e9eadb99051df0158c2d

Seems to work now, just a HMR bug? Only recompute computed properties which parameters have changed: https://svelte.technology/repl?version=1.54.1&gist=61200957976c77c4a7283f3788b33569

thgh avatar Feb 07 '18 10:02 thgh

In terms of whole-app optimization, some other ideas that spring to mind:

  • mangle veryLongPropNamesToWhichIAmPartial into a, b, c, etc
  • mangle method names, especially those used only inside the component (I do this all the time)
  • inline/flatten components when the child component isn't reused by multiple parents

Just some random ideas. :)

nolanlawson avatar Apr 18 '18 19:04 nolanlawson

I don't use animations anywhere in my app. It'd be nice if the animation code were not included in that case

benmccann avatar Aug 24 '20 15:08 benmccann

linking related issues:

  • collapsing <div> inside <p> across components https://github.com/sveltejs/svelte/issues/1686

swyxio avatar Jun 11 '21 14:06 swyxio

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Dec 23 '21 23:12 stale[bot]

Any chance we could see something like this in Svelte 5?

Azarattum avatar Apr 23 '24 04:04 Azarattum