Recently I tried Vue3+TS+Vite. Compared with Vue2, I didn’t adapt to it, but it still smells good

Let’s talk about some changes to Vue3 before we get started

The change of Vue3

The changes brought by Vue3 mainly include the following aspects:

  • Use level
    • Compared with Vue2, the startup speed is much faster, and the new project is upgraded from 1s to less than 500ms
    • vite.config.tsThe configuration file can be updated without restarting the service
  • The code level
    • Functional programming, convenient combination of logic, such as mixin easy naming conflict, data source is not clear
    • newref.reativeAPI definition variables
    • bettertssupport
    • Component filetemplateThere is no need to wrap a root node tag around a component element within a template
  • The underlying design
    • Two-way data binding fromdefinePropertyChange the for in loop variable toproxy.definePropertyIs to change the original object attribute tag; whileproxyInstead of changing the original object, a new proxy object is generated, and the JS engine prefers stable objects
    • To redefine thevdomComparison of ideas:
      • Distinguish dynamic and static DOM, only compare dynamic data DOM, use block to mark static tags inside dynamic tags
      • Using the longest increasing subsequence algorithm, find all elements that do not need to be moved
    • Compile optimizes, putting a lot of computation into the Node layer, and the browser ends up executing the least amount of code

Underlying design changes made VUE3 faster than VUE2

Here’s how to get started.

Create a project

Use the vite command to create the initial project

# npm 6.x
npm create vite@latest my-vue-app --template vue

# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue

cd my-vue-app

npm install
npm run dev
Copy the code

Viteconfiguration

Most of the configurations with consistent functions are similar to vue-CLI configurations, but there are more details

resolve

Resolve. Alias: When using the alias of a file system path, always use an absolute path. Alias values for relative paths are used intact and therefore cannot be properly parsed.

Resolve: {"@": path.resolve(__dirname, "SRC "),}}Copy the code

Sass configuration

Install sass dependencies and configure viet.config. ts predefined global variables

npm i sass -D
Copy the code
/* vite.config.ts */ css: { preprocessorOptions: { scss: { additionalData: '@import "./src/assets/scss/var.scss"; '}}}Copy the code

Enabling Service Configuration

Enabling the HTTP Service

/* vite.config.ts */
server:{
    host: 'dev.moon.cn',
    port: 3000
}
Copy the code

Enabling the HTTPS Service

/* vite.config.ts */
let httpsConfig = {
  key: fs.readFileSync("C:/Users/ca/wps.cn/_wildcard.wps.cn+3-key.pem"),
  cert: fs.readFileSync("C:/Users/ca/wps.cn/_wildcard.wps.cn+3.pem")
};

server:{
    https: httpsConfig,
    host: 'dev.moon.cn',
    port: 443,
    open: true
}
Copy the code

Prebuild depends on optimization

By default, Vite will crawl your index.html to detect dependencies that need to be pre-built. If you specify the build. RollupOptions. Input, Vite, in turn, to go to grab the entry point.

optimizeDeps.include

By default, linked packages that are not in node_modules are not prebuilt. Use this option to force the prebuild of linked packages.

/* vite.config.ts */
optimizeDeps: {
  include: ['axios'],
},
Copy the code

optimizeDeps.exclude

Dependencies that are forced out of a prebuild.

Vue3 + TS

Vue3 has added a composition API that is more similar to react writing. Here is a brief introduction to vue3 and its life cycle

setup

A component option that is executed after the props is resolved before the component is created. It is the entry point to a composite API.

< Script Setup > is a compile-time syntactic sugar for using composite apis in single-file components (SFC). It has many advantages over plain

  • Less boilerplate content, cleaner code.
  • You can declare props and throw events using pure Typescript.
  • Better runtime performance (their templates are compiled into renderers of the same scope as them, without any intermediate proxies).
  • Better IDE type inference performance (less work for the language server to extract types from code).

To use this syntax, add setup attributes to the

<script setup lang="ts">
</script>
Copy the code

The code inside is compiled into the contents of the component setup() function. This means that instead of normal

setupFunction in terms of life cycle, it is inbeforeCreateCalled before the hook.

The life cycle

Mapping between the lifecycle options of the optional API and the composite API

  • beforeCreate– > usesetup()
  • created– > usesetup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeUnmount -> onBeforeUnmount
  • unmounted -> onUnmounted
  • errorCaptured -> onErrorCaptured
  • renderTracked -> onRenderTracked
  • renderTriggered -> onRenderTriggered
  • activated -> onActivated
  • deactivated -> onDeactivated

TIP: Because setup runs around beforeCreate and Created lifecycle hooks, you don’t need to explicitly define them. In other words, any code written in these hooks should be written directly in the Setup function.

Responsive ref

Takes an internal value and returns a reactive and mutable REF object. The ref object has only one.value property that points to this internal value. Like the value returned from the setup() function, the ref value is automatically unpacked when used in the template.

A generic parameter can be passed when ref is called to override the default inference

import { ref } from "vue";

let str = ref<string>("test");
Copy the code

Complex types can also be specified

Const foo = ref < string | number > (' foo ') / / foo types: ref < string | number > foo value = 123 / / ok!Copy the code

props/emit

  • Props /emit declarations of type only
