I have a dream. I dream of a day when every line of code I write will be driven by a desire, not by necessity.

preface

The purpose of this article is to provide a simple answer: what are the improvements and optimizations of Vue3.0 compared to 2X?

There are three levels: performance, source code and new features.

Performance optimization

1. Tree-shaking technology is introduced to reduce packaging volume

As we all know, modules in ES6, when we introduce a Module, the Module is loaded as a whole and is packaged as a whole when it is built. Even if we only use one of these methods.

import { a } from './xxx.js' 
Copy the code

I just want to harvest a wisp of spring breeze, but you gave me the whole spring.

Tree-shaking marks unreferenced functions or objects at compile time and removes marked useless code at compression time, enabling on-demand packaging.

2. Optimized the data hijacking scheme and changed it from Object.defineProperty to Proxy Object

Object.defineproperty is known to have limitations. It listens for changes to a property on the object.

Object.defineProperty(data, 'a',{
  get(){
    // track
  },
  set(){
    // trigger
  }
})
Copy the code

Attention! It’s listening for some property. If you want to listen on objects, you need to hijack all the properties by looping through them. This inevitably imposes a performance burden and does not listen for additions and deletions of object attributes. This is what it says “Due to JavaScript limitations, Vue cannot detect array and object changes. “. Do you feel a sense of resentment… Ha ha 😁

As a direct result, the reactive formula fails in the following scenarios.

  • When adding or removing object properties
  • When an array item is set directly using an index
  • When modifying the length of an array

To solve this problem, Vue has to extend the Array object and provide additional set and \delete.

The emergence of Proxy shines a light on the responsive side of things, giving Vue a chance to make up for its “JavaScript limitations.”

Because it hijacks the whole object.

const target = { message1: "hello", message2: "everyone" }; const handler = { get: function(target, prop, receiver) { return "world"; }}; const proxy = new Proxy(target, handler);Copy the code

Are there any responsive generals? Here’s a little background music for Utah. Red high heels ^^ broken tone…

3. Compilation optimization

It is well known that the granularity with which data updates trigger rerendering in Vue2.0 is component-level. This is a significant performance improvement over React rerendering the entire component subtree (without using PureComponent and shouldComponentUpdate). But Utah thought that wasn’t enough. He could do better.

Vue3.0 designs the concept of blocks at compile time. It divides nodes into dynamic and static nodes according to whether there is responsive interpolation or not, and then only compares and updates the dynamic child nodes in the Block in the patch phase. In this way, unnecessary static node comparison is avoided and the performance of component update at run time is optimized.

In addition, an AST (Abstract syntax tree) was added during compilation. The process is roughly as follows: parse the template template to generate AST node objects, traverse the AST and conduct lexical analysis, improve the semantics and information of virtual nodes through various conversion functions, and finally generate the Render function for rendering VNode.

Compilation should be one of the most complex Vue source code, yoda also said, understand the principle of compilation can do whatever you want, interested children, recommended to see the wall crack Huang Yi teacher “vue.js 3.0 core source code analysis”. One word: hardcore.

The source code level

1. Better source code organization

Vue3.0 uses monorepo to manage project code. Let’s get a feel for the directory structure…

/ / 2 x ├ ─ ─ the SRC │ ├ ─ ─ the compiler / / template compilation related │ ├ ─ ─ the core / / has nothing to do with the platform of general runtime code │ ├ ─ ─ platforms / / platform proprietary code │ ├ ─ ─ server / / server rendering │ ├ ─ ─ SFC / /. Vue single file parsing │ └ ─ ─ Shared/code/Shared toolsCopy the code
/ / 3. X ├ ─ ─ packages │ ├ ─ ─ the compiler - core │ ├ ─ ─ the compiler - dom │ ├ ─ ─ the compiler - SFC │ ├ ─ ─ the compiler - SSR │ ├ ─ ─ global, which s │ ├ ─ ─ │ ├─ Running-core │ ├─ Running-dom │ ├─ Running-test │ ├─ Server-renderer │ ├─ Sie-Check │ ├─ Template-Explorer ├─ ├─Copy the code

Is there a more granular, explicit module division? In fact, the main benefit of Monorepo is unified workflow and code sharing. Some packages in the Vue3.0 source code can be run independently, such as the ReActivity reactive library.

Develop with TypeScript

There’s nothing to say. It’s a win-win-win. Vue takes advantage of TypeScript’s trend; TypeScript adds a new player to its empire; We ordinary people, save the trouble of maintaining.TS. Really want to key three even ah… [the head 👏]

I don’t use TypeScript very much and don’t have a deep understanding of it. Wish TypeScript a long life and remember how good it is:

  • Explicit typing makes our code more readable and robust;
  • Static type detection can help us avoid a lot of type-induced errors;
  • It helps IDE derive variable types to provide precise and effective code hints.

New features

1. Compound apis

If you can trace it back to “Hello Vue!” To start.

