实用指南:vite插件的使用

vite的编译结果

当我们执行npm run build将项目打包之后, 会生成一个dist文件, 下面我们看一下打包结果

  1. 首先查看页面文件



  
  
  Document
  <script type="module" crossorigin src="/assets/index-Bz2AOqjK.js"></script>
  


  



  
  
  Document


  
<script src="./main.js" type="module"></script>
  • 主要的变化就是引入资源的路由由相对路径被替换为绝对路径, 只有绝对路径才能最终定位资源
  • 如果我们直接使用Live Server运行这个index.html文件, 发现提示找不到资源, 因为dist不是运行根目录

  • 我们确保dist是运行的根目录, 在用Live Server运行就可以了

  • 在生产环境不会遇到这个问题, 因为会把dist作为项目根目录

  1. 查看静态资源
  • 打包后的静态资源为什么要有hash?

  • 浏览器是有一个缓存机制, 静态资源名字只要不改,那么他就会直接用缓存的
  • 当我们刷新页面, 浏览器不是立刻去请求资源, 而是根据资源的文件名, 尝试从浏览器器缓存中获取资源, 获取不到再去请求
  • hash算法: 将一串字符串经过运算得到一个新的乱码字符串, 利用好hash算法 可以让我们更好的去控制浏览器的缓存机制
  • vite中的资源的哈希值是根据文件内容+文件名生产的, 只要文件内容变化或文件名变化, 就会生成新的哈希值, 就不会命中浏览器缓存, 否则生成的哈希值是不变的

  1. 一些打包配置
import { defineConfig } from 'vite'
export default defineConfig({
  build: {
    rollupOptions: { // 配置rollup的一些构建策略
      output: { // 控制输出
        // 控制打包后的文件名格式
        assetFileNames: "[hash].[name].[ext]"
      }
    },
    assetsInlineLimit: 4096, // 当图片小于4kb, 打包成base64图片(生成在JS中), 而不是单独的图片
    outDir: "testDist", // 默认dist, 打包文件输出的文件夹名称
    assetsDir: "static" // 默认assets, 静态资源的文件夹名称
  }
})

vite的插件

插件是什么?

  1. vite会在生命周期的不同阶段中去调用不同的插件以达到不同的目的
  2. 生命周期: vite从开始执行到执行结束,那么整个过程就是vite的生命周期

vite-aliases

  1. 作用: 检测你当前目录下包括src在内的所有文件夹,并帮助我们去生成别名
{
  "@": "/**/src",
  "@aseets":"/**/src/assets",
  "@components":"/**/src/components"
}
  1. 安装配置
npm install vite-aliases -D
import { defineConfig } from 'vite'
import { ViteAliases } from 'vite-aliases'
export default defineConfig({
  plugins: [
    ViteAliases()
  ]
})
  1. 手写插件: 我们去手写Vite-aliases其实就是抢在vite执行配置文件之前去改写配置文件
import { defineConfig } from 'vite'
import MyViteAliases from './plugins/ViteAliases'
export default defineConfig({
  plugins: [
    MyViteAliases()
  ]
})
const fs = require("fs")
const path = require("path")
function diffDirAndFile(dirFilesArr = [], basePath = "") {
  const result = {
    dirs: [],
    files: []
  }
  dirFilesArr.forEach(name => {
    const currentFileStat = fs.statSync(path.resolve(__dirname, basePath + "/" + name))
    const isDirectory = currentFileStat.isDirectory()
    if (isDirectory) {
      result.dirs.push(name)
    } else {
      result.files.push(name)
    }
  })
  return result
}
function getTotalSrcDir() {
  const result = fs.readdirSync(path.resolve(__dirname, "../"))
  const diffResult = diffDirAndFile(result, "../")
  console.log("当前工程下的所有文件名夹", diffResult);
  const resolveAliasesObj = {}
  diffResult.dirs.forEach(dirName => {
    const key = `@${dirName}`
    const absPath = path.resolve(__dirname, "../" + "/" + dirName)
    resolveAliasesObj[key] = absPath
  })
  return resolveAliasesObj
}
module.exports = () => {
  return {
    config(config, env) {
      // config当前工程的配置对象
      // env环境数据
      // ---mode: 模式, 开发模式(dev)或生产模式(pro)
      // ---command: 执行的命令, npm run dev或 npm run build
      const resolveAliasesObj = getTotalSrcDir()
      console.log("路径别名对象", resolveAliasesObj);
      // config函数可以返回一个对象, 这个对象是部分的vite配置(就是要更改的那一部分)
      return {
        resolve: {
          alias: resolveAliasesObj
        }
      }
    }
  }
}

