vite 原理解析与实践

4 篇文章 0 订阅

vite 原理解析与实践

vite 是什么?

Vite (法语意为 “快速的”,发音 /vit/) 是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:

Vite 意在提供开箱即用的配置,同时它的 插件 APIJavaScript API 带来了高度的可扩展性,并有完整的类型支持。

vite项目初体验

创建新项目

npm init @vitejs/app my-react-demo --template react-ts

在这里插入图片描述

在这里插入图片描述

构建项目只用了2秒,启动项目只用了466毫秒,是不是特别快,那么它是怎么做到这么快的呢?

vite 的特点

  1. 快速的冷启动
  2. 真正的按需编译
  3. 即时的模块热更新

vite 部分功能原理解析

常见的模块规范
  • commonjs

语法类似于node,因为node使用commonjs规范,commonjs导入模块是同步导入,不能用于浏览器环境

//    文件名: foo.js
  //    依赖
  var $ = require('jquery');
  //    方法
  function myFunc(){};
  //    暴露公共方法(一个)
   module.exports = myFunc;
  • amd

由许多不喜欢commonjs的人员创造,最大特点是支持异步,但是语法不直观,不好书写

// 文件名: foo.js
    define(['jquery'], function ($) {
        //    方法
        function myFunc(){};

        //    暴露公共方法
        return myFunc;
    });
  • umd

其是amd和commonjs的统一规范,支持两种规范,即写一套代码,可用于多种场景。通常用作Rollup/ Webpack之类的bundler时通常用作备用模块

(function (root, factory) {
            if (typeof define === 'function' && define.amd) {
                // AMD
                define(['jquery'], factory);
            } else if (typeof exports === 'object') {
                // Node, CommonJS之类的
                module.exports = factory(require('jquery'));
            } else {
                // 浏览器全局变量(root 即 window)
                root.returnExports = factory(root.jQuery);
            }
        }(this, function ($) {
            //    方法
            function myFunc(){};

            //    暴露公共方法
            return myFunc;
        }));
  • ESM

ESM 是ES6提出的标准模块系统,就是我们经常使用的方式,浏览器支持,支持同步异步加载

import React from 'react';

各种模块详细特点可以查看下面链接

commonjs

es6

amd

npm 依赖解析和预构建

vite 在构建过程中使用esbuild进行构建,esbuild 是一个新的代码构建工具,近来构建速度及其迅猛,圈粉速度也很疯狂,它可以将 CommonJS / UMD 转换为 ESM 格式,转换ts, tsx文件等,它使用go编写,并编译成了机器码,利用paralleljs 的高并行优势,具有大量的并行算法。
在这里插入图片描述
在这里插入图片描述

为何 vite 不用 esbuild 打包?

esbuild这么厉害?为什么vite不适用esbuild 打包而使用rollup 呢?

esbuild的作为一个势头很强劲的开发工具,但是在代码分割和css处理方面还存在问题,相比来说rollup 更加成熟和灵活,但可能在不久的以后,当esbuild 稳定之后,esbuild很有可能会成为vite生产环境的构建工具。

vite插件简介

但是esbuild 的最低只兼容到es6,这也意味着一些 to C的项目会存在兼容行问题,那么vite怎么来解决的呢?

vite 通过它的插件系统来解决兼容性问题。(vite插件)

@vitejs/plugin-legacy 在 esbuild 构建之后再经过一层 @babel/preset-env,用来兼容不支持 ESM 或 ie11 的旧版浏览器。

在这要说的vite插件发展也及其迅速,下面是一部分插件截图
在这里插入图片描述

冷启动与按需编译

vite 的预编译是通过原生ES模块实现的,对于模块中使用的是commonjs或者AMD 的模块,则需要进行模块间的转换,同时减少模块间依赖降低请求次数

比如我们在使用lodash-es时,

import { debounce } from "lodash-es"

在这里插入图片描述

lodash-es会有上百个请求, 我们需要使用预编译去处理这种情况
在这里插入图片描述

这里节省的时间,我们指的就是预编译

在调用预编译后,vite会将运行的函数放到,构建的前置步骤上

const listen = httpServer.listen.bind(httpServer)
httpServer.listen = (async (port: number, ...args: any[]) => {
  try {
    await container.buildStart({})
    // 这里会进行依赖的预构建
    await runOptimize()
  } catch (e) {
    httpServer.emit('error', e)
    return
  }
  return listen(port, ...args)
}) as any
const runOptimize = async () => {
  if (config.optimizeCacheDir) {
    ..
    try {
      server._optimizeDepsMetadata = await optimizeDeps(config)
    }
    ..
    server._registerMissingImport = createMissingImpoterRegisterFn(server)
  }
}

