vite基本配置 (vite 3.0)

438 阅读10分钟

vite介绍

vite是基于原生的ES-Module的构建工具
vite是一个开发构建工具,开发过程中它利用浏览器native ES Module特性导入组织代码,生产中利用rollup作为打包工具,它有如下特点:

  • 光速启动
  • 热模块替换(HMR)
  • 按需编译

为什么使用vite

在浏览器支持ES模块之前,JavaScript并没有提供原生的机制,让开发者以模块化的方式开发。
打包就是使用工具抓取处理,把我们的原代码模块,串联成在浏览器可以运行的文件。

开发环境下服务器启动更新
vue-cli优先抓取构建整个应用。依赖方面:大多数时候,依赖都是在开发过程中,不变的、纯的js代码,并且一些较大的依赖处理代价很高,例如有上百个模块组件库。依赖也存在多种模块化的格式,比如ESM、CommonJS这样的格式等。源码方面:除了纯的js文件,例如jsx、cssvue、这些文件还需要转换、或者是编辑。不是所有的源码都需要被同时的加载,例如基于路由的拆分的代码模块。这种对源码和以来的处理方式,势必会导致服务器启动慢。基于打包器启动时,重建整个包的效率是很低的。这样的更新速度会随着应用体积增长而直线下降。一些打包器的开发服务器,会将构建内容存入内存,比如webpack。这样只需要在文件更改的时候,是一部分模块失活。但它任需整个重新构建,并重载页面。这样代价是很高的,并且重新加载页面,会消除应用的当前状态,所以打包器支持了动态模块热重载,即HMR。它允许一个模块热替换它自己,而不会影响页面的其余部分,这就大大改进了开发体验。比如webpack-dev-server,就提供了HMR这样的功能。然而在实践中会发现,就是采用了HMR这样的模式,其热更新的速度也会随着应用规模的增长而显著下降。
vitevite在一开始会将应用中的模块区分为源码和依赖两类。vite使用ESBuild来构建依赖,ESBuild使用go语言(编译型语言)编写,比JavaScript编写的打包器快10-100倍。vite以原生的ESM提供源码,实际是让浏览器接管了部分的打包工作。vite只需要在浏览器请求源码的时候,进行转换,并按需提供源码,根据场景动态的导入代码。vite的HMR是在ESM上执行的,当编辑一个文件的时候,vite只需要精确的使已编辑的模块与最近的HMR边界时间的链失活,无论应用大小,HMR始终保持快速更新,因为大多数时候,指示模块本身被更新了。vite同时利用http头来加速整个页面的重新加载。源码模块的请求,会根据304来进行协商缓存,而依赖模块的请求会通过Cache-Control来进行强缓存。一旦被缓存,他们将不需要再次请求,即浏览器可以做更多的事情。
生产环境下
为什么生产环境下任需打包?生产环境下不能直接使用开发环境的玩法。尽管原生的ESM得到广泛支持,但是由于嵌套导入,会导致额外的网络往返。再生产环境中发布未打包的ESM任然效率低下,及时使用了http/2也是如此,为了在生产环境中获得最佳的加载性能,最好还是将代码进行tree-shaking、懒加载chunk分割等操作。其中chunk分割的目的,是获得更好的缓存,要确保开发服务器和生产环境构建之间的最有输出和行为一致,并不容易。所以vite附带了一套构建优化的构建命令,开箱即用。
为什么不适用ESBuild打包?虽然ESBuild速度快,并且在构建库方面是一个比较出色的工具了。但一些针对构建应用的重要功能,任在持续开发中,特别是代码分割和CSS处理方面。Rollup在应用打包方面更加成熟和灵活。尽管如此,官方也表示,在未来这些功能稳健以后,也不排除使用ESBuild作为生产构建其的可能

npm依赖解析和预构建

image.png import { createApp } from 'vue' 直接放在浏览器中是不能执行的,通过vite来帮忙。vite会检测所有的源文件当中,此类裸模块的导入,并执行以下两个操作:预构建、重写url。预构建可以页面加载速度,并且将CommonJS UMD转化为ESM格式。预构建是由esbuild来执行的,这使得vite的启动时间比任何JavaScript的打包器都要快。重写导入为合法的url,将import { createApp } from 'vue'的路径改写为/node_modules/.vite/deps/vue.js?v=46b0d5b8,以便浏览器可以正确的导入他们。