var app = new Vue({ el: '#app', data: { message: 'Hello Vue! '}})Copy the code
Hello Vue!
Copy the code

We have successfully created our first Vue application! Everything is responsive!”

To this day, I can still feel the overwhelming pride and joy. It is hard to realize this without experiencing the era of JQ. But that doesn’t stop us from having the same first impression: simple and intuitive.

Developing pages by configuration is clearly more intuitive and has earned Vue a reputation for being “easy to use”. It was also one of the main reasons why it quickly rose to prominence and then took the front-end world by storm.

But… All the gifts of fate have already marked the price in the dark, this is a price.

As components become more and more functional and complex, the Options API approach leads to a fragmentation of logical concerns, which makes it difficult to understand and maintain components. This example of a large component is shown in the official documentation. The logical concerns are grouped by color.

To solve this problem and enable us to configure code related to the same logical concern together and reuse logic, the composite API was born.

To get straight to the answer, here is the code refactored through the composite API.

// src/components/UserRepositories.vue
import { toRefs } from 'vue'
import useUserRepositories from '@/composables/useUserRepositories'
import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
import useRepositoryFilters from '@/composables/useRepositoryFilters'

export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: { type: String}},setup(props) {
    const { user } = toRefs(props)

    const { repositories, getUserRepositories } = useUserRepositories(user)

    const {
      searchQuery,
      repositoriesMatchingSearchQuery
    } = useRepositoryNameSearch(repositories)

    const {
      filters,
      updateFilters,
      filteredRepositories
    } = useRepositoryFilters(repositoriesMatchingSearchQuery)

    return {
      // Because we don't care about unfiltered warehouses
      // We can expose the filtered results under the name 'Repositories'
      repositories: filteredRepositories,
      getUserRepositories,
      searchQuery,
      filters,
      updateFilters
    }
  }
}
Copy the code

Let’s ignore the setup and toRefs syntax, which is a bit strange, and just look at the structure. As you can see, it abstracts part of the component logic into reusable chunks, breaking them into three Composables, and then installs the function points in between into the parent component in a unified manner, based on the principle of “logic correlation.” The code structure and running logic are clear and clear, and the problem of scattered logical concerns is gone forever.

At the same time, it also completes the logic reuse below the component level. Before that, when logic was scattered in data, computed, methods, filters… We want to reuse, usually through mixins. The disadvantages of mixins are obvious. Firstly, we cannot pass any parameters to a mixin to change its logic, which reduces its flexibility in abstract logic. In addition, when there are multiple mixins in a component, there is the problem of variable overwriting and unknown source of data.

This section is a bit long, so let’s conclude: Compound apis are a new way to organize code by logical concerns, and they help us better aggregate and reuse code logic.

2.Teleport

Teleport is a built-in component added to 3.0 that allows you to specify which DOM node to mount component elements to. For those scenarios where some elements of a component need to be placed outside the component node or even outside the Vue app.

Here is an example of a full-screen modal window

// vue app.component('modal-button', { template: ` <button @click="modalOpen = true"> Open full screen modal! (With teleport!) </button> <teleport to="body"> <div v-if="modalOpen" class="modal"> <div> I'm a teleported modal! (My parent is "body") <button @click="modalOpen = false"> Close </button> </div> </div> </teleport> `, data() { return { modalOpen: false } } }) // css .modal { position: absolute; top: 0; right: 0; bottom: 0; left: 0; Background - color: rgba (0, 0, 5); display: flex; flex-direction: column; align-items: center; justify-content: center; } .modal div { display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: white; width: 300px; height: 300px; padding: 5px; }Copy the code

The.modal node is mounted to the body specified by props to.

The syntax is simple, the function is direct, can say not much. It’s just that this component is so elegantly named, you know, Teleport.

Segments of 3.

As you know, a 2.0 template must have one and only one root node. Otherwise, the program will report an error:

The template root requires exactly one element

<template> <div> <header>... </header> <main>... </main> <footer>... </footer> </div> </template>Copy the code

3.0 has been improved to eliminate this limitation. Support for multi-node components is officially referred to as fragmentation.

<template> <header>... </header> <main v-bind="$attrs">... </main> <footer>... </footer> </template>Copy the code

At this point, some students will ask, why can’t 2.0 do 3.0?

Remember that the granularity of data updates in Vue2.0 that trigger rerendering is component-level? Vue uses this root node to limit the diff to a component to improve the efficiency of comparing old and new DOM and thus improve rendering performance.

This advantage is still there in 3.0, but the AST is always created at the end of the Template parsing process after the AST is introduced. The virtual root node can perform the same function so that an explicit root node is no longer necessary.

conclusion

The above is the answer given by the poor students after reading and thinking, which is filled with a lot of subjective personal understanding. If there is bias, welcome to correct.

The resources

  1. Vue3 Chinese document

  2. Deep into the responsivity principle

  3. Vue. Js 3.0 Core Source Code Analysis by Huang Yi

  4. Monorepo – Code management for large front-end projects