Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leverage types for perf improvements #418

Closed
Rich-Harris opened this issue Mar 28, 2017 · 18 comments
Closed

Leverage types for perf improvements #418

Rich-Harris opened this issue Mar 28, 2017 · 18 comments
Labels
compiler Changes relating to the compiler perf

Comments

@Rich-Harris
Copy link
Member

Moving #415 (comment) into its own issue.

There are certain places where Svelte could use type information to generate more compact or efficient code.

The big win is probably in recompute (formerly applyComputations) where we can shortcut the conditional that determines whether a given computed value's dependencies may have changed. There are other cases as well, e.g. this...

<div class='{{foo}} {{bar}}'></div>

...results in this code...

var div = createElement( 'div' );
div.className = "" + ( root.foo ) + " " + ( root.bar );

...which could easily become this, if we had confidence that foo was a string:

var div = createElement( 'div' );
div.className = root.foo + " " + root.bar;

(The unnecessary parens are a separate matter — they're included defensively but unnecessarily in most cases. A minifier can see to those though, whereas it can't remove the leading "" +).

The easiest way to get the type information would be to analyse the template — if {{a.b}} is encountered we know a is non-primitive, if {{a()}} is encountered we know it's a function, and if {{#each a as x}} is encountered we know a is array-like. (Or rather, we know that the component would fail anyway if those assumptions proved incorrect, in which case we lose nothing by making the assumption.)

There are other bits of static analysis we could do but they are far less straightforward and probably prone to uncertainty, which we should avoid.

We could also allow users to specify type information:

<script>
  export default {
    data () {
      return {
        foo: couldBeAnything,
        bar: couldAlsoBeAnything,
        baz: whoKnows
      };
    },

    types: {
      foo: Object,
      bar: Array,
      baz: String
    }
  };
</script>

This would only be used for SA, and removed from the compiled output. In dev mode, we could add warnings if the wrong type is supplied.

Finally, it might be possible to use Flow to more sophisticated type inference. No idea how that would work in practice though.

@PaulBGD
Copy link
Member

PaulBGD commented Mar 28, 2017

I don't think we should add flow built-in to Svelte, but instead add an API for specifying type of JavaScript to transpile (ex flow, typescript, coffeescript) and then allow setting data types.

@alexcorvi
Copy link

I highly recommend TypeScript if you're going in this direction. It has mature echo system and well-designed syntax.

