vite对浏览器的请求做了什么

简介: 本文主要讲vite在浏览器的请求方面的作用

网络异常,图片无法展示
|



hello 大家好,🙎🏻‍♀️🙋🏻‍♀️🙆🏻‍♀️

我是一个热爱知识传递,正在学习写作的作者,ClyingDeng 凳凳!


工作原理:


  • type="module" 浏览器中ES Module原生native支持。 如果浏览器支持type="module",我i们可以使用es6模块化的方式编写。浏览器会把我们需要导入的文件再发一次http请求,再发到服务器上。 开发阶段不需要打包
  • 第三方依赖预打包
  • 启动一个开发服务器处理资源请求


一图详解vite原理:

网络异常,图片无法展示
|


浏览器做的什么事啊


宿主文件index.html


<script type="module" src="/src/main.js"></script>


浏览器获取到宿主文件中的资源后,发现还要再去请求main.js文件。会再向服务端发送一次main.js的资源请求。


网络异常,图片无法展示
|


main.js


在main中,可以发现,浏览器又再次发起对vue.js?v=d253a66cApp.vue?t=1637479953836两个文件的资源请求。


服务器会将App.vue中的内容进行编译然后返回给浏览器,下图可以看出logo图片和文字都被编译成_hoisted_ 的静态节点。


网络异常,图片无法展示
|


从请求头中,也可以看出sfc文件已经变成浏览器可以识别的js文件(app.vue文件中要存在script内容才会编译成js)。对于浏览器来说,执行的就是一段js代码。


网络异常,图片无法展示
|


其他裸模块


如果vue依赖中还存在其他依赖的话,浏览器依旧会再次发起资源请求,获取相应资源。


了解一下预打包


对于第三方依赖(裸模块)的加载,vite对其提前做好打包工作,将其放到node_modules/.vite下。当启动项目的时候,直接从该路径下下载文件。


网络异常,图片无法展示
|


通过上图,可以看到再裸模块的引入时,路径发生了改变。


服务器做的什么事啊


总结一句话:服务器把特殊后缀名的文件进行处理返回给前端展示

我们可以模拟vite的devServe,使用koa中间件启动一个本地服务。


// 引入依赖
const Koa = require('koa')
const app = new Koa()
const fs = require('fs')
const path = require('path')
const compilerSfc = require('@vue/compiler-sfc')
const compilerDom = require('@vue/compiler-dom')
app.use(async (ctx) => {
 const { url, query } = ctx.request
 // 处理请求资源代码都写这
})
app.listen(3001, () => {
  console.log('dyVite start!!')
})


请求首页index.html


if (url === '/') {
    const p = path.join(__dirname, './index.html') // 绝对路径
    //  首页
    ctx.type = 'text/html'
    ctx.body = fs.readFileSync(p, 'utf8')
  }


网络异常,图片无法展示
|

看到上面这张图,就知道我们的宿主文件已经请求成功了。只是浏览器又给服务端发送的一个main.js文件的请求。这时,我们还需要判断处理一下main.js文件。


请求以.js结尾的文件


我们处理上述情况后,emmmm。。。发现main中还是存在好多其他资源请求。


基础js文件


main文件:


console.log(1)


处理main:


else if (url.endsWith('.js')) {
    // 响应js请求
    const p = path.join(__dirname, url)
    ctx.type = 'text/javascript'
    ctx.body = rewriteImport(fs.readFileSync(p, 'utf8')) // 处理依赖函数
  }


对main中的依赖进行处理


你以为main里面就一个输出吗?太天真了。这样的还能处理吗?

main文件:


import { createApp, h } from 'vue'
createApp({ render: () => h('div', 'helllo dyVite!') }).mount('#app')


emmm。。。应该可以!

我们可以将main中导入的地址变成相对地址。

在裸模块路径添加上/@modules/。再去识别/@modules/的文件即(裸模块文件)。


// 把能读出来的文件地址变成相对地址
// 正则替换 重写导入 变成相对地址
// import { createApp } from 'vue'  => import { createApp } from '/@modules/vue'
function rewriteImport(content) {
  return content.replace(/ from ['|"](.*)['|"]/g, function (s0, s1) {
    //  s0匹配字符串,s1分组内容
    // 是否是相对路径
    if (s1.startsWith('./') || s1.startsWith('/') || s1.startsWith('../')) {
      // 直接返回
      return s0
    } else {
      return ` from '/@modules/${s1}'`
    }
  })
}


对于第三方依赖,vite内部是使用预打包请求自己服务器/node_modules/.vite/下的内部资源。 我们可以简单化一点,将拿到的依赖名去客户端下的node_modules下拿相应的资源。


else if (url.startsWith('/@modules/')) {
    // 裸模块的加载
    const moduleName = url.replace('/@modules/', '')
    const pre![1637477009328](imgs/1637477009328.png)![1637477009368](imgs/1637477009368.png)的地址
    const module = require(prefix + '/package.json').module
    const filePath = path.join(prefix, module) // 拿到文件加载的地址
    // 读取相关依赖
    const ret = fs.readFileSync(filePath, 'utf8')
    ctx.type = 'text/javascript'
    ctx.body = rewriteImport(ret) //依赖内部可能还存在依赖,需要递归
  }
复制代码


在main中进行render时,会报下图错误:


网络异常,图片无法展示
|


我们加载的文件都是服务端执行的库,内部可能会产生node环境的代码,需要判断一下环境变量。如果开发时,会输出一些警告信息,但是在前端是没有的。所以我们需要mock一下,告诉浏览器我们当前的环境。

给html加上process环境变量。


<script>
    window.process = { env: { NODE_ENV: 'dev' } }
  </script>


此时main文件算是加载出来了。

但是这远远打不到我们的目的啊!

