Vite2 come

Vite1 is not available yet, Vite2 has been updated with a new plugin architecture, a silky development experience, and a perfect combination of Vue3. In the first round of 2021, the village head plans to open the front end learning journey with Vite2+Vue3 as the theme.

2021 learn vite first

In this paper, the target

  • vite2Change analysis
  • Common tasks in a projectvite2+vue3practice

Create the Vite2 project

Gossip needless to say, below we table a table of heroes Vite2

Use NPM:

$ npm init @vitejs/app
Copy the code

Specify the project name and template as prompted, or directly

$ npm init @vitejs/app my-vue-app --template vue
Copy the code

Vite2 major changes

I have marked the ones that had a big impact on our previous projects:

  • Configuration options change:Vue-specific options, Create options, CSS options, JSX options, etc
  • Alias behavior change: No longer required/Beginning or ending
  • Vue supportThrough:@vitejs/plugin-vuePlug-in support
  • The React to support
  • HMR API changes
  • List format changes
  • Plug-in API redesign

Vue support

Vue integration is also implemented through plug-ins, just like any other framework:

SFC definitions use setup script by default.

The alias definition

No longer need to add/before and after aliases like vite1, this and Webpack project configuration can be consistent for portability.

import path from 'path'

export default {
  alias: {
    "@": path.resolve(__dirname, "src"),
    "comps": path.resolve(__dirname, "src/components"),}}Copy the code

Try it in app.vue

<script setup>
import HelloWorld from 'comps/HelloWorld.vue'
</script>
Copy the code

Plug-in API redesign

The main change in Vite2 is the plugin architecture, which is more standardized and extensible. The Vite2 plugin API extends from the Rollup plugin architecture, so it is compatible with existing Rollup plugins. The Vite plugin can also be developed and created at the same time.

I will have a separate panel discussion on plug-in writing, welcome to follow me.

Vue3 Jsx support

Vue3 JSX support requires the introduction of plugins: @vitejs/ plugin-vuE-jsx

$ npm i @vitejs/plugin-vue-jsx -D
Copy the code

Register the plugin, vite.config.js

import vueJsx from "@vitejs/plugin-vue-jsx";

export default {
  plugins: [vue(), vueJsx()],
}
Copy the code

Usage also has requirements, revamp app.vue

<! -- 1. mark JSX --> <script setup lang=" JSX "> import {defineComponent} from "vue"; import HelloWorld from "comps/HelloWorld.vue"; import logo from "./assets/logo.png" // 2. Define components with defineComponent and export Default defineComponent({render: () => ( <> <img alt="Vue logo" src={logo} /> <HelloWorld msg="Hello Vue 3 + Vite" /> </> ), }); </script>Copy the code
Mock plug-in application

Vite2 has been refactored from vite-plugin-Mock.

Installing a plug-in

npm i mockjs -S
Copy the code
npm i vite-plugin-mock cross-env -D
Copy the code

The configuration, vite. Config. Js

import { viteMockServe } from 'vite-plugin-mock'

export default {
  plugins: [ viteMockServe({ supportTs: false}})]Copy the code

Set the environment variable, package.json

{
  "scripts": {
    "dev": "cross-env NODE_ENV=development vite"."build": "vite build"}},Copy the code

Project Infrastructure

routing

Install the vue – the router 4. X

npm i vue-router@next -S
Copy the code

Route configuration, router/index.js

import { createRouter, createWebHashHistory } from 'vue-router';

