preface

The year 2020 has passed, and the ecosystem of Vue3 in the community has been gradually enriched. Element Plus and ANTD-Vue have released versions of Vue3.

Evan You has released a new noun Vite which means fast in French, pronounced /vit/, and handles vue3 app projects by default, as well as react projects.

On January 21, 2001, Evan You released Vite version 2.0.0, repositioning Vite as a pure build tool. However, version 2.0 is still in beta, and the core concepts of Vite remain the same as 1.0, providing richer and more standardized standards and ideas at the configuration level.

So today, let’s start from 1.X and take the first step of the New Year with VUE3

Project initialization

First we create a new project using Vite:

/ / 1. Initialization program ╭ ─ ~ / vite ╰ ─ ➤ NPM init vite - app vite1. X - demo Scaffolding project in/Users/leiliao/vite/vite1 x - demo... Done. Now run: ╰─ ─ CD vite1.x-demo install (or 'yarn') NPM run dev (or 'yarn') // 2, install other dependencies ╭─~/vite ╰─ CD vite1.x-demo ╭─~/vite/vite1.x-demo ╰─➤ NPM I @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier Koa-compose @^4.1.0 prettier typescript vue-eslint-parser eslint-plugin-prettier -d + [email protected] + [email protected] + [email protected] + [email protected] + [email protected] + [email protected] + @typescript-eslint/[email protected] + @typescript-eslint/[email protected] + [email protected] ╭─~/vite/vite1.x-demo ╰─➤ NPM I vuex@next vue-router@next + [email protected] + [email protected]Copy the code
// 3. Add the configuration file

// tsconfig.json
{
  "include": ["./**/*.ts"]."exclude": [
    "node_modules"."dist"."./**/*.js"]."compilerOptions": {
    "target": "esnext"."module": "esnext"."baseUrl": "."."paths": {"/ @ / *": ["src/*"]},
    "jsx": "preserve"."sourceMap": true /* Generates corresponding '.map' file. */."outDir": "./dist" /* Redirect output structure to the directory. */."strict": true /* Enable all strict type-checking options. */."noUnusedLocals": true /* Report errors on unused locals. */."noImplicitReturns": true /* Report error when not all code paths in function return a value. */."moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */."esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */}}// vite.config.ts
import {} from 'vite';

import path from 'path';
export default {
  alias: {
    '/ @ /': path.resolve(__dirname, './src'),}};// .prettierrc.js
module.exports = {
  semi: true.trailingComma: 'all'.singleQuote: true.printWidth: 100.tabWidth: 2.endOfLine: 'auto'};// .eslintrc.js
module.exports = {
  parser: 'vue-eslint-parser'.parserOptions: {
    parser: '@typescript-eslint/parser'.// Specifies the ESLint parser
    ecmaVersion: 2020.// Allows for the parsing of modern ECMAScript features
    sourceType: 'module'.// Allows for the use of imports
    ecmaFeatures: {
      tsx: true.// Allows for the parsing of JSX}},plugins: ['@typescript-eslint'].extends: [
    'plugin:vue/vue3-recommended'.'plugin:@typescript-eslint/recommended'.// Uses the recommended rules from the @typescript-eslint/eslint-plugin
    'prettier/@typescript-eslint'.// Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
    'plugin:prettier/recommended'.// Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.].rules: {
    'vue/html-self-closing': 'off'.'vue/max-attributes-per-line': 'off',},env: {
    browser: true.node: true,}};Copy the code

4. Modify the import file

  • main.js -> main.ts
  • index.html
    • <script type="module" src="/src/main.js"></script> -> <script type="module" src="/src/main.ts"></script>

5. Add the declaration file

// src/shim.d.ts
declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;
}

declare module '*.scss' {
  const content: any;
  export default content;
}

// src/source.d.ts
declare const React: string;
declare module '*.json';
declare module '*.png';
declare module '*.jpg';

Copy the code

Vue3

The most important aspects of VUe3 are the Proxy and setup functions, and today I’ll focus on those two aspects

  1. fromObject.definePropertyLook up the
const obj = {}
Object.defineProperty(obj, "a", {
  value : 1.writable : false.// Is writable
  configurable : false.// Whether it can be configured
  enumerable : false // Whether enumerable
})

// Given three false, the following operations are easy to understand
obj.a = 2 / / is invalid
delete obj.a / / is invalid
for(key in obj){
  console.log(key) / / is invalid
}

obj.b = 3 / / 3
obj // {b: 3, a: 1}
delete obj.b // true
Copy the code

As you can see from the above example, Object.defineProperty can only intercept existing attributes. If it is a new attribute, there is no way to intercept again. So vue2 provides vm.$set to allow developers to re-intercept certain attributes of objects.

But we can solve this problem by using proxy.


var obj = new Proxy({}, {
  deleteProperty: function(target, prop) {
    return false; }}); obj.b =1

delete obj.b // false
Copy the code

Proxy returns a new object. Only a new object has the features of Proxy. You do not need to manually intercept new attributes.

  1. setup()

The setup function is the essence of VUe3:

// HelloWorkd.tsx
import { defineComponent, ref, reactive, computed } from 'vue';

export default defineComponent({
  name: 'App'.props: {
    modelValue: {
      type: Number.default: ' ',}},emits: ['update:modelValue'.'change'].setup(props, { attrs, slots, emit }) {
    const count = ref(0);

    const title = computed(() = > `hello vue3-${count.value}`);

    const info = reactive({ title, version: 'vue3', count });

    function handleClick() {
      info.count++;
      emit('update:modelValue', info.count);
    }

    return () = > (
      <>
        <button onClick={handleClick}>count is: {count.value}</button>

        <p>title.value: {title.value}</p>
        <p>info.title: {info.title}</p>
        <p>info.version: {info.version}</p>
      </>); }});Copy the code