vite常用插件之vitee-plugin-html

  1. 作用: 就是帮我们动态的去控制整个html文件中内容 (基于ejs语法)
  2. 安装使用
npm install vite-plugin-html -D
import { defineConfig } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'
export default defineConfig({
  plugins: [
    createHtmlPlugin({
      inject: {
        data: {
          title: "首页"
        }
      }
    })
  ]
})



  
  
  
    <%= title %>
  

  1. 手写插件
import { defineConfig } from 'vite'
import CreateHtmlPlugin from './plugins/CreateHtmlPlugin'
export default defineConfig({
  plugins: [
    CreateHtmlPlugin({
      inject: {
        data: {
          title: "主页"
        }
      }
    })
  ]
})
module.exports = (options) => {
  return {
    // 转换html的周期
    transformIndexHtml: {
      enforce: "pre", // 生命周期的执行时机
      transform: (html, ctx) => {
        // html: 编译前的原文
        console.log(html);
        // ctx: 当前执行期上下文
        return html.replace(/<%= title %>/g, options.inject.data.title)
      }
    }
  }
}



  
  
  
    <%= title %>
  

vite常用插件之vite-plugin-mock

  1. 作用: 模拟数据
# 简单方式: 直接去写死一两个数据
# 优点: 方便调试
# 缺陷:
# --没法做海量数据测试
# --没法获得一些标准数据
# --没法去感知http的异常
# 标准方式: mock.js
  1. 简单示例
npm install vite-plugin-mock mock.js
import mockJS from "mockjs"
const userList = mockJS.mock({
  "data|100": [{
    name: "@cname", // 生成不同的中文名
    "id|+1": 1, // 生成自增+1的id
    time: "@time",
    date: "@date"
  }]
})
module.exports = [
  {
    method: "post",
    url: "/api/user",
    response: ({ body }) => {
      return {
        code: 200,
        mas: "sucess",
        data: userList
      }
    }
  }
]
  • 注意mock目录要放在根目录下才会被扫描到, 也可以配置
fetch("/api/user", {
  method: "post"
}).then(data => {
  console.log("data=", data);
}).catch(error => {
  console.log("err=", error);
})
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
  plugins: [
    viteMockServe()
  ]
})

  1. 手写vite-plugin-mock插件
const fs = require("fs")
const path = require("path")
export default (options) => {
  // 核心任务: 拦截Http请求
  // 请求流程:
  // 1.发送请求 ->
  // 2.补全请求地址(请求发送至本地开发服务器) ->
  // 3.viteserve会把请求上下文交给若干中间件处理 ->
  // 4.静态资源中间件(命中返回就资源) ->
  // 5.用户身份校验中间件(cookie,token)(合法继续,不合法返回) ->
  // 6.Api中间件
  return {
    // vite提供的服务器配置的钩子
    configureServer(server) {
      const mockStat = fs.statSync("mock") // 默认mock文件夹位于项目根目录, 否则不处理
      const isDirectory = mockStat.isDirectory() // 判断是否为文件夹
      let mockResult = []
      if (isDirectory) {
        // process.cwd(): 获取当前的执行根目录
        mockResult = require(path.resolve(process.cwd(), "mock/index.js")) // 拼接处完整的路径
        console.log(mockResult, "===");
      }
      // 服务器的相关配置 (安装middlewares插件)(也就是配置中间件)
      // req,请求对象 -->用户发过来的请求,请求头请求体 url cookie
      // res:响应对象,--> res.header
      // next:是否交给下一个中间件,调用next方法会将处理结果交给下一个中间件m1
      server.middlewares.use((req, res, next) => {
        const mathItem = mockResult.find(mockDescriptor => mockDescriptor.url === req.url)
        if (mathItem) {
          const responseDate = mathItem.response(req)
          res.setHeader("Content-Type", "application/json")
          res.end(JSON.stringify(responseDate)) // 异步代码
        } else {
          next() // 放行
        }
      })
    }
  }
}
import { defineConfig } from 'vite'
import VitePluginMock from './plugins/VitePluginMock'
console.log(VitePluginMock, '========');
export default defineConfig({
  plugins: [
    VitePluginMock()
  ]
})

认识其他的插件的生命周期