通过runOptimize中的optimizeDeps方法会根据package.json 的 dependencies 的参数进行编译,然后将编译出来的依赖通过esbuild打包成单文件,当浏览器器请求时就可以保证只请求一次接口了。

各种文件转换

使用esbuild 将 .tsx .jsx .vue 等文件转化成浏览器可以识别的js文件

具体原理过程如下:

文件main.tsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
)

按理说index.html 中是不能引入react 代码的,也不会去认识.tsx文件的,这是怎么做到的呢?

当浏览器识别type="module"引入js文件的时候,内部的import 就会发起一个网络请求,尝试去获取这个文件

在这我们看下当前页面的请求:
在这里插入图片描述

vite 的作用就是体现在了这里,vite的任务就是用koa起一个http请求,然后利用拦截器去拦截修改这些请求内容,然后返回适合的内容

浏览器识别js代码实现大致原理:

const fs = require('fs')
const path = require('path')
const Koa = require('koa')

const app = new Koa()

app.use(async ctx=>{
  const {request:{url} } = ctx
  if(url=='/'){n
    ctx.type="text/html"
    ctx.body = fs.readFileSync('./index.html','utf-8')
  }else if(url.endsWith('.tsx')){
    const p = path.resolve(__dirname,url.slice(1))
    ctx.type = 'application/javascript'
    const content = fs.readFileSync(p,'utf-8')
    ctx.body = content
  }
})

app.listen(3001, ()=>{
  console.log('项目启动于3001端口')
})

模块热重载

对于热重载,我们先看下热重载的效果

热重载原理(以下均为模拟代码)

1、监听文件变动

使用node的 fs.watch监听文件变动

(fs.FSWatcher) fs.watch(filename[, options][, listener])

2、读取文件内容

使用node的fs.readFileSync 读取文件内容

${fs.readFileSync(runtimeFilePath, 'utf-8')}

3、通知浏览器更新

使用websocket 通知浏览器更新

Vite与webpack 的区别

从运行项目比较

见操作

从打包项目比较

见操作

webpack 打包图解

在这里插入图片描述

vite 打包图解

在这里插入图片描述

从上图可以看出:

webpack会先进行打包操作然后将,打包后的数据存储到内存中,然后启动服务器,与浏览器进行交互
而vite是直接启动开发服务器,请求哪个模块再对该模块进行实时编译,没有本地打包的过程

由于现代浏览器本身就支持ES Module,会自动向依赖的Module发出请求。vite充分利用这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像webpack那样进行打包合并。

由于vite在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。这种按需动态编译的方式,极大的缩减了编译时间,项目越复杂、模块越多,vite的优势越明显。

在HMR(热更新)方面,当改动了一个模块后,仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。

当需要打包到生产环境时,vite使用传统的rollup(也可以自己手动安装webpack来)进行打包,因此,vite的主要优势在开发阶段。

目前vite 存在的问题

  • vite 生态不及webpack
  • 在生产环境中使用的esbuild对css 和代码分割不够友好,这也是vite最终ebuild 又选择了rollup的原因
  • 对旧浏览器的兼容性不好

vite 会取代webpack 吗

现在的vite就像当初的M1,刚出现时大家都担心兼容性不好,但是一旦上手就发现真香,虽然目前还存在一些问题,但是vite使用平台原生的开发方式确实让人眼前一亮,并且非常容易上手,用户体验度也很高,并且原生的平台提供的标准特性,大部分也会发展为主流特性,所以vite极有可能代表了未来前端工程化的方向,同时在vue3 大生态的趋势下,vite已经成为前端开发者必须了解的一个框架。

那么vite到底会不会取代webpack 呢?我认为不会,对于vite的崛起,webpack不会坐视不管,如果未来webpack也将构建性能进行了优化,那么webpack将利于不败之地,就算webpack不进行优化,它现在稳定的生态环境和庞大用户量注定了webpack在未来很长的一段时间内构建工具老大的地位不会被动摇,而且在许多场景下性能并不是最重要的问题,所以我认为未来最有可能的一种情况是,webpack ,vite,rollup 三者形成三足鼎立的局面,三者相互借鉴共同发展。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值