一个开发服务器,基于原生ESModule 提供了丰富的内部构建功能:

1、原生ES导入不支持裸模块导入,Vite会检测到裸模块导入的源文件并将CommonJS或UMD转换为ESM格式,重写导入为合法的URL使得浏览器可以正确导入。

2、预构建这一步由esbuild执行,Vite的冷启动时间比基于js的任何打包器都要快。同时Vite提供了一套原生ESM的HMR API,具有HMR功能的框架可以利用该API进行无需重加载或清除应用程序状态的即时更新。

一套构建指令,使用Rollup打包代码,并且是预配置的,可输出用于生产环境的高度优化过的静态资源:

1、静态资源使用需要import导入,会返回解析后的URL,小于4M的图片资源会被编译成base64格式

2、支持使用特殊的import.meta.glob函数从文件系统导入多个模块,通常用于动态路由的文件读取

3、动态引入时,Rollup对共用chunk的情况进行优化处理:

Vite 将使用一个预加载步骤自动重写代码,来分割动态导入调用,以实现当 A 被请求时, C 也将 同时 被请求: C 也可能有更深的导入,在未优化的场景中,这会导致更多的网络往返。Vite 的优化会跟踪所有的直接导入,无论导入的深度如何,都能够完全消除不必要的往返。

Entry ---> (A + C)

默认支持TS和css/JSON引入

自动支持PostCSS 添加postcss.config.js配置文件

自动对sass等css预处理器进行了处理

只支持现代浏览器(不包括ie)

支持jsx和react项目的搭建