import { defineConfig, loadEnv } from "vite"
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        assetFileNames: "[hash].[name].[ext]"
      }
    }
  },
  plugins: [
    {
      // 作用: 获取用户的配置
      config(options) {
        // console.log("拿到vite.config中的所有配置", options);
      },
      // 对开发服务器进行配置
      configureServer(serve) {
        // console.log("对开发服务器进行控制", serve);
        // server.middlewares.use((req, res, next) => { }
      },
      // 对Html页面进行控制
      transformIndexHtml(html) {
        console.log("原始Html字符串", html);
      },
      // 可以拿到最终的配置文件
      configResolved(options) {
        // console.log("解析完毕的最终配置文件", options);
      },
      // 配置dist预览服务器
      configurePreviewServer(server) {
        // 打包完成后, 可以使用vscode的live serve插件启动html, 预览打包后的文件
        // vite也提供了一个服务器, 预览打包后的文件 (dist要是根目录)
        // npx vite preview   (打包后完直接敲就行)
        // 打包后的文件预览正常, 部署到线上就基本不会有问题
        // console.log("dist预览服务器的配置", server);
      },
      // 自定义一些热更新的行为
      handleHotUpdate(serve) {
        // console.log("热更新的配置", serve);
        // 了解下热更新的原理:
        // 1. 在服务端可以读到用户对vite的配置对象的
        // 2.把用户的配置对象和vite默认配置还有命令行参数都合并到一个对象里
        // 3.让配置逐个生效, 返回给浏览器, 页面就更新了
      },
      // 下面是一些universal hooks (就是vite和rollup都会执行的钩子)(上面的钩子只有vite执行)
      options(rollupOptions) {
        // 这里拿到配置就是我们在配置文件中定义的build选项中的配置
        console.log("build options", rollupOptions); // 这里会打印两次, 因为都会执行, 知道就行不影响什么
      },
      // 同configResolved
      buildStart(rullRollupOptions) {
        // 因为vite为了要和rollup保持一致, 所有会有一些重复的钩子, 对我们作用不大
        console.log("rullRollupOptions", rullRollupOptions);
      }
    }
  ]
})

vite与ts的结合

搭建环境




  
  
  Document
  <script src="./src/main.ts" type="module"></script>



console.log("hello");
npm init -y #初始化工程
npm i vite -D  #安装vite
npm run dev

说明: vite天生支持ts, 我们什么都没做, 就可以运行main.ts

TS的特点就是强类型绑定, 最大的作用就是提高代码的规范性

我们将数值类型的值赋值给字符串类型的变量, 在TS中肯定是不合法的, 而且编译器也给出了提示

但是这并不影响我们运行代码, 如果我们更强制的约束, 可以引入插件帮助把语法错误直接输出到控制台

npm install vite-plugin-checker -D
import { defineConfig } from "vite"
import check from "vite-plugin-checker"
export default defineConfig({
  plugins: [check({
    typescript: true
  })]
})

该插件依赖TS, TS也需要配置文件

npm install typescript -D
// 配置一些ts的检查手段和规则
{
  "compilerOptions": {
    "skipLibCheck": true // 忽略对node_modules目录的检查
  }
}

重新运行项目, TS语法错误就会阻塞项目, 减少项目中的雷

由于语法错误最终打包失败, 但是在编译到错误错误之前, 还是执行了构建操作

对于大型项目, 边构建边校验这样很浪费时间, 我们希望先检验,再构建

{
  "name": "04vite-ts",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "vite",
    "build": "tsc --noEmit && vite build",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}

TS中使用环境变量会有以下坑

VITE_TARGET=http://www.baidu.com

这个报错是因为tsconfig中默认把ts编译为es3, 就不支持 import.meta属性了, 所以要配置一下

// 配置一些ts的检查手段和规则
{
  "compilerOptions": {
    "skipLibCheck": true, // 忽略对node_modules目录的检查
    "module": "ESNext" // 编译为最新的ES语法
  }
}

又发现找不到env属性

要通过声明文件解决这个问题

/**
 * 下面写的是 三斜线指令
 * readonly是只读的意思, 一般环境变量的值不希望被改
 */
/// 
interface ImportMetaEnv {
  readonly VITE_TARGET: string
}

课程中是正常了, 而且我这里编译器也通过了

但是vite.config.ts文件报错了, 是因为vite不知道去哪找资源, 模块方案配置为node后, 默认去node_modules中寻找资源

// 配置一些ts的检查手段和规则
{
  "compilerOptions": {
    "moduleResolution": "node", // 模块解析方案
    "skipLibCheck": true, // 忽略对node_modules目录的检查
    "module": "ESNext" // 编译为最新的ES语法
  }
}

posted on 2025-10-03 12:06  slgkaifa  阅读(10)  评论(0)    收藏  举报

导航