sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.55k stars 4.12k forks source link

Whole-app optimisation #1102

Open Rich-Harris opened 6 years ago

Rich-Harris commented 6 years ago

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!

tivac commented 6 years ago

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.

Rich-Harris commented 6 years ago

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.

arxpoetica commented 6 years ago

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

Rich-Harris commented 6 years ago

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

thgh commented 6 years ago

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

nolanlawson commented 6 years ago

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

Just some random ideas. :)

benmccann commented 4 years ago

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

swyxio commented 3 years ago

linking related issues:

stale[bot] commented 2 years ago

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.

Azarattum commented 5 months ago

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