vite 原理解析与实践

2023-11-12

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 三者形成三足鼎立的局面,三者相互借鉴共同发展。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vite 原理解析与实践 的相关文章

  • webpack根据chunk加载不同的模块

    是否可以让 webpack 根据某些上下文信息加载另一个模块 例如 我的 React 应用程序有两个版本 桌面版和移动版 在我的 index js 中 我决定加载哪个应用程序 if isMobile loadMobile then defa
  • Vite Vue 3 库构建并不隐式包含 dist/style.css

    我构建了一个库项目 Vue 3 Vite 我想通过以下方式将其包含在主机项目中package json 但我遇到了一个问题 我可以导入组件并使用这些导入的组件运行一个简单的程序 但它们的样式消失了 请让我知道我的配置有什么问题 当我必须手动
  • Webpack 的 sass-loader 构建时间较慢

    Summary 当我们改用 Webpack 处理 SASS 文件时 我们注意到在某些情况下构建时间变得非常慢 使用以下方法测量构建的不同部分的性能后测速插件 https www npmjs com package speed measure
  • 如何使用 Webpack 同时创建包的“web”和“node”版本?

    有没有一种方法可以使用 Webpack 或 Browserify 一次性创建捆绑包的 web 和 node 版本 捆绑包的 web 版本将在客户端上使用 同一捆绑包的 节点 版本将在服务器上用于预渲染 同构 http nerds airbn
  • webpack-dev-server 中的代理 websockets 连接

    是否可以在 webpack 开发服务器中代理 websocket 连接 我知道如何将常规 HTTP 请求代理到另一个后端 但它不适用于 websockets 大概是因为代理配置中的目标以 http 开头 webpack dev server
  • Vue cli 3项目,图像路径中的动态src不起作用

    我在 vue 组件中引用图像 url 例如 img alt Vue logo src statics reports logo png 这有效 但在尝试的同时 img alt Vue logo data return imgPath sta
  • 如何从捆绑 .spec.js 文件中排除 webpack

    我的 Package bundle 读取 var reqContext require context true js reqContext keys map reqContext 其中基本上包括所有 js 文件 我希望表达式排除任何 sp
  • 如何在Vite配置中更改antd主题?

    是一个由Vite和React antd组成的项目 我想在 vite config ts 中动态处理 antd 主题 如果您能告诉我如何修改 React 组件中的 less modifyVars 值 我将不胜感激 这是当前屏幕 光状态 htt
  • Karma 与 Webpack 和 Typescript 不执行任何测试

    我试图弄清楚如何将 Karma 测试运行器与 Webpack 和 Typescript 源文件一起使用 以此源文件作为唯一的测试文件为例 测试规格 var message string yay alert message describe
  • Vue.js 严格模式下不允许对一个属性进行多个定义

    再会 我们正在使用 Vuejs Vuex vue router 构建我们的应用程序https github com vuejs vue hackernews 2 0 https github com vuejs vue hackernews
  • 使用 webpacker 部署到 heroku 后,资产不存在于资产管道中

    我正在使用 Rails 5 2 3 我可以在本地下载 pdf 但Heroku它通过错误 500 错误是 ActionView Template Error 资源 pdf css 不存在于资源管道中 这是我的 Heroku 日志 2019 0
  • 如何在 Rollup 中配置从多个输入文件仅生成单个输出文件?

    配置Rollupjs生成库时 如果输入是由多个javascript文件组成的数组 我们如何才能将这些输入生成为一个输出 js 文件呢 export const lgService input src app services livegiv
  • 如何全局公开 es6 模块

    我需要编写一个可在全局窗口上使用的模块 我使用 es6 创建模块 我定义的每个类都有它自己的文件 我正在使用 webpack 来 babelify 并捆绑这些类 我的模块的入口点也是包含要公开的全局的文件 我尝试了各种方法来实现这一点 包括
  • 未捕获的异常:无法找到 Mix 文件

    我正在尝试在本地系统中运行 laravel 应用程序 我已遵循https gist github com hootlex da59b91c628a6688ceb1 https gist github com hootlex da59b91c
  • 找不到模块“webpack”

    决定不在我的项目中使用 webpack 当我把它从package json出现以下错误ng s 找不到模块 webpack 错误 找不到模块 webpack 在 Function Module resolveFilename 内部 modu
  • 使用HTMLWebpackPlugin时如何通过webpack加载图片?

    我正在使用 HTMLWebpackPlugin 在我的模板中我有一个 img 标签 img src images logo png 如果您注意到 这里我使用相对路径 认为 webpack 将触发在 webpack config js 文件中
  • 覆盖 vuetify 中的 scss 变量

    为了增加 vuetify 的 v switch 的宽度 我想修改 vuetify 的 scss 变量的值 vuetify是通过vue cli配置的 开发的代码如下 src assets css overrides scss font siz
  • 将 jsonwebtoken 与 angular-cli 应用程序一起使用时出错

    我有一个 angular2 应用程序 它使用角度 cli https github com angular angular cli 20angular cli用于脚手架和其他任务 但现在我不能使用jsonwebtoken https git
  • 为什么 Webpack 忽略我的 CSS 文件?

    我正在尝试让 webpack 将我的 CSS 文件 使用 PostCSS 编译为单独的文件 从文档来看 这似乎正是 ExtractTextPlugin 应该做的 但是 我无法让 webpack 对我的 CSS 文件执行任何操作 相关项目结构
  • Sentry 与 @sentry/webpack-plugin 和 heroku

    我正在使用 webpack 来构建我的应用程序 它可以在本地使用 sentry webpack plugin 它自动生成版本并将源映射上传到 Sentry 但是 如果我尝试在 Heroku 上构建相同的应用程序 则会出现以下错误 Error

随机推荐