体验一把Vite

2/15/2021 Vite

# vite和webpack的区别

vite优点:快速冷启动、按需编译、模块热更新

  • webpack会先打包,然后启动开发服务器,请求服务器时直接给予打包结果。 而vite是直接启动开发服务器,请求哪个模块再对该模块进行实时编译。

  • 现代浏览器本身就支持ES Module,会自动向依赖的Module发出请求。 vite利用这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,vite在启动的时候不需要打包,不需要分析模块的依赖和编译,因此启动速度快

  • 当浏览器请求某个模块时,再根据需要对模块内容进行编译。按需动态编译缩减了编译时间。 在浏览器请求路由时才会进行打包,而且也仅仅打包当前路由的源码,这相当于让浏览器掌握了打包的控制权。从而将Bundle based dev server一次性打包全部源码的操作改为了多次

  • HMR方面,当改动了一个模块后,仅需让浏览器重新请求该模块,而webpack需要把该模块的相关依赖模块全部编译一次,效率更高。

    Webpack 的热更新会以当前修改的文件为入口重新 build 打包,所有涉及到的依赖也都会被重新加载一次。虽然webpack 也采用的是局部热更新并且是有缓存机制的,但是还是需要重新打包所以很大的代码项目是真的有卡顿的现象

    文件缓存:Vite 会将预构建的依赖缓存到node_modules/.vite。它根据几个源来决定是否需要重新运行预构建步骤:package.json中的 dependencies列表, package-lock等 浏览器缓存:源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable 进行强缓存

# 缺点

  • 生态不如webpack:wepback的loader和plugin非常丰富

  • prod环境的构建用Rollup:esbuild对于css和代码分割不是很友好

  • vite的主要优势在开发阶段。另外,由于vite利用的是ES Module,因此在代码中不可以使用CommonJS

# Vite 的原理

Vite 实现的核心——拦截浏览器对模块的请求并返回处理后的结果

浏览器发起的第一个请求 localhost:3000/,发送到 Vite 后端之后经过静态资源服务器的处理,会进而请求到 index.html,Vite对这个请求做拦截和处理了

把原本一个 .vue 的文件拆成了2个请求(分别对应 template和script、style ) ,浏览器会先收到包含 script和template 逻辑的 App.vue 的响应,然后解析到 style 的路径后,会再次发起 HTTP 请求来请求对应的资源,此时 Vite 对其拦截并再次处理后返回相应的内容。

  • vite1: 使用的是 koa
  • vite2: 使用的是 Connext; Connext更加是个转发
    请求服务器 --> 获取自己的代码 --> Connext拦截 -->vite工具处理成 es6.js代码---> Connext转发--->发送给浏览器

# ESBuild

vite打包快:基于ESBuild,ESbuild 是一个类似webpack构建工具。

  • ESBuild为什么这么快?
  • 使用GO语言编写的, 可以直接转换成机器代码, 而无需经过字节码;
  • ESBuild利用CPU的多内核,尽可能饱和运行;
  • ESBuild的所有内容都是从零开始编写的,而不是使用第三方,考虑各种性能问题;
  • Vite生产环境为什么选择Rollup做构建工具。
  • Vite是一个由原生ESM驱动的Web开发构建工具。在选择构建工具的时候也最好可以选择基于ESM的工具。
  • Rollup是基于ES2015的JavaScript打包工具。 它将小文件打包成一个大文件或者更复杂的库和应用,打包既可用于浏览器和Node.js使用。 Rollup最显著的地方就是能让打包文件体积很小。相比其他JavaScript打包工具,Rollup总能打出更小,更快的包。
  • 因为Rollup基于ES2015模块,比Webpack和Browserify使用的CommonJS模块机制更高效。

rollup打包生成代码的构建比较简单,总的流程的是先调用rollup.rollup()从入口开始编译,建立依赖关系图, 然后调用bundle.write()或bundle.generate()输出代码,其中bundle.write()会将代码输出到磁盘中。

# vite 搭建项目

npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install

//  或者
npm install -g create-vite-app

create-vite-app my-vue-app
cd my-vue-app
npm install
1
2
3
4
5
6
7
8
9
10
  • vite.config.js常用配置
import { defineConfig } from 'vite'
import { resolve } from "path"; 		// 主要用于alias文件路径别名
import vue from '@vitejs/plugin-vue'
import vueJsx from "@vitejs/plugin-vue-jsx"; // jsx插件

export default defineConfig({
    plugins: [vue(), vueJsx()], // 插件列表
    base: './',   				// 在生产中服务时的基本公共路径。 
    resolve: {
        alias: { "@": path.resolve(__dirname, './src'), } 	// 配置别名
    },
    // 引入第三方的配置,强制预构建插件包
    optimizeDeps: { include: ['echarts', 'axios', 'mockjs'], },
    // 打包配置
    build: {
        target: 'modules', 	// 最终构建的浏览器兼容目标。modules:支持原生 ES 模块的浏览器
        outDir: 'dist', 		// 指定输出路径
        assetsDir: 'assets', 	// 指定生成静态资源的存放路径
        sourcemap: false, 		// 构建后是否生成 source map 文件
        minify: 'terser' 		// 混淆器,terser构建后文件体积更小
    },
    // 本地运行配置,及反向代理配置
    server: {
        host: 'localhost', 		// 指定服务器主机名
        port: 3000, 		// 指定服务器端口
        open: true, 		// 在服务器启动时自动在浏览器中打开应用程序
        strictPort: false, // false-- 若端口已被占用则会尝试下一个可用端口,而不是直接退出
        https: false, 		// 是否开启 https
        cors: true, 		// 为开发服务器配置 CORS。默认启用并允许任何源
        proxy: { 			// 为开发服务器配置自定义代理规则
            '/foo': 'http://192.168.xxx.xxx:xxxx', 
            '/api': {
                target: 'http://192.168.xxx.xxx:xxxx', //代理接口
                changeOrigin: true,
                rewrite: (path) => path.replace(/^\/api/, '')
            }
        }
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39