vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.36k stars 8.28k forks source link

Replace vue-template-compiler with babel-macros #3539

Closed revyh closed 3 years ago

revyh commented 3 years ago

What problem does this feature solve?

The main problem that I'm trying to solve here is that SFC's are not valid javascript. It complicates the ecosystem a lot. You can't just use a tool like webpack, jest, eslint, or prettier. You have to either install and configure some integration or make such integration yourself. And I suspect (without evidence though) that these integrations cause waste of computation resources because each of them runs vue-template-compiler under the hood.

The illustrative example in my opinion is typescript integration. Because tsc doesn't type check files with extensions other than js/ts/jsx/tsx/json, we can't make proper integration with typescript itself. And we have to create typescript integration for webpack (fork-ts-checker-webpack-plugin), for an editor (vetur, volar), and for CI (vetur, vue-tsc). So, in order to properly integrate vue with just typescript developers should install and configure at least: webpack-fork-ts-checker-plugin, vue-tsc, vue-dst, vetur. But still, all these packages won't provide such a smooth experience with typescript as react does. That's especially daunting considering all the hard work the core team invested in rewriting v3 using typescript.

What does the proposed API look like?

The idea is to ship the template compiler in a form of a tagged template, let's say tmpl. This tmpl tagged template comes in two forms: real tagged template for runtime compilation and babel-macros for build time compilation (like graphql or css-in-js solutions do). So, it will look something like this

// App.ts
import { defineComponent, tmpl, ref } from 'vue';
import CustomButton from './CustomButton';

export default defineComponent({
  name: 'App',
  components: {
    CustomButton,
  },
  props: {
    name: { type: String, required },
  },
  setup() {
    const counter = ref(0);
    const increment = () => counter.value = counter.value + 1;
    const decrement = () => counter.value = counter.value - 1;

    return {
      counter,
      increment,
      decrement,
    };
  },
  render: tmpl`
    <h1>Hello {{ name }}!</h1>
    <div>
      Here is your counter: {{ ref }}
      <custom-button @click="increment">+</custom-button>
      <custom-button @click="decrement">-</custom-button>
    </div>
  `,
})

Pros of this approach:

This idea seems straightforward to me and I believe that someone else has already proposed it, but I can't find any issues or other public discussion about this. This may mean that I have missed something important, something that negates all the possible benefits. For example, we may need to provide some solution for css as well to ensure feature parity with SFC. So, I would be glad to hear what others think about this.

yyx990803 commented 3 years ago

Now back to your proposal: what makes you think it'd be a good idea to throw away all the work around SFC and essentially re-invent the framework? Consider the cost of implementing what you proposed, re-educating users on how to write in a new syntax, configuring the new build setup (btw in Vite-based setups Babel is rarely needed rather than a requirement), and updating documentation... do you realize how much work that is, and the level of ecosystem fragmentation it implies?

AND most importantly, in your proposal Vue templates are inlined as JS strings. Note Vue templates are not like template-string-based solutions where expressions are embedded and enjoy intellisense automatically (e.g. lit-html) - we'd have to now hack the other way around to provide template intellisense in JS strings instead of in SFCs (which is XML at the top syntax level). I just don't see how this actually makes things any easier.

Getting SFC to the point where it is wasn't easy (which seems to be the main point of the proposal), but the work has already been done. It already works. For end users, it's just a matter of providing best practices and scaffolds to make things work out of the box. That's 100x easier than what you are proposing here.

For those who prefer a "just JS/TS" experience, just use TSX with Vue 3. It also already works and fits most of what you want.