Qi son

This article mainly introduces the knowledge points and use of Vite. This article will update and optimize the collection of some problems and related configurations encountered in the process of using Vite from time to time.

One, foreword

Vite next-generation Front-end development and build tools >>

Vite is a new front-end build tool that dramatically improves the front-end development experience. It mainly consists of two parts:

  • A development server, based on nativeES moduleProvides rich built-in features such as module hot update (HMR);
  • A set of build instructions, usingRollupPackage your code, and it is pre-configured to output optimized static resources for production.

Its characteristics are:

  • Extreme service startup: Use nativeESMFile, no need to pack!
  • Lightweight fast thermal overloading: Module thermal overloading that is always extremely fast, regardless of application size (HMR)
  • Rich features: YesTypeScript,JSX,CSSSupport out of the box.
  • Optimized build: Optional “multi-page application” or “library” mode preconfigurationRollupbuild
  • Common plug-ins: shared between development and buildRollup-supersetPlug-in interface.
  • Fully typed apis: Flexible apis and full TypeScript types.

Browser support:

  1. Development environment: Vite needs to be used in browsers that support dynamic import of native ES modules.
  2. In production: Default supported browsers need to support the introduction of native ES modules via script tags. Older browsers can be supported via the official plugin @vitejs/ plugin-Legacy.

Ii. Construction project

See here >>

$ yarn create @vitejs/app
Copy the code

Quick create project directive:

# vue + ts
$ yarn create @vitejs/app vue-ts-proj --template vue-ts
# react + ts
$ yarn create @vitejs/app react-ts-proj --template react-ts
Copy the code

Vite configuration items

Configuration file: vite.config.js

1. An alias

import { defineConfig } from "vite";
import { resolve } from "path";

export default defineConfig({
   resolve: {
    alias: {
      "@": resolve(__dirname, "src"),}}});Copy the code

Tip: If you use TS, you also need to add the following configuration to the ts.config.json file:

{
  "compilerOptions": {
   "baseUrl": "."."paths": {
     "@ / *": ["src/*"]}},Copy the code

2. Configure the proxy

// Configure the proxy
server: {
  proxy: {
    "/api": {
      target: "http://jsonplaceholder.typicode.com".changeOrigin: true.rewrite: (path) = > path.replace(/^\/api/.""),}}},Copy the code

3. Environment variables

①. Create a new directory in the root directory.env.dev,.env.production,.env.test

# Development environment:.env.dev
NODE_ENV=development
VITE_APP_ENV=development

# server address
VITE_APP_HOST= Address of the development environment server# Base path
VITE_APP_BASE=""

# appID related
VITE_APP_APPID_WEIXIN= WeChat appIDVITE_APP_APPID_ALIPAY= Alipay appIDCopy the code
# production environment:.env
NODE_ENV=production
VITE_APP_ENV=production

# server address
VITE_APP_HOST= IP address of the production server# Base path
VITE_APP_BASE=""

# appID related
VITE_APP_APPID_WEIXIN= WeChat appIDVITE_APP_APPID_ALIPAY= Alipay appIDCopy the code
# Test environment:.env.test
NODE_ENV=production
VITE_APP_ENV=production

# server address
VITE_APP_HOST= Address of the server in the test environment# Base path
VITE_APP_BASE=""

# appID related
VITE_APP_APPID_WEIXIN= WeChat appIDVITE_APP_APPID_ALIPAY= Alipay appIDCopy the code

Tips:

1) Environment variable names must start with VITE_APP;

2) Set the content of the configuration file according to the project requirements;

(2). To modifypackage.jsoninstruction

**@Vue **

"dev": "vite --mode dev --host 0.0.0.0"."test": "Vue-tsc --noEmit &&vite build --mode test --base=/"."build": "vue-tsc --noEmit && vite build --mode production".Copy the code

@React

"Dev" : "vite - mode = = dev - host 0.0.0.0", "test", "TSC && vite build - mode = test", "build" : "tsc && vite build --mode=production",Copy the code

③ Configure intelligent prompts for environment variables

@Vue

Create a new env.d.ts file in the root directory and type the following:

interface ImportMetaEnv {
  VITE_APP_BASE: string;
  VITE_APP_HOST: string;
  VITE_APP_APPID_WEIXIN: string;
  VITE_APP_APPID_ALIPAY: string;
}
Copy the code

@React