Moreover, it has been designed by Anders Hejlsberg (the creator of C# lang) and being maintained by Microsoft. It's being used by Microsoft (for Visual Studio Code and a bunch of other projects) as well as Angular and other open source popular projects.

@Ryuno-Ki
Copy link

Flow has a feature called „library definition ”, where you can add type information outside the code base.

Concerning TypeScript I'd like to quote Eric Elliot from The shocking secret about static types

I worry about building up a large codebase using TypeScript, only to have the ECMAScript spec introduce conflicting keywords and type features such as interface and implements.

The advantage of using the TypeScript compiler is that even if that happens, you can just compile away the differences. The disadvantage is that you’re not really writing standard JavaScript anymore. I predict that TypeScript won’t be able to maintain its position as a superset of JavaScript. I believe it will inevitably diverge over the years.

@alexcorvi
Copy link

alexcorvi commented Mar 29, 2017

@Ryuno-Ki You can do the same thing in TypeScript, it's called declaration files. Have a look at Definitly Typed it's a huge repository of type declarations for packages that are written in pure javascript.

@PaulBGD
Copy link
Member

PaulBGD commented Jul 11, 2017

This came up when I was looking at how to solve #58, basically if we know the types at compile time then we can generate 100% correct type definitions for tools like typescript, flow, and (most importantly) closure-compiler. This also means that we can add dev mode warnings for setting/getting a property from the state that doesn't exist, which can catch mistakes like this.get('boo'). My suggestion on how to do this is to define type as either strings, or importing constants from svelte (I prefer strings):

export default {
  types: {
    foo: 'string',
    bar: 'number',
    complex: 'object'
  }
}

I also have the personal belief that we should keep it simple and use 'object' to represent functions, symbols, and other fun types. One thing we could do if we ever add typescript/flow support is only use this syntax for javascript and let typescript/flow handle types themselves.

@Rich-Harris
Copy link
Member Author

I believe Babylon will be getting TS support soon. Maybe if that happened, we could allow people to write either Flow or TypeScript, and people could use real types?

<script language='typescript'>
  import { Options } from 'svelte';

  interface Data {
    foo: string;
    bar: number;
    complex: object;
  };

  export default <Options>{
    data() {
      return <Data>{
        foo: 'x',
        bar: 42,
        complex: {
          x: 'y'
        }
      };
    }
  };
</script>

@PaulBGD
Copy link
Member

PaulBGD commented Jul 11, 2017

That's actually a bit of a complication, you can't enforce exporting a type in typescript (and flow too I think..) One way you could solve that is by wrapping the object like

import svelte from 'svelte';

interface DataType {
  foo: string;
  bar: number;
  complex: MyCustomType;
}
export default svelte<DataType>({
  data() {
    return {
      foo: 'x',
      bar: 42,
      complex: new MyCustomType()
    }
  }
})

It also doesn't solve the issue of jsdoc since microsoft/TypeScript#10 isn't finished yet. I also suppose if we do it this way then we can follow the pattern of continuing to deny JavaScript compile time types.

@Rich-Harris
Copy link
Member Author

I don't think we'd need the export to have a type — that would just be for the user's benefit, so that they'd get autocomplete when they start typing oncr... etc. All we'd need to do (he said confidently!) is extract the type information for the data function's returned value.

I also suppose if we do it this way then we can follow the pattern of continuing to deny JavaScript compile time types.

Good point — would be nice to have a non-TS/Flow approach as well, i.e. the types property you outlined above. My thinking is that you could use types, interface, or whatever the Flow equivalent is (literally no idea) and they would all get converted to the same thing internally — then we could offer a choice between outputting the appropriate JSDoc comments or preserving the TS/Flow for the user to deal with themselves.

@PaulBGD
Copy link
Member

PaulBGD commented Jul 11, 2017

I'm still very partial to representing svelte as a function to TS/flow, because they think that the file is exporting a literally object, but it's actually exporting a full component. By wrapping the object in a function call (that happens at compile time technically) everything works smoothly in the typed world.

@Rich-Harris
Copy link
Member Author

Ah, think I understand you now. Can TS/Flow understand <script> tags inside HTML files in the first place though? I'd be surprised if either knew what to do with import Foo from './Foo.html'.

@PaulBGD
Copy link
Member

PaulBGD commented Jul 11, 2017

It depends on the editor, IntelliJ/WebStorm seem to do it well (but they implement IDE features themselves instead of using typescript's.)

@Rich-Harris
Copy link
Member Author

Interesting. Will have to try them sometime.

@PaulBGD
Copy link
Member

PaulBGD commented Jul 11, 2017

With microsoft/TypeScript#6508 in theory we could extend the typescript compiler to add support for svelte though, but that's probably another issue.

@tomcon
Copy link

tomcon commented Nov 28, 2017

Looks like there has been movement within Typescript here which may help Svelte:
https://medium.com/the-vue-point/upcoming-typescript-changes-in-vue-2-5-e9bd7e2ecf08
microsoft/TypeScript#14141

@PaulMaly
Copy link
Contributor

@Rich-Harris Moving from pure JS to Typescript of the whole team and an in-progress project, is a big deal, actually. But simple, zero-config, type-checking is a very needful thing.

I propose this simple approach:

rollup.config.js

svelte({
    ...
    typeChecking: true
    ...
})

After it enabled, Svelte would check default values and will check state changes to have same types. If not, Svelte will produce a warning.

{qux} <!-- could be Any type --> 
<script>
  export default {
    data () {
      return {
        foo: '', // should be a sting
        bar: false, // should be a boolean
        baz: [] // should be an array 
      };
    }
  };
</script>

This's simplest approach without hitting new props or langs.

@stalkerg
Copy link
Contributor

I totally agree with @PaulMaly , optional type checking will be awesome. Typescript or die it's not an argument.
But we should think about "store" too.

@YogliB
Copy link

YogliB commented May 22, 2020

Are the any plans for this issue?

Smething like React's PropTypes can be nice (not sure about the implementation...

@benmccann benmccann changed the title Types Leverage types for perf improvements Jun 10, 2021
@pngwn pngwn added compiler Changes relating to the compiler temp-stale and removed triage: rfc-1 labels Jun 26, 2021
@dummdidumm
Copy link
Member

Closing as most of the discussion predates Svelte 3, so the thoughts on performance improvements are out of date by now. Regarding type-checking, there's good support for TypeScript now, and it's also possible to leverage JSDocs to do type checking without transitioning to TypeScript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler Changes relating to the compiler perf
Projects
None yet
Development

No branches or pull requests