一文帶你了解vite對(duì)瀏覽器的請(qǐng)求做了什么
工作原理:
- type="module" 瀏覽器中ES Module原生native支持。 如果瀏覽器支持type="module" ,我i們可以使用es6模塊化的方式編寫。瀏覽器會(huì)把我們需要導(dǎo)入的文件再發(fā)一次http請(qǐng)求,再發(fā)到服務(wù)器上。 開發(fā)階段不需要打包
- 第三方依賴預(yù)打包
- 啟動(dòng)一個(gè)開發(fā)服務(wù)器處理資源請(qǐng)求
一圖詳解vite原理:
瀏覽器做的什么事啊
宿主文件index.html
<script type="module" src="/src/main.js"></script>
瀏覽器獲取到宿主文件中的資源后,發(fā)現(xiàn)還要再去請(qǐng)求main.js文件。會(huì)再向服務(wù)端發(fā)送一次main.js的資源請(qǐng)求。
main.js
在main中,可以發(fā)現(xiàn),瀏覽器又再次發(fā)起對(duì)vue.js?v=d253a66c、App.vue?t=1637479953836兩個(gè)文件的資源請(qǐng)求。
服務(wù)器會(huì)將App.vue中的內(nèi)容進(jìn)行編譯然后返回給瀏覽器,下圖可以看出logo圖片和文字都被編譯成_hoisted_ 的靜態(tài)節(jié)點(diǎn)。
從請(qǐng)求頭中,也可以看出sfc文件已經(jīng)變成瀏覽器可以識(shí)別的js文件(app.vue文件中要存在script內(nèi)容才會(huì)編譯成js)。對(duì)于瀏覽器來說,執(zhí)行的就是一段js代碼。
其他裸模塊
如果vue依賴中還存在其他依賴的話,瀏覽器依舊會(huì)再次發(fā)起資源請(qǐng)求,獲取相應(yīng)資源。
了解一下預(yù)打包
對(duì)于第三方依賴(裸模塊)的加載,vite對(duì)其提前做好打包工作,將其放到node_modules/.vite下。當(dāng)啟動(dòng)項(xiàng)目的時(shí)候,直接從該路徑下下載文件。
通過上圖,可以看到再裸模塊的引入時(shí),路徑發(fā)生了改變。
服務(wù)器做的什么事啊
總結(jié)一句話:服務(wù)器把特殊后綴名的文件進(jìn)行處理返回給前端展示。
我們可以模擬vite的devServe,使用koa中間件啟動(dòng)一個(gè)本地服務(wù)。
// 引入依賴 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 // 處理請(qǐng)求資源代碼都寫這 }) app.listen(3001, () => { console.log('dyVite start!!') })
請(qǐng)求首頁index.html
if (url === '/') { const p = path.join(__dirname, './index.html') // 絕對(duì)路徑 // 首頁 ctx.type = 'text/html' ctx.body = fs.readFileSync(p, 'utf8') }
看到上面這張圖,就知道我們的宿主文件已經(jīng)請(qǐng)求成功了。只是瀏覽器又給服務(wù)端發(fā)送的一個(gè)main.js文件的請(qǐng)求。這時(shí),我們還需要判斷處理一下main.js文件。
請(qǐng)求以.js結(jié)尾的文件
我們處理上述情況后,emmmm。。。發(fā)現(xiàn)main中還是存在好多其他資源請(qǐng)求。
基礎(chǔ)js文件
main文件:
console.log(1)
處理main:
else if (url.endsWith('.js')) { ? ?// 響應(yīng)js請(qǐng)求 ? ?const p = path.join(__dirname, url) ? ?ctx.type = 'text/javascript' ? ?ctx.body = rewriteImport(fs.readFileSync(p, 'utf8')) // 處理依賴函數(shù) }
對(duì)main中的依賴進(jìn)行處理
你以為main里面就一個(gè)輸出嗎?太天真了。這樣的還能處理嗎?
main文件:
import { createApp, h } from 'vue' createApp({ render: () => h('div', 'helllo dyVite!') }).mount('#app')
emmm。。。應(yīng)該可以!
我們可以將main中導(dǎo)入的地址變成相對(duì)地址。
在裸模塊路徑添加上/@modules/。再去識(shí)別/@modules/的文件即(裸模塊文件)。
// 把能讀出來的文件地址變成相對(duì)地址 // 正則替換 重寫導(dǎo)入 變成相對(duì)地址 // import { createApp } from 'vue' => import { createApp } from '/@modules/vue' function rewriteImport(content) { return content.replace(/ from ['|"](.*)['|"]/g, function (s0, s1) { // s0匹配字符串,s1分組內(nèi)容 // 是否是相對(duì)路徑 if (s1.startsWith('./') || s1.startsWith('/') || s1.startsWith('../')) { // 直接返回 return s0 } else { return ` from '/@modules/${s1}'` } }) }
對(duì)于第三方依賴,vite內(nèi)部是使用預(yù)打包請(qǐng)求自己服務(wù)器/node_modules/.vite/下的內(nèi)部資源。
我們可以簡單化一點(diǎn),將拿到的依賴名去客戶端下的node_modules下拿相應(yīng)的資源。
else if (url.startsWith('/@modules/')) { // 裸模塊的加載 const moduleName = url.replace('/@modules/', '') const pre的地址 const module = require(prefix + '/package.json').module const filePath = path.join(prefix, module) // 拿到文件加載的地址 // 讀取相關(guān)依賴 const ret = fs.readFileSync(filePath, 'utf8') ctx.type = 'text/javascript' ctx.body = rewriteImport(ret) //依賴內(nèi)部可能還存在依賴,需要遞歸 }
在main中進(jìn)行render時(shí),會(huì)報(bào)下圖錯(cuò)誤:
我們加載的文件都是服務(wù)端執(zhí)行的庫,內(nèi)部可能會(huì)產(chǎn)生node環(huán)境的代碼,需要判斷一下環(huán)境變量。如果開發(fā)時(shí),會(huì)輸出一些警告信息,但是在前端是沒有的。所以我們需要mock一下,告訴瀏覽器我們當(dāng)前的環(huán)境。
給html加上process環(huán)境變量。
?<script> ? ?window.process = { env: { NODE_ENV: 'dev' } } ?</script>
此時(shí)main文件算是加載出來了。
但是這遠(yuǎn)遠(yuǎn)打不到我們的目的啊!
我們需要的是可以編譯vue文件的服務(wù)器??!
處理.vue文件
main.js文件:
import { createApp, h } from 'vue' import App from './App.vue' createApp(App).mount('#app')
在vue文件中,它是模塊化加載的。
我們需要在處理vue文件的時(shí)候,對(duì).vue后面攜帶的參數(shù)做處理。
在此,我們簡化只考慮template和sfc情況。
else if (url.indexOf('.vue') > -1) { // 處理vue文件 App.vue?vue&type=style&index=0&lang.css // 讀取vue內(nèi)容 const p = path.join(__dirname, url.split('?')[0]) // compilerSfc解析sfc 獲得ast const ret = compilerSfc.parse(fs.readFileSync(p, 'utf8')) // App.vue?type=template // 如果請(qǐng)求沒有query.type 說明是sfc if (!query.type) { // 處理內(nèi)部的script const scriptContent = ret.descriptor.script.content // 將默認(rèn)導(dǎo)出配置對(duì)象轉(zhuǎn)為常量 const script = scriptContent.replace( 'export default ', 'const __script = ', ) ctx.type = 'text/javascript' ctx.body = ` ${rewriteImport(script)} // template解析轉(zhuǎn)換為單獨(dú)請(qǐng)求一個(gè)資源 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) }
總結(jié)
到此這篇關(guān)于vite對(duì)瀏覽器的請(qǐng)求做了什么的文章就介紹到這了,更多相關(guān)vite瀏覽器的請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue2安裝使用MonacoEditor方式(自定義語法,自定義高亮,自定義提示)
這篇文章主要介紹了Vue2安裝使用MonacoEditor方式(自定義語法,自定義高亮,自定義提示),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04解決element-ui el-input賦值后不能編輯的問題
這篇文章主要介紹了解決element-ui el-input賦值后不能編輯的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02element?ui組件中element.style怎么改詳解
element.style是一種內(nèi)聯(lián)樣式,一般都是代碼里寫死的,下面這篇文章主要給大家介紹了關(guān)于element?ui組件中element.style怎么改的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06vue中使用axios post上傳頭像/圖片并實(shí)時(shí)顯示到頁面的方法
今天小編就為大家分享一篇vue中使用axios post上傳頭像/圖片并實(shí)時(shí)顯示到頁面的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09