// app.vue
<template>
  <img alt="Vue logo" src="/@/assets/logo.png" />
  <HelloWorld v-model="counts" />

  <div>counts :{{ counts }}</div>
</template>

<script>
import { ref } from 'vue';

import HelloWorld from '/@/components/HelloWorld';

export default {
  name: 'App'.components: {
    HelloWorld,
  },
  setup() {
    const counts = ref(0);
    return{ counts, }; }};</script>
Copy the code
  • In TSX, the JSX Templete code is returned directly in the setup function
  • All refs, Reactive, and functions need to be returned from the vue file to be used in templete
  • Templete can flatten refs automatically, but not on TSX
  • The TSX version cannot parse syntax sugar such as V-model
//App.tsx
port { defineComponent, ref } from 'vue';
// import { RouterLink, RouterView } from 'vue-router';
import HelloWorld from './components/HelloWorld';

export default defineComponent({
  name: 'App'.setup() {
    const counts = ref(0);
    return () = > (
      <>
        <img alt="Vue logo" src="/@/assets/logo.png" />
        <HelloWorld v-model={counts.value} />

        <div>counts :{counts.value}</div>
      </>); }});Copy the code

In the WebPack era, JSX V-Models can be translated and supported using babel-Plugin

  • You can read the documentation for additional syntax for Setup

Vite

Evan You exclaimed after launching Vite, “I don’t think I’ll ever come back to Webpack.”

This intrigued me, which is why I started this article using Vite as a tool to build VUe3.

es module

The srcript tag Module references other JS in the browser rendering principle of the browser album. It will make requests to other JS in the same domain without blocking. Es Module is already supported by most browsers.

esbuild

An extremely fast JavaScript bundler

Compared to other packaging tools, there are simply two types of packaging tools based on the speed of packaging tools: Esbuild and other packaging tools…

koa

Nodejs, the next generation web framework based on onion model, can quickly build customized Web services with middleware

Vite principle overview

const resolvedPlugins = [
    // rewrite and source map plugins take highest priority and should be run
    // after all other middlewares have finished
    sourceMapPlugin,
    moduleRewritePlugin,
    htmlRewritePlugin,
    // user plugins
    ...toArray(configureServer),
    envPlugin,
    moduleResolvePlugin,
    proxyPlugin,
    clientPlugin,
    hmrPlugin,
    ...(transforms.length || Object.keys(vueCustomBlockTransforms).length
      ? [
          createServerTransformPlugin(
            transforms,
            vueCustomBlockTransforms,
            resolver
          )
        ]
      : []),
    vuePlugin,
    cssPlugin,
    enableEsbuild ? esbuildPlugin : null,
    jsonPlugin,
    assetPathPlugin,
    webWorkerPlugin,
    wasmPlugin,
    serveStaticPlugin
  ]
Copy the code

Vite is simply a native Web service wrapped in middleware that provides compilation and hot update capabilities

  • serveStaticPluginA static server created by KOA returns index.html by default
  • using<script src='main.ts' module ></script>Request co-domain (under server folder)main.tsThe file frommain.tsGo out and request other resources.
  • webWorkerPlugin wasmPluginTo deal withWasm, webWorkerFile.
  • Process the Asset file requested in JS.
  • hmrPluginProvide hot update capability
  • Handles custom plugins.
  • moduleRewritePluginFlag the node_module module reference in the request code (because there is no node_module in the browser) as/@modules/
  • moduleResolvePluginProcessing the request/@modules/Node_module looks for the correct reference in node_module
  • vuePluginParse and compile VUE files, process and parse VUE files, monitor WACTH to inform HMR in time. (css t)
  • esbuildPluginCompile files with requests of type JS/JSX
    • Because esBuild is fast enough to compile files in the es Module during dynamic requests, Vite is fast enough to open in seconds

This is a rough order of middleware execution (subject to error).

Due to the Onion model, the middleware and code execute in a different order than in the array

rollup

Since many wheels in the industry do not support ESM references for the time being, Vite provides the option to specify certain packages to be repackaged using rollup during service initialization in configuration

server.listen = (async(port: number, ... args: any[]) => {if(optimizeDeps.auto ! = =false) {
      await require('.. /optimizer').optimizeDeps(config)
    }
    returnlisten(port, ... args) })as any
Copy the code

The Optimizer module is the processing module for rollUp

Debugging vite

In fact, introduced so much may be our idea is still on the surface, we can follow the method behind their own in-depth source discussion.

  • The first step is to set up the project according to the article (the version is 2.0 now, please refer to the official command).
  • Step 2 Download the vite code of the corresponding version
$ cd vite && yarn && yarn dev
$ yarn link # Open another terminal window and run the yarn link command
$ cd vite_xxxx && yarn remove vite && yarn link vite Switch to the project link Vite built in the first step
$ yarn dev --debug
Copy the code

conclusion

Front-end development environment and compilation due to browser differences lead to the need for a variety of tools to adapt, the experience is to develop a variety of pain and configuration, my dream is to directly write the latest syntax in the development without discussing compatibility, code version.

The appearance of Vite brought me closer to this dream.

All kinds of new technologies seem to be coming, but as long as the analysis of their essence is actually some small modules and just pieced together, and learning new technologies will always let you find their own shortcomings and loopholes.

Then we don’t reject, don’t complain, starting from 2021, from VUe3, from vite, progress together.

The content is rough and the analysis is not in place. In fact, I have not carefully looked at the principle of many plugins. If there is any mistake, please point it out in time.