vite 2.0 你学会了吗?

1,796 阅读5分钟

vite 的一些小知识

大致介绍

vite是vue作者尤雨溪开发的一款前端开发与构建工具,主要拥有以下几点优势:

  1. 在开发模式下,使用原生 ESM 文件,无需打包!传统的webpack项目,当项目拥有一定规模,页面较多的时候。启动devServer时,需要花费很长的时间。但是vite直接使用原声esm文件,启动开发模式几乎是秒开!
  2. 轻量快速的热重载。Vite实现热更新的方式主要是通过创建WebSocket建立浏览器与服务器建立通信,通过监听文件的改变像客户端发出消息,客户端对应不同的文件进行不同的操作的更新。
  3. 功能丰富:对 TypeScript、JSX、CSS 等支持开箱即用
  4. 在构建时使用rollup,支持多种模式的构建、同时支持各种rollup插件
  5. vite的api拥有完整的类型支持

从以上几点优势其实就可以大概看出,vite主要由下面两部分组成:

  1. 一个开发服务器,它基于原生ES模块提供了丰富的内建功能,如速度快到惊人的模块热更新(HMR)。

    • 关于es模块,大家可以阅读:JavaScript modules 模块
    • Vite 内置了模块热替换(hot module replacement)到 Vue 单文件组件(SFC) 和 React Fast Refresh 中。也通过 @prefresh/vite 对 Preact 实现了官方集成。当你使用 create an app via @vitejs/create-app 创建应用的时候,所选的模板就会为你预先配置这些功能。这与webpack相比,省去了很大一部分开发者需要配置的时间。
  2. 一套构建指令,它使用Rollup打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。

    • 关于Rollup,感兴趣的同学可以阅读:rollupjs

vite 对项目的构建优化

  1. build.cssCodeSplit 启用/禁用 CSS 代码拆分。默认为开启。 当启用时,在异步 chunk 中导入的 CSS 将内联到异步 chunk 本身,并在其被加载时插入。如果禁用,整个项目中的所有 CSS 将被提取到一个 CSS 文件中。 当我们的项目比较大的时候,项目的各个模块的css样式其实会相对独立。如果所有样式全部被打包成一个文件,用户在浏览一个大型web应用的某个页面,却要等待所有的资源加载完成,这明显是不合理的。 因此,开启这个配置,让css代码与异步chunk同步导入,可以加速页面的渲染。

    这个功能,在webpack中也有,但是需要下载对应的插件,并且配合css-loader使用。感兴趣的同学移步这里.

  2. 预加载指令生成。Vite 会为入口 chunk 和它们在打包出的 HTML 中的直接引入自动生成 <link rel="modulepreload"> 指令。 关于预加载指令,感兴趣的同学可以移步这里

    这个功能,在webpack中也有,同样需要配置插件。感兴趣的同学移步这里

  3. 异步 Chunk 加载优化。 在rollup项目中,被两个或以上的其他 chunk 共享的 chunk通常会生成共用Chunk,当其与动态导入相结合的时候,很容易出现以下情景

async-chunk.png

在无优化的情境下,当异步 chunk A 被导入时,浏览器将必须请求和解析 A,然后它才能弄清楚它也需要共用 chunk C。这会导致额外的网络往返.

Vite 将使用一个预加载步骤自动重写代码,来分割动态导入调用,以实现当 A 被请求时,C 也将 同时 被请求.

C 也可能有更深的导入,在未优化的场景中,这会导致更多的网络往返。Vite 的优化会跟踪所有的直接导入,无论导入的深度如何,都能够完全消除不必要的往返。

webpack 同样提供了代码分割为chunk 的功能,但是不同于vite的开箱即用且对其进行了加载优化,webpack还是需要额外的配置。感兴趣的同学移步这里

配置项介绍

以下是实际项目中的一份vite.config.js 文件:

import vue from '@vitejs/plugin-vue'
import eslint from '@rollup/plugin-eslint'
import path from 'path'
import moment from 'moment'

export default {
  mode, // 模式,在配置中指明将会把 serve 和 build 时的模式 都 覆盖掉。也可以通过命令行 --mode 选项来重写。
  plugins: [
    eslint({
      include: '**/*.+(vue|js|jsx|ts|tsx)',
      fix: false,
    }), // eslint插件,fix项开启会在启动项目时或者构建项目时修复eslint报错
    vue(),
  ],
  base: basePath, //开发或生产环境服务的公共基础路径
  build: {
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true,// 去除构建环境的debugger以及console
      },
    },
    chunkSizeWarningLimit: '1000',// 会产生警告的chunk文件大小
    rollupOptions: {
      // 传递给rollup 的配置,用于构建模式
      output: {
        manualChunks(id) {
          // 以下这段代码会根据条件,将符合条件的文件模块打包成特定的chunk文件
          // 将node_modules 中的包切割成单独的chunk,有助于文件的预加载、以及缓存优化
          if (id.includes('node_modules') && id.includes('ant-design-vue')) {
            return 'ant-design-vue'
          } else if (id.includes('node_modules') && id.includes('vue')) {
            return 'vue-module'
          } else if (id.includes('node_modules')) {
            return 'other-module'
          }
        },
      },
    },
  },
  resolve: {
    alias: {
      '/@src': path.resolve(__dirname, 'src'), // 设置别名
    },
  },
  define: {
    // 定义全局常量替换方式。字符串值将直接作为一个表达式,所以如果需要定义一个字符串常量,它需要被显式地引用(例如:通过 JSON.stringify)
    'BUILD_TIME': JSON.stringify(moment().format('YYYY-MM-DD HH:mm:ss')),
  },
  optimizeDeps: {
    include: [
      // 不是位于node_modules直接目录下的包不会被预构建,使用此选项可强制预构建链接的包
      'ant-design-vue/es/date-picker/locale/zh_CN',
      'ant-design-vue/es/locale/zh_CN',
      '@ant-design-vue/use',
    ],
  },
}

对应的vite版本以及相关插件的版本

{  
  "devDependencies": {
    "@rollup/plugin-eslint": "8.0.1",
    "@vitejs/plugin-vue": "1.1.0",
    "vite": "2.3.8"
  }
 }

其它

  1. 注意不同的版本的vite版本,对配置项的写法上会有一些差异。具体可以根据构建时的报错来进行修改。
  2. 有一篇分析vite原理的文章,写的比较详细。分享给大家: 深入 vite 原理:尤大最新力作到底是如何实现的?。不过这篇文章是2020年5月左右发表的,vite也在这将近一年的时间里,从1.0版本发布到了2.0版本,这里是更新日志,想要更加透彻的了解vite的工作方式,还是可以去阅读vite的源码:传送门