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

Performance of templates vs render functions #1936

Closed
betweenbrain opened this issue Jan 14, 2019 · 7 comments
Closed

Performance of templates vs render functions #1936

betweenbrain opened this issue Jan 14, 2019 · 7 comments

Comments

@betweenbrain
Copy link
Contributor

Render Functions & JSX: Basics states that templates are recommended in the majority of cases. I understand that templates are compiled to render functions. Evan’s keynote at VueConf Toronto 2018 got me wondering about the performance of using templates vs render functions and even to JSX. More specifically, Even discussed how the Vue template compiler optimizes code, and that in Vue 3.0, it should further be optimized by the compiler. It would be great to document if there are any performance gains of using over.

@AlbertMarashi
Copy link

Warning: Just my opinion

I'd expect that render functions are generally faster in more scenarios since everything is manually created with no overhead, whereas, with templates, they need to be compiled and won't be as optimised as render functions in some cases, as additional overhead may be included.

But Vue 3's template compiler should be getting tonnes of new optimisations. I don't think it matters much in any real-life cases, so just use what's easier to maintain and develop.

@betweenbrain
Copy link
Contributor Author

Thanks for the response @DominusVilicus. I have been doing some preliminary performance testing of templates vs JSX, with Vue v2.5, and so far the results generally support your conclusion that it may not matter much in real-life scenarios. I suspect that Vue 3's optimizations may make templates more performant for larger, complex applications, but that's just a guess.

@LinusBorg
Copy link
Member

LinusBorg commented Jan 22, 2019

I'd expect that render functions are generally faster in more scenarios since everything is manually created with no overhead, whereas, with templates, they need to be compiled and won't be as optimised as render functions in some cases, as additional overhead may be included.

As long as we talk ab out a template and a render function doing the same thing, the opposite is the case, pretty much.

  1. Yes, if you compile termplates at runtime, they come with a one-time overhead. But with .vue files, you do that work during compile time (like for JSX), so the runtime doesn'T have any negative effect by this.
  2. Static analysis during compile time allows us to produces optimized render functions. In Vue 2, this mainly means we extract static parts of the element tree so we don't re-render them over and over. In Vue 3, we will do much more than that, i.e. optimize calls for component vs. element vnode creation, elements that can or can't have children etc.

It may of course be the case that in specific situations, you can write a more perfomant render function because of the dynamic nature of JSX. But for the bulk of the usual markup that you have to create, the render functions from .vue files will be faster than their hand-written counterparts.

How much faster? To be honest I personally don't know.

@betweenbrain
Copy link
Contributor Author

Awesome, thanks @LinusBorg!

@phanan
Copy link
Member

phanan commented Jan 27, 2019

@betweenbrain As your issue seems to have been clarified, I'm closing this. Feel free to open another if you think it's necessary.

@phanan phanan closed this as completed Jan 27, 2019
@onx2
Copy link

onx2 commented Jul 16, 2020

I know this is closed but Vue 3.x is in a more stable spot now so I'm curious if any opinions have changed or if there's any new information regarding performance between the two options.

I've been building a small component library to test out / learn Vue 3.x and would love to hear thoughts on just how optimized the templates can be vs manually writings render functions.

Let's take a simple example (hopefully these are identical, I haven't actually tested them):

Render function approach

import { defineComponent, h } from "vue"

export default defineComponent({
  name: "MyComponent",
  props: {
    someProp: {
      type: Boolean
    }
  },
  render() {
    const { someProp } = this.$props
    const { default: defaultSlot, slotOne, slotTwo } = this.$slots

    const child = h("span", { class: "inner" }, defaultSlot)

    return h(
      "div",
      {
        class: {
          "static-class": true,
          "some-class": someProp
        }
      },
      [slotOne && slotOne(), child, slotTwo && slotTwo()]
    )
  }
})

Template approach

<template>
  <div class="static-class" :class="{ 'some-class': someProp }">
    <slot name="slotOne" />
    <span class="inner">
      <slot name="default" />
    </span>
    <slot name="slotTwo" />
  </div>
</template>

<script>
import { defineComponent } from "vue"

export default defineComponent({
  name: "MyComponent",
  props: {
    someProp: {
      type: Boolean
    }
  }
})
</script>

This example may not be great... I'm just trying to determine if the improvements in the static analysis in Vue 3.x have improved the generated render functions beyond what someone could write manually, and / or if the convenience of using pure JS to handle complex user input is the only benefit to manually writing them.

I'm seeing in the Functional Components RFC that is pretty much pointless to write those now other than for simplicity... I wonder if this is related or can be used to extrapolate that templates are just the 💣 now?

Here's an actual component if it helps

import { defineComponent, h, mergeProps } from "vue"
import { RouterLink } from "vue-router"

import { validatePropFromEnum } from "../../utils"
import { Colors, Sizes } from "../types"
import "./styles.scss"

enum ButtonTypes {
  button = "button",
  submit = "submit",
  reset = "reset"
}

type Elevations = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7

export namespace OnyxButton {
  export type Props = {
    disabled?: boolean
    fill?: boolean
    flat?: boolean
    fab?: boolean
    type?: keyof typeof ButtonTypes
    color?: keyof typeof Colors
    size?: keyof typeof Sizes
    elevation?: Elevations
    href?: string
    to?: string
  }
}

export default defineComponent({
  name: "OnyxBtn",
  props: {
    fill: {
      type: Boolean
    },
    type: {
      type: String,
      default: ButtonTypes.button,
      validator: (prop: keyof typeof ButtonTypes): boolean =>
        validatePropFromEnum(prop, ButtonTypes)
    },
    disabled: {
      type: Boolean
    },
    fab: {
      type: Boolean
    },
    flat: {
      type: Boolean
    },
    color: {
      type: String,
      default: Colors.default,
      validator: (prop: keyof typeof Colors): boolean =>
        validatePropFromEnum(prop, Colors)
    },
    size: {
      type: String,
      default: Sizes.medium,
      validator: (prop: keyof typeof Sizes): boolean =>
        validatePropFromEnum(prop, Sizes)
    },
    elevation: {
      type: Number,
      default: 0,
      /** @todo Define a max elevation */
      validator: (prop: Elevations): boolean => prop <= 7 && prop >= 0
    },
    href: {
      type: String
    },
    to: {
      type: String
    }
  },
  render() {
    const {
      href,
      to,
      fill,
      flat,
      fab,
      type,
      color,
      size,
      elevation
    }: Readonly<OnyxButton.Props> = this.$props

    let component: any = "button"

    if (href && to) {
      console.error(`"href" and "to" props shouldn't be used together.`)
    } else if (href) {
      component = "a"
    } else if (to) {
      component = RouterLink
    }

    if (fab && fill) {
      console.error(`"fill" and "fab" props shouldn't be used together`)
    }

    return h(
      component,
      mergeProps(this.$props, {
        class: {
          button: true,
          [`button-${size}`]: true,
          [`button-${color}`]: true,
          [`button-elevation-${elevation}`]: true,
          fill: fill && !fab,
          fab,
          flat
        },
        type
      }),
      this.$slots
    )
  }
})

@ThinhVu
Copy link

ThinhVu commented Mar 19, 2021

My repo include some test cases about renderFn, template, computedVDOM stuff (all in vue 3).
https://github.com/ThinhVu/hello-vue3

I think using vue template is the best approach cause it reduce _createVNode function call a lot.

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

No branches or pull requests

6 participants