const router = createRouter({
  history: createWebHashHistory(),
  routes: [{path: '/'.component: () = > import('views/home.vue')}});export default router
Copy the code

Introduction, main. Js

import router from "@/router";
createApp(App).use(router).mount("#app");
Copy the code

Don’t forget to create home.vue and modify app.vue

Routing usage changes slightly in video tutorials

State management

Install vuex 4. X

npm i vuex@next -S
Copy the code

Store configuration, Store /index.js

import {createStore} from 'vuex';

export const store = createStore({
  state: {
    couter: 0}});Copy the code

Introduction, main. Js

import store from "@/store";
createApp(App).use(store).mount("#app");
Copy the code

Usage is basically the same as before, video tutorial

Style organization

Install the sass

npm i sass -D
Copy the code

The styles directory holds various styles

Index.scss organizes these styles as an exit, while writing some global styles

Finally import in main.js

import "styles/index.scss";
Copy the code

Note that the styles alias is added in viet.config. js

UI library

Use our own element3 from the flower hill team.

Chinese document

The installation

npm i element3 -S
Copy the code

Full introduction, main.js

import element3 from "element3";
import "element3/lib/theme-chalk/index.css";

createApp(App).use(element3)
Copy the code

Import main.js on demand

import "element3/lib/theme-chalk/button.css";
import { ElButton } from "element3"
createApp(App).use(ElButton)
Copy the code

Better to extract as plugins, plugins/element3.js

// complete introduction
import element3 from "element3";
import "element3/lib/theme-chalk/index.css";

// Import on demand
// import { ElButton } from "element3";
// import "element3/lib/theme-chalk/button.css";

export default function (app) {
  // complete introduction
  app.use(element3)

  // Import on demand
  // app.use(ElButton);
}
Copy the code

test

<el-button>my button</el-button>
Copy the code

Basic layout

We need a basic layout page for our application, similar to the following, and each page will be parent page:

Layout page, Layout /index.vue

<template> <div class="app-wrapper"> <! - the sidebar - > < div class = "sidebar - container" > < / div > <! Content container --> <div class="main-container"> <! -- Top navigation bar --> <navbar /> <! < AppMain /> </div> </div> </template> <script setup> import AppMain from "./ Components/appmain.vue "; import Navbar from "./components/Navbar.vue"; </script> <style lang="scss" scoped> @import ".. /styles/mixin.scss"; .app-wrapper { @include clearfix; position: relative; height: 100%; width: 100%; } </style>Copy the code

Don’t forget to create appmain. vue and navbar. vue

Route configuration, router/index.js

{
  path: "/".component: Layout,
  children: [{path: "".component: () = > import('views/home.vue'),
      name: "Home".meta: { title: "Home page".icon: "el-icon-s-home"}},],},Copy the code

Dynamic navigation

The side navigation

Dynamically generate side navigation menus from routing tables.

First create a Sidebar component. The configuration in the recursive output routes is a multi-level menu, Layout /Sidebar/index.vue

<template>
  <el-scrollbar wrap-class="scrollbar-wrapper">
    <el-menu
      :default-active="activeMenu"
      :background-color="variables.menuBg"
      :text-color="variables.menuText"
      :unique-opened="false"
      :active-text-color="variables.menuActiveText"
      mode="vertical"
    >
      <sidebar-item
        v-for="route in routes"
        :key="route.path"
        :item="route"
        :base-path="route.path"
      />
    </el-menu>
  </el-scrollbar>
</template>

<script setup>
import SidebarItem from "./SidebarItem.vue";
import { computed } from "vue";
import { useRoute } from "vue-router";
import { routes } from "@/router";
import variables from "styles/variables.module.scss";

const activeMenu = computed(() => {
  const route = useRoute();
  const { meta, path } = route;
  if (meta.activeMenu) {
    return meta.activeMenu;
  }
  return path;
});
</script>

Copy the code

Note: The sass file export variable resolution requires CSS Module, so the variables file should have a module infix.

Add related styles:

  • styles/variables.module.scss
  • styles/sidebar.scss
  • styles/index.scssThe introduction of

Create sideBarItem. vue component to resolve whether the current route is a navigation link or a parent menu:

Bread crumbs

Breadcrumbs can be dynamically generated by routing the match array.

Bread crumbs components, layouts/components/Breadcrumb. Vue

<template> <el-breadcrumb class="app-breadcrumb" separator="/"> <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path"> <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect" >{{ item.meta.title }}</span> <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> </el-breadcrumb-item> </el-breadcrumb> </template> <script setup> import { compile } from "path-to-regexp"; import { reactive, ref, watch } from "vue"; import { useRoute, useRouter } from "vue-router"; const levelList = ref(null); const router = useRouter(); const route = useRoute(); const getBreadcrumb = () => { let matched = route.matched.filter((item) => item.meta && item.meta.title); const first = matched[0]; if (first.path ! = = = "/") {matched [{path: "/ home", meta: {title: "home page"}}]. Concat (matched); } levelList.value = matched.filter( (item) => item.meta && item.meta.title && item.meta.breadcrumb ! == false ); } const pathCompile = (path) => { var toPath = compile(path); return toPath(route.params); } const handleLink = (item) => { const { redirect, path } = item; if (redirect) { router.push(redirect); return; } router.push(pathCompile(path)); } getBreadcrumb(); watch(route, getBreadcrumb) </script> <style lang="scss" scoped> .app-breadcrumb.el-breadcrumb { display: inline-block; font-size: 14px; line-height: 50px; margin-left: 8px; .no-redirect { color: #97a8be; cursor: text; } } </style>Copy the code

Don’t forget to add dependencies: path-to-regexp

Note: Vue-Router4 no longer uses path-to-regexp to resolve dynamic paths, so this needs to be improved.

Data encapsulation

Unified encapsulation of data request services helps to solve the following problems:

  • Unified configuration request
  • Requests and responses are processed in a unified manner

Preparations:

  • Install axios:

    npm i axios -S
    Copy the code
  • Add the configuration file:.env.development

    VITE_BASE_API=/api
    Copy the code

Request encapsulation, utils/request.js

import axios from "axios";
import { Message, Msgbox } from "element3";

// Create an axios instance
const service = axios.create({
  // Prefix the request address with baseURL
  baseURL: import.meta.env.VITE_BASE_API,
  // Cookies are carried when sending a cross-domain request
  // withCredentials: true,
  timeout: 5000});// Request interception
service.interceptors.request.use(
  (config) = > {
    // Emulated the specified request token
    config.headers["X-Token"] = "my token";
    return config;
  },
  (error) = > {
    // Unified handling of request errors
    console.log(error); // for debug
    return Promise.reject(error); });// Response interceptor
service.interceptors.response.use(
  /** * The response can be processed by the status code, which can be modified according to the situation
  (response) = > {
    const res = response.data;

    // If the status code is not 20000, an error is considered
    if(res.code ! = =20000) {
      Message.error({
        message: res.message || "Error".duration: 5 * 1000});// 50008: invalid token; 50012: Other clients are logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // Log in again
        Msgbox.confirm("You have logged out. Please log in again."."Confirm", {
          confirmButtonText: "Log in again".cancelButtonText: "Cancel".type: "warning",
        }).then(() = > {
          store.dispatch("user/resetToken").then(() = > {
            location.reload();
          });
        });
      }
      return Promise.reject(new Error(res.message || "Error"));
    } else {
      returnres; }},(error) = > {
    console.log("err" + error); // for debug
    Message({
      message: error.message,
      type: "error".duration: 5 * 1000});return Promise.reject(error); });export default service;

Copy the code

The business process

Structured data presentation

El-table was used to display structured data, and el-Pagination was used for data pagination.

The file structure is as follows: list.vue displays the list, edit.vue and create.vue edit or create, internally reuse detail.vue processing, model is responsible for data business processing.

Data display in list.vue

<el-table v-loading="loading" :data="list"> <el-table-column label="ID" prop="id"></el-table-column> <el-table-column </el-table-column> <el-table-column label=" age" prop="age"></el-table-column> </el-table>Copy the code

The acquisition logic of list and loading data can be extracted from userModel.js using compsition-API

export function useList() {
  // List data
  const state = reactive({
    loading: true.// Load status
    list: [].// List data
  });

  // Get the list
  function getList() {
    state.loading = true;
    return request({
      url: "/getUsers".method: "get",
    }).then(({ data, total }) = > {
      // Set the list data
      state.list = data;
    }).finally(() = > {
      state.loading = false;
    });
  }
  
  // Obtain data for the first time
  getList();

  return { state, getList };
}
Copy the code

Used in the list. The vue

import { useList } from "./model/userModel";
Copy the code
const { state, getList } = useList();
Copy the code

Paging, list.vue

<pagination
      :total="total"
      v-model:page="listQuery.page"
      v-model:limit="listQuery.limit"
      @pagination="getList"
    ></pagination>
Copy the code

The data is also processed in the userModel

const state = reactive({
  total: 0./ / the total number of article
  listQuery: {// paging query parameters
    page: 1.// Current page number
    limit: 5.// Number of entries per page}});Copy the code
request({
  url: "/getUsers".method: "get".params: state.listQuery, // Add paging parameters to the query
})
Copy the code
Form processing

User data is added and edited using El-Form

This can be handled by a component detail.vue, the only difference being whether information is retrieved and backfilled into the form at initialization.

<el-form ref="form" :model="model" :rules="rules">
  <el-form-item prop="name" label="Username">
    <el-input v-model="model.name"></el-input>
  </el-form-item>
  <el-form-item prop="age" label="User age">
    <el-input v-model.number="model.age"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button @click="submitForm" type="primary">submit</el-button>
  </el-form-item>
</el-form>
Copy the code

Data processing can also be extracted into userModel for processing.

export function useItem(isEdit, id) {
  const model = ref(Object.assign({}, defaultData));

  // During initialization, isEdit determines whether the details need to be retrieved
  onMounted(() = > {
    if (isEdit && id) {
      // Get details
      request({
        url: "/getUser".method: "get".params: { id },
      }).then(({ data }) = >{ model.value = data; }); }});return { model };
}
Copy the code

Supporting video demonstration

I have specially recorded a set of video to demonstrate all the operations in this article. If you like to watch the video, you can follow the following steps: “Prepare for 2021” Vite2 + Vue3 project best practices

Production is not easy, for a 3, not too much attention! ?

Accompanying source code handout

Welcome to pay attention to the public number “village head learning front”

Follow-up Creation Plan

The most important update to Vite2 is the plugin system, which I plan to make later, including but not limited to the following:

  • Vite2 working mechanism analysis
  • Vite2 plug-in mechanism analysis
  • Vite2 plug-in to write actual combat

Let’s give it a thumbs up and bookmark it for future study.

Support the village chief

So much for the vitE2 project practice, this article has been tortured for a long time, stepped on a lot of pits, lost a few hair, friends point a thumbs up 👍 to encourage, ok?

My recent article (thanks for your encouragement and support 🌹🌹🌹) :

  • 🔥 Prepare for 2021: Vite engineering practice, suggested collection 857 likes
  • 🔥 Another night, this composition-API still feel short 217 upvotes
  • 🔥 to win vue3 you need to be prepared for this 76 likes
  • 🔥 Lightning five whip: Deep analysis of Composition API Principle 54 thumbs