defineProps<{ title: string }>();

const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
Copy the code
  • Default props value when using type declarations

The weakness of the type-only defineProps declaration is that it does not define a default value for props. With the withDefaults compiler macro:

interface Props { title? : string; msg? : string; } withDefaults(defineProps<Props>(), {title: "tip ", MSG:" Whether to jump to app? });Copy the code

V-model bidirectional binding

In VUe2, v-Model is used by passing the value attribute and receiving the input event, while in VUe3, the modelValue attribute is replaced by update:modelValue.

The following popover example takes Page.vue as the parent component and dialog. vue as the child component, and the key code is as follows:

/* Page. Vue */ <template> <Dialog V-model ="dialogVisible"></Dialog> </template> <script setup lang="ts"> import { ref } from "vue"; import Dialog from "./Dialog.vue"; let dialogVisible = ref<boolean>(false); function onTap() { dialogVisible.value = true; } <script>Copy the code
/* Dialog.vue */ <template> <div class="dialog" v-show="modelValue"> <span class="dialog-content-btn" @click="onConfirm"> confirm </span> </div> </template> <script setup lang="ts"> import {ref} from "vue"; interface Props { modelValue? : boolean; } let props = withDefaults(defineProps< props >(), {modelValue: false}); // Const emit = defineEmits<{(e: "update:modelValue", visible: Boolean): Boolean; } > (); function onConfirm() { emit("update:modelValue", false); } <script>Copy the code

Why is Vite faster

Vite is optimized in the following ways:

  • Provide code on demand when starting the application
  • Browser caches (negotiated and strong caches) for code updates
  • Use esBuild to pre-build dependencies and speed up builds

The startup time

Traditional packaging tools when cold starting development servers, the packager-based startup must first grab and build your entire application before it can be served. And there are performance bottlenecks — tools developed in JavaScript often take a long time (even minutes!). To start the development server, even with HMR, it takes a few seconds for the effect of the file changes to be reflected in the browser.

Vite improves development server startup times by separating application modules into dependent and source modules at the outset, and converting the source code only when the browser requests it and making it available on demand. And the esBuild prebuilt dependency uses the language Go, which is 10-100 times faster than the wrapper prebuilt dependency written in JavaScript.

Update time

In Vite, HMR is executed on native ESM. When editing a file, Vite only needs to precisely inactivate the chain [1] between the edited module and its nearest HMR boundary (most of the time just the module itself), allowing HMR to keep up to date quickly regardless of the size of the application.

Vite also uses HTTP headers to speed up whole page reloads (again letting the browser do more for us) : requests from source modules are negotiated in the Cache according to 304 Not Modified, while dependent module requests go through cache-control: Max-age =31536000,immutable Strong cache, so once cached they do not need to be requested again.

The cause and effect of pre-build dependencies

Vite prebuild dependencies for two reasons:

  • CommonJS and UMD compatibility: During development, Vite’s development server treats all code as native ES modules. Therefore, Vite must first convert dependencies published as CommonJS or UMD to ESM.

  • Performance: Vite reduces the number of browser requests and improves page loading performance by converting ESM dependencies that have many internal modules into a single module through pre-built dependencies.

    For example, lodash-es has more than 600 built-in modules. When import {debounce} from ‘lodash-es’ is executed, the browser makes more than 600 HTTP requests simultaneously. By pre-building LoDash-es into a module, only one HTTP request is required.

Automatic dependent search

If no corresponding cache is found, Vite will grab your source code and automatically look for imported dependencies (i.e. “bare import”, meaning expected resolution from node_modules) and use those dependencies as entry points to pre-built packages.

After the server has been started, if a new dependency import is encountered that is not already in the cache, Vite will rerun the dependency build process and reload the page.

When a dependency in the Monorepo repository becomes a dependency of another package, Vite automatically detects dependencies that are not resolved from node_modules and treats linked dependencies as source code. Instead of trying to package linked dependencies, it analyzes the list of linked dependencies.

The cache

File system caching

Vite caches pre-built dependencies to node_modules/.vite. It determines whether the pre-build step needs to be rerun based on several sources:

  • package.jsonIn thedependenciesThe list of
  • Lockfile for package manager, for examplepackage-lock.json.yarn.lockOr,pnpm-lock.yaml
  • May be invite.config.jsThe value has been configured in related fields

You only need to rerun the prebuild if one of the above changes.

To force Vite to rebuild dependencies, you can either start the development server with the –force command-line option, or manually delete the node_modules/.vite directory.

Browser cache

Parsed dependent requests are strongly cached with HTTP header max-age=31536000,immutable, to improve page reloading performance at development time. Once cached, these requests will never reach the development server again. If different versions are installed (as reflected in the lockfile of the package manager), the additional version query automatically invalidates them. If you want to debug dependencies via local editing, you can:

  1. Temporarily disable caching through the Network TAB of the browser debugging tool;
  2. Restart Vite Dev Server and add--forceCommand to rebuild dependencies;
  3. Reload the page.

Why not pack with ESBuild?

While EsBuild is surprisingly fast and a great tool for building libraries, some important features for building applications are still under development — especially code splitting and CSS handling. For now, Rollup is more mature and flexible when it comes to application packaging.

The last

Post upload complete code, to be continued…