我们需要的是可以编译vue文件的服务器啊!


处理.vue文件


main.js文件:


import { createApp, h } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')


在vue文件中,它是模块化加载的。


网络异常,图片无法展示
|


我们需要在处理vue文件的时候,对.vue后面携带的参数做处理。

在此,我们简化只考虑template和sfc情况。


else if (url.indexOf('.vue') > -1) {
    // 处理vue文件  App.vue?vue&type=style&index=0&lang.css
    // 读取vue内容
    const p = path.join(__dirname, url.split('?')[0])
    // compilerSfc解析sfc  获得ast
    const ret = compilerSfc.parse(fs.readFileSync(p, 'utf8'))
    // App.vue?type=template
    // 如果请求没有query.type 说明是sfc
    if (!query.type) {
      // 处理内部的script
      const scriptContent = ret.descriptor.script.content
      // 将默认导出配置对象转为常量
      const script = scriptContent.replace(
        'export default ',
        'const __script = ',
      )
      ctx.type = 'text/javascript'
      ctx.body = `
  ${rewriteImport(script)}
  // template解析转换为单独请求一个资源
  import {render as __render} from '${url}?type=template'
  __script.render = __render
  export default __script
`
    } else if (query.type === 'template') {
      const tpl = ret.descriptor.template.content
      // 编译包含render模块
      const render = compilerDom.compile(tpl, { mode: 'module' }).code
      ctx.type = 'text/javascript'
      ctx.body = rewriteImport(render)
    }
  }


处理图片路径


直接从客户端读取返回。


else if (url.endsWith('.png')) {
    ctx.body = fs.readFileSync('src' + url)
  }


文末有惊喜


感谢大家一直一来支持与鼓励, 今天我的文章终于过百啦!

可以先点个关注🙋‍♀️,防止迷路!

如果评论区超过 20 人互动,一赞一评👍!

我将抽取一位幸运读者,送出掘金马克杯(或者掘金搪瓷杯)一个🙇‍♀️!

还是老样子(不需要承担运费哦)😁!

网络异常,图片无法展示
|

网络异常,图片无法展示
|

活动截止11月30号!心动不如行动🎈🎈🎈!

抽奖方式:使用随机数方式抽取第random位评论者✨。

随机数random区间:最大值取点赞数评论数的最小值。

中奖的幸运儿这次不用担心过期啦,我会一直等到你回复我的哈🤞🤞🤞!

感兴趣的朋友可以关注 vite系列专栏或者点击关注作者哦(●'◡'●)!。 如果不足,请多指教。


幸运儿揭秘的🎊


幸运儿会是谁呢?!


网络异常,图片无法展示
|


本文一共65个评论!去除重复的一条,共64条。

激动人心的时候到啦!📢

恭喜第37位评论的幸运儿!


前端木木


网络异常,图片无法展示
|

目录
相关文章
|
4月前
|
测试技术
用navigator.sendBeacon完成网页埋点异步请求记录用户行为,当网页关闭的时候,依然后完美完成接口请求,不会因为浏览器关闭了被中断请求。
用navigator.sendBeacon完成网页埋点异步请求记录用户行为,当网页关闭的时候,依然后完美完成接口请求,不会因为浏览器关闭了被中断请求。
|
2月前
|
缓存 JavaScript 前端开发
浏览器处理预检请求的响应
浏览器处理预检请求的响应
|
2月前
|
缓存 网络协议 Java
(六)网络编程之化身一个请求感受浏览器输入URL后奇妙的网络之旅!
在浏览器上输入一个URL后发生了什么? 这也是面试中老生常谈的话题,包括网上也有大量关于这块的内容。
Request请求转发和重定向的资源路径问题,目录到底加不加,取决于浏览器用,还是服务器用,规避项目目录发生修改,导致重定向失败
Request请求转发和重定向的资源路径问题,目录到底加不加,取决于浏览器用,还是服务器用,规避项目目录发生修改,导致重定向失败
|
3月前
|
域名解析 存储 缓存
HTTP请求流程概览:浏览器构建请求行含方法、URL和版本;检查缓存;解析IP与端口
【6月更文挑战第23天】 HTTP请求流程概览:浏览器构建请求行含方法、URL和版本;检查缓存;解析IP与端口;TCP连接(HTTP/1.1可能需排队);三次握手;发送请求头与体;服务器处理并返回响应;TCP连接可能关闭或保持;浏览器接收并显示响应,更新缓存。HTTP版本间有差异。
60 5
|
3月前
|
JSON JavaScript 数据格式
postman如何模拟浏览器发送post请求,意思是替代Vue向后端发送一个请求
postman如何模拟浏览器发送post请求,意思是替代Vue向后端发送一个请求
|
4月前
|
前端开发 JavaScript API
如何在不同浏览器中创建和使用 XMLHttpRequest 对象来执行 HTTP 请求
如何在不同浏览器中创建和使用 XMLHttpRequest 对象来执行 HTTP 请求
|
4月前
|
缓存 安全
控制浏览器发送请求采用请求方式的详细介绍
本文讲述了HTTP请求的GET和POST两种主要方式。GET请求限制参数不超过4K,参数显示在地址栏并缓存资源;POST请求能携带任意数量参数,参数隐藏在请求体,不保存资源。GET常用于超链接和表单默认提交,POST适用于文件上传、登录验证和获取实时数据等场景,因安全考虑,部分网站仅接受GET请求。可通过表单的method属性设置请求方式,默认为GET。
51 0
|
4月前
|
前端开发 JavaScript
同源策略下,服务器会收到浏览器的请求吗?
同源策略下,服务器会收到浏览器的请求吗?
|
4月前
|
安全 开发者
【问题篇】浏览器get请求带token
【问题篇】浏览器get请求带token
261 0

热门文章

最新文章