"依赖预构建"过程的两个目的

  • 完成CommonJS和UMD兼容性 在开发过程中,vite会将所有的代码视为原生的ES模块,vite必须先将作为CommonJS和UMD发布的依赖项转换为ESM。当转换CommonJS依赖的时候,vite会进行智能的导入分析,这样即使导出的是动态分配的表示也能达到预期的效果。
  • 性能方面 vite会将许多内部的模块的ESM依赖关系,转换为单个的模块,以提高我们后续页面加载的性能。一些包将它们的ES模块的构建作为许多单独文件相互的导入,比如ES这里我们有一个lodash,那lodash es再去导入的时候,其实上有超过600个内置的模块需要去导入。执行import { debounce } from 'lodash-es',会同时发出600多个http请求。尽管服务器端在处理这些请求的时候是没有问题的,但是大量的请求会在浏览器端造成拥塞,导致页面的加载速度相当慢。通过预构建lodash-es,把它变成一个模块,只需要做一次http请求即可。

esbuild特点

  • 极快的速度而不需要缓存
  • ES6和CommonJS模块支持
  • ES6模块的tree shaking
  • 一个用于JavaScript和Go的API
  • TypeScript和JSX语法支持
  • Source maps支持
  • 简化打包
  • 插件支持

vite缓存

vite默认在模块预构建完成之后,会对构建好的模块进行缓存。

  1. vite在服务器端,是通过文件系统来实现缓存的,vite会将与构建的依赖缓存到node_modules/.vite这个文件夹下。
  • package.json文件中的dependencies列表
  • pnpm-lock.yaml文件
  • vite.config.ts相关字段的配置 image.png 当发生以上情况时,就会重新进行预构建。如果想要强制进行预构建,使用--fource命令启动服务器。这个命令会强制本地服务端的依赖的缓存,即把依赖的模块的缓存都清理调,重新生成。或者通过手动把.cache文件删除 image.png
  1. vite在浏览器端,通过解析后的依赖请求,以HTTP头的max-age=315360000immutable来实现强缓存。
  • 通过控制台操作禁用缓存 image.png
  • 通过--fource命令(同上)
  • 重新载入页面,也会将缓存清理

模块热重载

vite提供了一套原生的ESM的HMR API。vite内置了HMR到vue单文件组件(SFC),React Fast Refresh,@prefresh/vite vite.config.js中自动设置了import vue from '@vitejs/plugin-vue',defineConfig配置项中声明了plugins: [vue()],这样项目就自动具备了HMR的效果。

CJS, AMD, UMD 和 ESM是什么

参考:juejin.cn/post/693597…

TypeScript

vite天然支持.ts文件引入,vite仅仅支持.ts文件的转译工作,并不执行任何类型检查。

静态资源处理

  • ?url
  • ?raw 【直接引入文件全部代码】
  • new URL()
  • public目录 【这个目录下的资源文件可以直接在页面上使用】 image.png image.png

json和glob导入

image.png image.png

// 表示导入./components/glob文件夹下所有的文件
const modules = import.meta.glob('./components/glob/*')

console.log('modules', modules)
// 打印结果如下图,是一个对象,key是文件的目录名字,value是对应的导入函数

image.png

1 创建新项目 (vite 3.0版本)

    1. yarn create vite <项目名>
    2. cd <项目名>
    3. pnpm install 【npm install, yarn install】
    4. pnpm dev 【npm run dev, yarn dev】
    5. pnpm build 打包
    6. pnpm preview 预览

2. 文件目录结构

image.png
.gitignore文件:上传git忽略的内容
index.html文件:在根目录下,是项目的入口文件,<script type="module" src="/src/main.ts"></script>。mian.js中使用了es module,即es模块的import语法,不能直接在浏览器上使用,需要设置type="module" 。【如果使用webpack构建项目,index.html是放在public文件下的】
package.json文件:定义name、version,开发、生产依赖以及npm脚本
pnpm-lock.yaml文件:如同 yarn.lock、package-lock.json 一样,可以为项目提供一份各个依赖稳定的版本信息
README.md文件:帮助(使用)文档
tsconfig.json文件:TypeScript 编译的相关配置
vite.config.ts文件:vite的相关配置

2. 配置vite.config.ts文件

2.1 遇到问题

😈 找不到模块“path”或其相应的类型声明。
原因:path模块是node.js内置的功能,但是node.js本身并不支持ts
解决方案:安装@types/node