和vue-cli区别

  • webpack会先打包,然后启动开发服务器,请求服务器时直接给予打包结果。
  • 由于vite在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。这种按需动态编译的方式,极大的缩减了编译时间,项目越复杂、模块越多,vite的优势越明显
  • 由于现代浏览器本身就支持ES Module,会自动向依赖的Module发出请求。vite充分利用这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像webpack那样进行打包合并。(代码需开启本地服务才能运行,否则会产生跨域错误)
  • vite是按需加载,webpack是全部加载:在HMR(热更新)方面,当改动了一个模块后,vite仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
  • vite的优势在开发环境:当需要打包到生产环境时,vite使用传统的rollup(也可以自己手动安装webpack来)进行打包,因此,vite的主要优势在开发阶段。另外,由于vite利用的是ES Module,因此在代码中(除了vite.config.js里面,这里是node的执行环境)不可以使用CommonJS 总体来说1. 工具本身定位不同 webpack是底层的东西,vite则是更上层的工具。webpack是配置化,灵活度极高的工具,vite是开箱即用,使用更简单的工具。 2.原理不同 webpack是bundle,自己实现了一套模块导入导出机制。vite是利用浏览器的esm能力,是bundless。 3.vite开箱即用,更加简单,基于浏览器esm,使得hmr更加优秀 达到极速效果。 webpack更加灵活,api以及插件生态更加丰富,高可定制,兼容更多浏览器,例如ie11。
  • 兼容性注意

    需要Node版本大于12.0.0,有些模块需要依赖更高版本的Node才能运行

    包管理工具推荐使用yarn

    yarn create vite my-vue-app --template vue

    yarn 安装依赖 设置package.json的脚本 “dev”:“vite --open”

    yarn run dev可以自动打开浏览器

    安装项目所需插件

    vuex由于vuex4版本对ts兼容性不是很好,推荐中小型项目的话使用pinia进行状态管理

    pinia

    yarn add pinia

    pinia和vuex区别:

    1、id必须,将所使用store连接到devtools

    2、创建方式不同

    3、没有mutations

    4、特殊的actions更加灵活:

  • 可以通过组件或其他 action 调用
  • 可以从其他 store 的 action 中调用
  • 直接在 store 实例上调用
  • 支持同步或异步
  • 有任意数量的参数
  • 可以包含有关如何更改状态的逻辑(也就是 vuex 的 mutations 的作用)
  • 可以 $patch 方法直接更改状态属性
  • 新建store文件夹,新建index.ts文件

    import {defineStore} from 'pinia'
    export const useStore = defineStore('storeId', {
        state: () => {
            return {
                counter: 0,
                name: 'Eduardo',
                isAdmin: true,
        getters:{
            nameLength:(state)=>state.name.length
        actions:{ //可以做异步
            async insertPost(data:string){
                const res = await Ajax(data)
    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
    组件内使用:
    import {useStore} from "@/store/store";
    import {index} from "@/types";
    const store:index = useStore()
    console.log(useStore().$state)
    //修改数据使用store.$patch
    

    VueRouter

    yarn add vue-router@4

    src新建router文件夹:router.js文件

    可以设置meta属性方便做一些功能的实现

    import {createRouter, createWebHistory, RouteRecordRaw} from 'vue-router'
    const routes: RouteRecordRaw[] = [
            path: '/',
            name: 'Login',
            meta:{
                title:string//页面标题
                icon?:string//图标,搭配菜单使用
                auth?:boolean//是否需要登录权限
                ignoreAuth?:boolean//是否忽略权限
                roles?:RoleEnum[],//可以访问的角色
                keepAlive?:boolean//是否开启页面缓存
                hideMenu?:boolean//隐藏起来不在菜单中展示的路由
                order?:number//菜单排序
            component: () => import('@/pages/login/Login.vue'), // 注意这里要带上 文件后缀.vue
    const router = createRouter({
        history: createWebHistory(),
        routes,
    export default router
    

    Element-plus

    yarn add element-plus

    yarn add -D unplugin-vue-components

    可以搭配antfu大佬开发的unplugin-vue-components实现组件和UI库组件自动引入

    配置vite.config.ts
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import Components from 'unplugin-vue-components/vite' // 新增
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // 引入ElementPlusResolver
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [
        vue(),
        Components({resolvers: [ElementPlusResolver()]}) // 添加配置
    

    Axios

    或者使用VueRequest

    yarn add axios

    yarn add nprogress安装进度条

    新建utils文件夹,新建request.ts文件

    import axios, {AxiosError, AxiosRequestConfig, AxiosResponse} from "axios";
    import NProgress from 'nprogress'
    import {Message} from '@element-plus/icons-vue'
    interface ResType<T> { //返回值得类型 根据公司实际需要自己配置减少any使用
        code: number
        data?: T
        msg: string
        err?: string
    interface Http { //
        get<T>(url: string, params?: unknown): Promise<ResType<T>>
        post<T>(url: string, params?: unknown): Promise<ResType<T>>
        upload<T>(url: string, params: unknown): Promise<ResType<T>>
        download(url: string): void
    // 设置请求头和请求路径
    axios.defaults.baseURL = '/api'
    axios.defaults.timeout = 10000
    axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
    //请求拦截器
    axios.interceptors.request.use(
        (config: AxiosRequestConfig) => {
            const token = window.sessionStorage.getItem('token')
            if (token) {
                // @ts-ignore
                config.headers.token = token
            return config
        (error: Error) => {
            return error
    // 响应拦截
    axios.interceptors.response.use(
        (res: AxiosResponse) => {
            switch (res.data.code) {
                case 111:
                    sessionStorage.setItem('token', '');
                    return res
                case 200:
                    return JSON.stringify(res.data)
                default :
                    return
        (error: AxiosError) => {
            // 接收到异常响应的处理开始
            if (error && error.response) {
                // 1.公共错误处理
                // 2.根据响应码具体处理
                switch (error.response.status) {
                    case 400:
                        error.message = '错误请求'
                        break;
                    case 401:
                        error.message = '未授权,请重新登录'
                        break;
                    case 403:
                        error.message = '拒绝访问'
                        break;
                    case 404:
                        error.message = '请求错误,未找到该资源'
                        window.location.href = "/NotFound"
                        break;
                    case 405:
                        error.message = '请求方法未允许'
                        break;
                    case 408:
                        error.message = '请求超时'
                        break;
                    case 500:
                        error.message = '服务器端出错'
                        break;
                    case 501:
                        error.message = '网络未实现'
                        break;
                    case 502:
                        error.message = '网络错误'
                        break;
                    case 503:
                        error.message = '服务不可用'
                        break;
                    case 504:
                        error.message = '网络超时'
                        break;
                    case 505:
                        error.message = 'http版本不支持该请求'
                        break;
                    default:
                        error.message = `连接错误${error.response.status}`
            } else {
                // 超时处理
                if (JSON.stringify(error).includes('timeout')) {
                    Message.error('服务器响应超时,请刷新当前页')
                Message.error('连接服务器失败')
            Message.error(error.message)
            //处理结束
            //如果不需要错误处理,以上的处理过程都可省略
            return Promise.resolve(error.response)
    const Http: Http = {
        get(url, params) {
            return new Promise((resolve, reject) => {
                NProgress.start()
                axios
                    .get(url, {params})
                    .then((res) => {
                        NProgress.done()
                        resolve(res.data)
                    .catch((err) => {
                        NProgress.done()
                        reject(err.data)
        post(url, params) {
            return new Promise((resolve, reject) => {
                NProgress.start()
                axios
                    .post(url, JSON.stringify(params)) //注意此处根据实际情况进行处理
                    .then((res) => {
                        NProgress.done()
                        resolve(res.data)
                    .catch((err) => {
                        NProgress.done()
                        reject(err.data)
        upload(url, file) {
            return new Promise((resolve, reject) => {
                NProgress.start()
                axios
                    .post(url, file, {
                        headers: {'Content-Type': 'multipart/form-data'}, //文件手动上传时调用
                    .then((res) => {
                        NProgress.done()
                        resolve(res.data)
                    .catch((err) => {
                        NProgress.done()
                        reject(err.data)
        download(url) {
            const iframe = document.createElement('iframe')
            iframe.style.display = 'none'
            iframe.src = url
            iframe.onload = function () {
                document.body.removeChild(iframe)
            document.body.appendChild(iframe)
    export default Http;
    

    环境变量配置

    1、.env.development文件:NODE_ENV=development VITE_APP_API='API_URL'

    2、.env.production文件:NODE_ENV=production VITE_APP_API= 'YOUR WEB URL'

    组件使用:import.meta.env.VITE_APP_API

    3、打包区分开发环境和生产环境

    "build:dev": "vite build --mode development",
    "build:pro": "vite build --mode production",
    

    vite常用基础配置

    代理和打包配置

    生产环境生成.gz文件:开启gzip压缩静态资源,提高页面加载速度

    yarn add --dev vite-plugin-compression

    下面是vite.config.ts的全部配置

    vite.config.ts
    import { defineConfig } from "vite";
    import vue from "@vitejs/plugin-vue";
    import AutoImport from "unplugin-auto-import/vite";
    import Components from "unplugin-vue-components/vite";
    import viteCompression from 'vite-plugin-compression'
    import { resolve } from "path";
    // https://vitejs.dev/config/
    export default defineConfig({
      base: "./", // 类似publicPath,'./'避免打包访问后空白页面,要加上,不然线上也访问不了
      plugins: [
        vue(),
        //配置插件
        plugins: [
            vue(),
            vueJsx(),
            viteCompression({
                verbose: true,
                disable: false,
                threshold: 10240,
                algorithm: 'gzip',
                ext: '.gz',
        AutoImport({
          imports: [
            "vue",
            "vue-router",
            "pinia",
              axios: [["default", "axios"]]
          dts: "src/auto-import.d.ts",
          eslintrc: {
            enabled: true
        Components({
          resolvers: [ElementPlusResolver()],
          dts: true
      build: {
        outDir: "",
        assetsDir: "assets", //指定静态资源存放路径
        sourcemap: false, //是否构建source map 文件
        terserOptions: {
          // 生产环境移除console
          compress: {
            drop_console: true,
            drop_debugger: true
      server: {
        https: false, // 是否开启 https
        open: false, // 是否自动在浏览器打开
        port: 8888, // 端口号
        host: "0.0.0.0",
        // hmr: {
        //   overlay: false
        // },
        proxy: {
          "/api": {
            target: "", // 后台接口
            changeOrigin: true,
            secure: false, // 如果是https接口,需要配置这个参数
            // ws: true, //websocket支持
            rewrite: (path) => path.replace(/^/api/, "")
      resolve: {
        alias: {
          //拼接文件夹名和后面自定的名字
          "@": resolve(__dirname, "src"),
          "@assets": resolve(__dirname, "src/assets"),
          "@components": resolve(__dirname, "src/components"),
          "@images": resolve(__dirname, "src/assets/images"),
          "@views": resolve(__dirname, "src/views"),
          "@store": resolve(__dirname, "src/store")
    
    main.ts
    import { createApp } from "vue";
    import App from "./App.vue";
    import router from "./router";
    import * as ElIconModules from "@element-plus/icons-vue";
    import ElementPlus from "element-plus";
    import store, { key } from "@/store";
    import "element-plus/dist/index.css";
    import { Request } from "@/utils/request/index";
    import VueAxios from "vue-axios";
    // 统一注册Icon图标
    for (const iconName in ElIconModules) {
      if (Reflect.has(ElIconModules, iconName)) {
        const item = ElIconModules[iconName];
        createApp(App).component(iconName, item);
    createApp(App)
      .use(router)
      .use(ElementPlus)
      .use(store, key)
      .use(VueAxios, Request.init())
      .mount("#app");
    
    tsconfig.json
    "compilerOptions": {   "target": "esnext",   "useDefineForClassFields": true,   "module": "esnext",   "moduleResolution": "node",   "strict": true,   "jsx": "preserve",   "sourceMap": true,   "resolveJsonModule": true,   "esModuleInterop": true,   "lib": ["esnext", "dom"],   "baseUrl": ".",   "suppressImplicitAnyIndexErrors": true,   "paths": {     "@/*": ["src/*"] "include": [   "src/**/*.ts",   "src/**/*.d.ts",   "src/**/*.tsx",   "**/*.ts",   "**/*.tsx",   "src/**/*.vue"
    package.json
    "name": "", "version": "0.0.0", "scripts": {   "dev": "vite --open",   "build": "vue-tsc --noEmit && vite build",   "build:dev": "vue-tsc --noEmit && vite build --mode development",   "build:prod": "vue-tsc --noEmit && vite build --mode production",   "preview": "vite preview",   "prepare": "cd .. && husky install ./radar-config-project/.husky",   "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src" "dependencies": {   "@element-plus/icons-vue": "^0.2.7",   "@types/uuid": "^8.3.4",   "axios": "^0.24.0",   "core-js": "^3.6.5",   "element-plus": "^1.3.0-beta.5",   "mitt": "^3.0.0",   "pinia": "^2.0.9",   "vue": "^3.2.26",   "vue-axios": "^3.4.0",   "vue-class-component": "^8.0.0-0",   "vue-router": "^4.0.12",   "vuex": "^4.0.0-0" "devDependencies": {   "@typescript-eslint/eslint-plugin": "^5.9.0",   "@typescript-eslint/parser": "^5.9.0",   "@vitejs/plugin-vue": "^2.0.1",   "eslint": "^8.6.0",   "eslint-config-prettier": "^8.3.0",   "eslint-plugin-prettier": "^4.0.0",   "eslint-plugin-vue": "^8.2.0",   "husky": "^7.0.4",   "lint-staged": "^12.1.7",   "prettier": "^2.5.1",   "sass": "^1.47.0",   "typescript": "^4.5.4",   "unplugin-auto-import": "^0.5.10",   "unplugin-vue-components": "^0.17.11",   "vite": "^2.7.10",   "vue-tsc": "^0.29.8" "lint-staged": {   "*.{vue,ts}": []
    .eslintrc.js
    module.exports = {
      env: {
        browser: true,
        es2021: true,
        node: true,
        "vue/setup-compiler-macros": true
      parser: "vue-eslint-parser",
      parserOptions: {
        ecmaVersion: 13,
        parser: "@typescript-eslint/parser",
        sourceType: "module"
      extends: [
        "plugin:vue/vue3-recommended",
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:prettier/recommended",
        "./.eslintrc-auto-import.json"
      rules: {
        "vue/multi-word-component-names": 0,
        endOfline: "auto"
    

    其他常用插件

    可以查看官方文档:vitejs.cn/plugins/\