In the viet-env.d.ts file, type the following:

/// <reference types="vite/client" />

interface ImportMetaEnv {
  VITE_APP_BASE: string;
  VITE_APP_HOST: string;
  VITE_APP_APPID_WEIXIN: string;
  VITE_APP_APPID_ALIPAY: string;
}
Copy the code

④ Use environment variables

import.meta.env.VITE_APP_HOST
Copy the code

Iv. Project configuration

1. Preprocessing styles

Install less/ sASS without any configuration.

$ yarn add less -D
$ yarn add sass -D
Copy the code

2. Mobile adaptation solution

Install dependencies:

$ yarn add postcss-pxtorem autoprefixer -D
Copy the code

Create the postcss.config.js file in the root directory:

module.exports = {
  plugins: {
    autoprefixer: {
      overrideBrowserslist: [
        "Android 4.1"."iOS 7.1"."Chrome > 31"."ff > 31"."ie >= 8",]},"postcss-pxtorem": {
      rootValue: 37.5.Vant's official root font size is 37.5
      propList: ["*"].selectorBlackList: [".norem"].// filter out. Norem - classes that start with norem conversion,}}};Copy the code

SRC /utils/rem.ts

// REM equal match configuration file
// Base size. Note that this value must be consistent with rootValue in the postcss.config.js file
const baseSize = 37.5;
// Set the rem function
function setRem() {
  // The current page width relative to the 375 width scale can be modified according to your own needs, generally the design is 750 wide.
  const scale = document.documentElement.clientWidth / 375; // Set the font size of the root node of the page (" math.min (scale, 2) "means the maximum zoom ratio is 2, which can be adjusted according to actual business requirements)
  document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + "px";
}
/ / initialization
setRem();
// Resets rem when changing the window size
window.onresize = function () {
  setRem();
};
Copy the code

Introduced in the mian. Ts (x)

import "./utils/rem"
Copy the code

Tip: If the message “cannot compile” rem.ts “under “–isolatedModules” because it is considered a global script file. Please add an import, export, or empty “export {}” statement to make it a module. At this point you should set the isolatedModules field to false in the tsconfig.json file.

3. Global TS type declaration

Create the typings/index.d.ts file in the root directory

export {};

// => Global type declaration
declare global {
  interface Window {
    _hmt: any;
    wx: any;
    AlipayJSBridge: any;
  }
  namespace GD {
    interface BaseResponse<T = any> {
      code: number;
      data: T;
      msg: string;
      page: {
        pageNo: number;
        pageSize: number;
        pages: number;
        total: number; }; }}}Copy the code

Tip: you need to include [**/*.d.ts] in the tsconfig.json file.

It can then be accessed globally, for example:

const response = GD.BaseResponse<{name: string} >Copy the code

4. mock.js

①. Installation dependencies:

$ yarn add mockjs -S
$ yarn add vite-plugin-mock -D
Copy the code

(2) The plugin vite.config.js is introduced:

import { viteMockServe } from 'vite-plugin-mock';
export default defineConfig({
  plugins: [
    viteMockServe({})
  ],
});
Copy the code

Create a mock/test.ts file

export default[{url: "/api-dev/users".method: "get".response: (req) = > {
      return {
        code: 0.data: {
          name: "Li-HONGYAO".phone: "173 * * * * 8669".address: 216 Yahe South 4th Road, High-tech Zone, Chengdu city,},msg: "success"}; }},];Copy the code

④. Simulate request

fetch("/api-dev/users")
  .then((res) => res.json())
  .then((users) => {
    console.log(users);
  });
Copy the code

5. axios

①. Installation-related dependencies:

$ yarn add axios lg-tools lg-cookie
Copy the code

Lg-cookie >> : I encapsulate a library about operating cookies.

Lg-tools >> : I package a library about tool functions.

/ SRC /utils/request.ts

import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import Cookie from "lg-cookie";
import Tools from "lg-tools";

const service = axios.create({
  baseURL: import.meta.env.VITE_APP_HOST,
  timeout: 20000});// Request interception
service.interceptors.request.use(
  (config: AxiosRequestConfig) = > {
    // => If it is a GET request to append a timestamp
    if (config.method && /get/i.test(config.method)) { config.params = { ... config.params,timeState: Tools.randomCharacters(1) + Date.now(),
      };
    }
    // => Configure the request header
    const token = Cookie.get<string> ("AUTHORIZATION_TOKEN");
    config.headers = {
      "Content-Type": "application/json".Authorization: Cookie.get<string> ("AUTHORIZATION_TOKEN"),};return config;
  },
  (error) = > {
    return Promise.reject(error); });// Response interception
service.interceptors.response.use(
  (response: AxiosResponse) = > {
    const { code, msg } = response.data;
    switch (code) {
      case 0:
        return response.data;
      default:
        console.log(msg);
        returnresponse.data; }},(error: any) = > {
    console.log(error);
    /timeout/.test(error.message) && console.log("Request timed out, please check network.");
    return Promise.reject(error); });export default service;
Copy the code

Create/SRC/API /index.ts && / SRC/API /test.ts

// 1. src/api/test.ts
import request from ".. /utils/request";

/** * Get user information *@returns* /
export function users<T> () {
  return request.get<T>("/api-dev/users");
}
Copy the code
// 2. src/api/index.ts
import * as test from "./test";

export default {
  test,
};
Copy the code

(4) Add axiOS-related type configuration to global TS type declaration file

// => Axios module definition
import { AxiosRequestConfig } from "axios";

declare module 'axios' {
  export interface AxiosInstance {
    <T = any>(config: AxiosRequestConfig): Promise<T>;
    request<T = any> (config: AxiosRequestConfig): Promise<T>;
    get<T = any>(url: string, config? : AxiosRequestConfig):Promise<T>;
    delete<T = any>(url: string, config? : AxiosRequestConfig):Promise<T>;
    head<T = any>(url: string, config? : AxiosRequestConfig):Promise<T>;
    post<T = any>(url: string, data? :any, config? : AxiosRequestConfig):Promise<T>;
    put<T = any>(url: string, data? :any, config? : AxiosRequestConfig):Promise<T>;
    patch<T = any>(url: string, data? :any, config? : AxiosRequestConfig):Promise<T>; }}Copy the code

⑤. Call the interface to request data

// => Import API
import api from "./api";

// => Response data type declaration
interface UserProps {
  name: string;
  phone: string;
  address: string;
}

// => Interface call
api.test.users<GD.BaseResponse<UserProps>>().then(res= > {
  if(res && res.code === 0) {
    console.log(res.data.name); }})Copy the code

6. Load static resources dynamically

When importing static resources dynamically using Webpack, you can use the require form, but not in Vite, which throws the require is not defined error.

However, we can introduce it in the form of import.meta.url, which is a native ESM feature that exposes the URL of the current module. Using it in combination with the native URL constructor, we get a fully parsed static resource URL from relative paths in a JavaScript module, with the syntax as follows:

new URL(url, import.meta.url)
Copy the code

Example:

const imgs = [
  { imgUrl: new URL('./assets/logo_1.png'.import.meta.url), text: "Heading 1" },
  { imgUrl: new URL('./assets/logo_2.png'.import.meta.url), text: "Heading 2"},];Copy the code
// => react
{imgs.map((item) => (
  <img src={item.imgUrl.toString()} key={item.title} />
))}
Copy the code

It is worth noting that the error “URL is not defined XXX” will be thrown in the production environment. In this case, we need to use a plug-in: rollup-plugin-import-meta-url-to-module.

It is easy to use, first install dependencies:

$ yarn add rollup-plugin-import-meta-url-to-module
Copy the code

Then configure the plugins in “vit.config.js” :

import urlToModule from 'rollup-plugin-import-meta-url-to-module';

export default {
  plugins: [
    urlToModule()
  ]
};
Copy the code

# 5. Differentiated configuration

1. vue

– Route Configuration

Install dependencies:

$ yarn add vue-router@next
Copy the code

Create the router directory under SRC and create the index.ts file

import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

const routes: Array<RouteRecordRaw> = [
  {
    path: "/".redirect: "/login"}, {path: "/login".name: "login".component: () = > import("pages/Login/Login.vue"),
    meta: {
      title: "Login",}}, {path: "/index-page".name: "indexPage".component: () = > import("pages/IndexPage/IndexPage.vue"),
    meta: {
      title: "Home page",}},];const router = createRouter({
  history: createWebHistory(),
  routes,
});

// Navigation guard
router.beforeEach((to, from, next) = > {
  if(to.path ! = ="/favicon.icon") {
    document.title = to.meta.title ? (to.meta.title as string) : ""; next(); }});export default router;
Copy the code

Mount the route in main.ts

import App from "./App.vue";
import router from "./router";

// App configuration/mount related
// create App
const app = createApp(App);
/ / 2. Injection
app.use(router);
/ / 3. Mount
app.mount("#app");
Copy the code

– Status management

Install dependencies:

$ yarn add vuex@next
Copy the code

Configuration: Create store directory under SRC and index.ts under store

import { InjectionKey } from "vue";
import { createStore, ActionTree, GetterTree, MutationTree, Store } from "vuex";

// 1. Declare the Store type
declare interfaceStoreProps { authUrlForIos? :string;
}
// 2. Define the injection type
export const globalStoreKey: InjectionKey<Store<StoreProps>> = Symbol(a);// 3. ---- state
const state: StoreProps = {
  authUrlForIos: ""};// 3. ---- getters
const getters: GetterTree<StoreProps, any> = {
  authUrlForIos: (state) = > state.authUrlForIos,
};
// 3. ---- mutations
const mutations: MutationTree<StoreProps> = {
  updateAuthUrlForIos(state, payload){ state.authUrlForIos = payload; }};// 3. ---- actions
const actions: ActionTree<StoreProps, any> = {
  updateAuthUrlForIos({ commit }, payload) {
    commit("updateAuthUrlForIos", payload); }};// 4. Create the export
export default createStore<StoreProps>({
  state,
  getters,
  mutations,
  actions,
});

Copy the code

Mount: Mount the data center in main.ts

import App from "./App.vue";
import router from "./router";
import store, { globalStoreKey } from "./store";

// App configuration/mount related
// create App
const app = createApp(App);
/ / 2. Injection
app.use(router).use(store, globalStoreKey).use(vant);
/ / 3. Mount
app.mount("#app");
Copy the code

– Vant3

Install dependencies:

$ yarn add vant@next
Copy the code

Tip: The Vite version does not require on-demand loading of configuration components, because all modules in Vant 3.0 are written based on ESM and naturally have the ability to import on demand, but styles must be fully imported at 137.2k

Introduce styles globally in main.ts:

import App from "./App.vue";
import router from "./router";
import store from './store';
import vant from 'vant';
import "vant/lib/index.css";   

// App configuration/mount related
// create App
const app = createApp(App);
/ / 2. Injection
app.use(router).use(store).use(vant);
/ / 3. Mount
app.mount("#app");
Copy the code

– Secondary directory deployment

Plan 1:

Set the -base option when packing:

"build": "Vue-tsc --noEmit && vite build --mode production --base=/".Copy the code

The router/index.ts configuration is as follows:

const router = createRouter({
  CreateWebHistory (base? : string)
  history: createWebHistory("/ secondary directory name /"),
  routes,
});
Copy the code

Scheme 2:

Add the base configuration to the viet.config. js configuration item, as follows:

base:"/YOUR_PROJECT_NAME/"
Copy the code

The router/index.ts configuration is as follows:

const router = createRouter({
  CreateWebHistory (base? : string)
  history: createWebHistory("/ secondary directory name /"),
  routes,
});
Copy the code

2. React

– Route Configuration

①. Directory structure

.Heavy Metal Exercises ── Heavy metal Exercises ─ heavy metal Exercises# lazy loading loading prompt│ ├ ─ ─ NotEnv# Non-wechat/Alipay environment tips│ └ ─ ─ TabBar# TAB bar│ │ ├ ─ ─ index. The TSX │ │ └ ─ ─ but less ├ ─ ─ layouts │ └ ─ ─ index. The TSX ├ ─ ─ pages │ ├ ─ ─ Auth │ ├ ─ ─ IndexPage │ ├ ─ ─ Integral │ ├ ─ ─ mime │ ├ ─ ─ NotFound │ └ ─ ─ PrivilegeBrand ├ ─ ─ the router │ ├ ─ ─ index. The TSX │ └ ─ ─ routes. The ts └ ─ ─ main. The TSXCopy the code

Tip: here is only part of the catalogue for reference.

②. Install dependencies

$ yarn add react-router-dom
Copy the code

Note: the version I am using is ^6.0.2, please refer to here for routing usage of v6 version.

③ file code

src/layout/index.tsx

import TabBar from '@/components/@lgs-react/TabBar';
import React from 'react';
import { Outlet } from 'react-router-dom';

const Layout: React.FC = () = > {
  return (
    <>{/* View container, similar to router-view */} in Vue<Outlet />{/* Label bar */}<TabBar />
    </>
  );
};

export default Layout;
Copy the code

src/App.tsx

import React, { Suspense } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

import Fallback from '@/components/@lgs-react/Fallback';
import Layout from '@/layout';
import IndexPage from '@/pages/IndexPage';
import Integral from '@/pages/Integral';
import Mine from '@/pages/Mine';
import PrivilegeBrand from '@/pages/PrivilegeBrand';
import Auth from '@/pages/Auth';
import NotFound from './pages/NotFound';
import NotEnv from './components/@lgs-react/NotEnv';

import Tools from 'lg-tools';

const Details = React.lazy(() = > import('@/pages/Details'));
const Download = React.lazy(() = > import('@/pages/Download'));
const Test = React.lazy(() = > import('@/pages/Test'));

If VITE_APP_SOURCE === 'mp', it will prompt "Please open the link in wechat or Alipay client" *@param param0
 * @returns* /
export const GuardEnv: React.FC = ({ children }) = > {
  return import.meta.env.VITE_APP_SOURCE === 'mp' &&
    ['weixin'.'alipay'].indexOf(Tools.getEnv()) === -1 ? (
    <NotEnv />
  ) : (
    <>{children}</>
  );
};

/**
 * appRouter
 * @returns* /
export const AppRouter: React.FC = ({ children }) = > {
  return (
    <Suspense fallback={Fallback}>
      <Router basename={import.meta.env.VITE_APP_BASE}>{children}</Router>
    </Suspense>
  );
};

/** * appRoutes - Render route *@returns* /
export const AppRoutes: React.FC = () = > {
  return (
    <Routes>
      <Route path='/' element={<Layout />} ><Route index element={<IndexPage />} / ><Route path='privilege-brand' element={<PrivilegeBrand />} / ><Route path='integral' element={<Integral />} / ><Route path='mine' element={<Mine />} / ></Route>
      <Route path='/details' element={<Details />} / ><Route path='/download' element={<Download />} / ><Route path='/test' element={<Test />} / ><Route path='/auth/:type' element={<Auth />} / ><Route path=The '*' element={<NotFound />} / ></Routes>
  );
};
Copy the code

src/main.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import ErrorBoundary from '@/components/@lgs-react/ErrorBoundary';

import '@/utils/rem';
import '@/index.css';
import { AppRouter, AppRoutes, GuardEnv } from './App';
import Schemes from 'lg-schemes';

// 1. Enable vconsole in development & Test environment -- Tips: Currently, an exception occurs when you enable vConsole packaging
import vconsole from 'vconsole';
if (import.meta.env.VITE_APP_ENV ! = ='pro') {
  new vconsole();
}

// 2. Render the view
ReactDOM.render(
  <React.StrictMode>
    <ErrorBoundary>
      <GuardEnv>
        <AppRouter>
          <AppRoutes />
        </AppRouter>
      </GuardEnv>
    </ErrorBoundary>
  </React.StrictMode>.document.getElementById('root'));Copy the code

– Antd-mobile

Currently used antD-Mobile V5 (Poplar) version.

① Installation dependencies

$ yarn add antd-mobile@next
Copy the code

During the beta phase it is possible to release break change in subsequent releases, so it is highly recommended to lock the release with lockfile or manually lock the release

(2) the introduction of

Just import the component and ANTD-Mobile will automatically load the CSS style file for you:

import { Button } from 'antd-mobile'
Copy the code

– Secondary directory deployment

Json file to set –base=/ secondary directory name /.

② Set the value of VITE_APP_BASE in each environment configuration file as required.

②. Set this parameter when configuring routesbasenameProperties, as shown below:

/**
 * src/router/index.tsx
 * appRouter
 * @returns* /
export const AppRouter: React.FC = ({ children }) = > {
  return (
    <Suspense fallback={Fallback}>
      <Router basename={import.meta.env.VITE_APP_BASE}>{children}</Router>
    </Suspense>
  );
};
Copy the code

6. Template address

Spare time, combined with Vite encapsulated two templates, we can refer to:

  • Vite2 + Vue3 + TypeScript + Vant Mobile >>

  • Vite2 + React +_TypeScript + Ant Design Mobile 5.x >>

Tip: The code snippets in this article are taken from the template file above.