pnpm install @types/node -D

2.2 build.minify配置

  • 类型:  boolean | 'terser' | 'esbuild'
  • 默认:  'esbuild'
    设置为 false 可以禁用最小化混淆,或是用来指定使用哪种混淆器。虽然 Terser 相对较慢,但大多数情况下构建后的文件体积更小。ESbuild 最小化混淆更快但构建后的文件相对更大。它比 terser 快 20-40 倍,压缩率只差 1%-2%。
    注意,在 lib 模式下使用 'es' 时,build.minify 选项不会缩减空格,因为会移除掉 pure 标注,导致破坏 tree-shaking。 当设置为 'terser' 时必须先安装 Terser。
pnpm add -D terser

2.3 mock数据配置

安装依赖:

yarn add vite-plugin-mock mockjs -D

官网:github.com/vbenjs/vite…

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

// 配置项
viteMockServe({
      // default
      mockPath: 'mock',
      // localEnabled: command === 'serve',
}),

在根目录下新建mock文件夹,index.ts文件(写测试数据)

// test.ts

import { MockMethod } from 'vite-plugin-mock'
export default [
  {
    url: '/api/get',
    method: 'get',
    response: ({ query }) => {
      return {
        code: 0,
        data: {
          name: 'vben',
        },
      }
    },
  },
] as MockMethod[]

安装axios

pnpm add axios

根目录下新建.env.development文件 (开发环境加载的配置文件)

VITE_BASE_API=http://api.test.xxx.xxx.com/api

根目录下新建.env.production文件 (生产环境加载的配置文件)

VITE_BASE_API=http://api.test.xxx.xxx.com

测试mock数据

import axios from 'axios'

const getApi = async() => {
  const { data } = await axios.get('/api/get')
  console.log('测试api', data)
  console.log('测试 base_api', import.meta.env.VITE_BASE_API)
}
getApi()

2.3 gzip压缩配置

安装插件

pnpm add vite-plugin-compression -D

官网: github.com/vbenjs/vite…

// gzip压缩插件
import viteCompression from 'vite-plugin-compression';

export default defineConfig({
  plugins: [
    vue(),
    // gzip压缩
    viteCompression(),
  ],
 })

pnpm build打包之后可以看到gzip压缩前后的体积大小 image.png

2.4 图片压缩打包

安装插件

pnpm add vite-plugin-imagemin -D

官网: github.com/vbenjs/vite…

// 图片压缩插件
import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({
  plugins: [
    vue(),
    // 压缩图片
    viteImagemin({
      gifsicle: {
        optimizationLevel: 7,
        interlaced: false,
      },
      optipng: {
        optimizationLevel: 7,
      },
      mozjpeg: {
        quality: 20,
      },
      pngquant: {
        quality: [0.8, 0.9],
        speed: 4,
      },
      svgo: {
        plugins: [
          {
            name: 'removeViewBox',
          },
          {
            name: 'removeEmptyAttrs',
            active: false,
          },
        ],
      },
    }),
  ],
 })  

pnpm build打包之后可以看到图片压缩前后的体积大小 image.png

2.5 格式化

安装相关插件

  • @typescript-eslint/eslint-plugin 它作为 eslint 默认规则的补充,提供了一些额外的适用于 ts 语法的规则。
  • @typescript-eslint/parser 是 一个 ESLint 解析器,它可以将 TS 源代码解析为 TypeScript ESTree,然后在 TypeScript ESTree 之上构建规则。
  • eslint-plugin-vue 是对 .vue 文件进行代码校验的插件
pnpm add eslint prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser @vue/eslint-config-prettier @vue/eslint-config-typescript babel-eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue -D

.eslintrc.js文件

module.exports = {
  // 是否开启 eslint
  root: true,
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/typescript/recommended',
    '@vue/prettier',
  ],
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
  },
  rules: {
    'prettier/prettier': 'error',
    '@typescript-eslint/no-explicit-any': 0,
    '@typescript-eslint/indent': ['off'],
    '@typescript-eslint/no-unused-vars': ['error'],
  },
  globals: {
    defineProps: 'readonly',
    defineEmits: 'readonly',
    defineComponent: 'readonly',
    defineExpose: 'readonly',
  },
}

2.6 共享配置

项目运行会先查找根目录下的.vscode文件夹,执行里面的文件配置。如果没有.vscode文件夹,会按照本地的配置执行。 image.png