日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
【vite】你不知道的小妙招,確定不看一下嗎?

分析 version:2.3.7。本文將整理 vite 靜態(tài)資源的幾種處理方式,應用案例和源碼分析相結合,帶你 10mins 通關該模塊知識~

公司主營業(yè)務:成都網站設計、網站建設、移動網站開發(fā)等業(yè)務。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出墊江免費做網站回饋大家。

一.處理的五種方式

(1) 使用根絕對路徑引入 public 中的資源

 
 
 
 
  1.  

敲重點!

  • publicDir 放靜態(tài)資源的目錄,默認為 public
  • 引入 public 中的資源永遠應該使用根絕對路徑 —— 舉個,public/wy-logo.png 應該在源碼中被引用為 /wy-logo.png。在開發(fā)時能直接通過${yourHost}/wy-logo.png根路徑訪問到。
  • public 中的資源不應該被 JavaScript 文件引用。

接下來我們來康康代碼處理:當我們直接/wy-logo.png 訪問資源:

以下是 public 靜態(tài)資源中間件處理入口 - vite/src/node/server/index.ts:

 
 
 
 
  1. if (config.publicDir) { 
  2.     middlewares.use(servePublicMiddleware(config.publicDir)) 
  3.  } 

這時候大家就有疑問了,怎樣才會走到 isImportRequest,以及為什么這么干?別急,下面我們慢慢嘮~

(2)通用 import 靜態(tài)資源, 返回[解析后]的公共路徑

首先,啥子是通用靜態(tài)資源嘞~~

是 vite 支持的默認資源類型:

KNOWN_ASSET_TYPES = ["png", "jpe?g", "gif", "svg", "ico", "webp", "avif", "mp4", "webm", "ogg", "mp3", "wav", "flac", "aac", "woff2?", "eot", "ttf", "otf", "wasm"]

是你自定義的放到 assetsInclude 配置中的文件

其次,我們來康康,靜態(tài)資源的導入

 
 
 
 
  1.  
  2.  

這是我們的輸入和輸出:我們可以看到每個 import 都會被處理成 xxx?import 請求,返回解析后的代碼,得到一個公共可訪問 url

然后,我們依舊根據 wy-logo 圖片來對比分析~ 之前是直接靜態(tài)文件訪問,提前返回資源,不會被解析成 import 依賴 反之如果作為 js 文件 import 引入,則不會當成正常靜態(tài)資源,都得優(yōu)先處理成通用&import js 文件,:

 
 
 
 
  1. import logo from '../../public/wy-logo.png' 
  2. console.log(logo) 

關鍵代碼:

 
 
 
 
  1. // 從初始執(zhí)行 cli 處啟動 createServer - vite/src/node/server/index.ts 
  2. // 會調用 resolveConfig()獲取 config, 而該方法里會調用 resolvePlugins(), 
  3. // 其中有個 plugin 處理是: importAnalysisPlugin(config) 
  4. // 所在文件如下: 
  5. import { importAnalysisPlugin } from './importAnalysis' 
  6.  
  7. // 在 importAnalysic.js 里有個關鍵方法: 
  8. async transform(source, importer, ssr) { 
  9.   // 用`?import`標識非 js/css 的 import 依賴 
  10.   url = markExplicitImport(url) 

可以看到 public 下的靜態(tài)資源直接請求會直接返回,反之 import 靜態(tài)資源的話 - 處理成/public/wy-logo.png?importwy-logo.png?import。需要后續(xù)通過返回解析后的 url 再去訪問資源。es-module-lexer 解析處理:

這時候大家就理解了之前的疑問,isImportRequest 需要區(qū)分是否是直接的靜態(tài)資源請求,如果是 import xxx 來引入的,都統(tǒng)一處理成依賴,給到你最終需要的一個 URL => 【公共靜態(tài)資源訪問路徑】。這就是為什么 public 中的資源不建議被 JavaScript 文件引用,因為 publicDir 資源文件的定義就是直接可以請求,沒有必要解析獲取 url 后再請求!!!

(3)非通用靜態(tài)資源?可顯式 URL

引入 ?url通用靜態(tài)資源可以直接處理獲取 url,那要是想要處理其他資源,怎么顯式導入為一個 URL 來用 (⊙_⊙)? 答案是用?url后綴 ../data/name.js:

 
 
 
 
  1. export const nameList = ['Tim', 'John', 'Bob', 'Catherine'] 
  2. console.log(`名稱列表 = `, nameList.join('  ')) 

components/name.vue

 
 
 
 
  1. import nameListUrl from '../data/name.js?url' 
  2. console.log(nameListUrl) // 解析成'/src/data/name.js' 

源碼解析: 同理,也是在resolvePlugins()里面有對 asset 處理的assetPlugin

 
 
 
 
  1. const urlRE = /(\?|&)url(?:&|$)/ 
  2. async load(id) { 
  3.  ... 
  4.   // 如果沒有被配置到靜態(tài)資源 assetsInclude 并且 沒有?url 后綴的,直接返回 
  5.   if (!config.assetsInclude(cleanUrl(id)) && !urlRE.test(id)) { 
  6.     return 
  7.   } 
  8.  
  9.   id = id.replace(urlRE, '$1').replace(/[\?&]$/, '') 
  10.   const url = await fileToUrl(id, config, this) // 獲取公共可訪問路徑 
  11.   return `export default ${JSON.stringify(url)}` // 返回解析后的代碼 

(4)將資源引入為字符串 ?raw

同一個例子,我們要獲取 name.js 的數(shù)據:1.場景 1 是獲取執(zhí)行 name.js 后輸出的數(shù)據 2.場景 2 是僅僅要獲取 name.js 的文本,比如我們可以做 template 的字符串,那就需要使用到?raw后綴了。

 
 
 
 
  1. import nameString from '../data/name.js?raw' 
  2. console.log(nameString) // 解析出 export default "xxxxx" 文本 

上源碼。依舊是assetPlugin

 
 
 
 
  1. const rawRE = /(\?|&)raw(?:&|$)/ 
  2. async load(id) { 
  3.  ... 
  4.   // raw requests, read from disk 
  5.   if (rawRE.test(id)) { 
  6.     // publicDir 存在同名靜態(tài)文件,優(yōu)先返回 
  7.     const file = checkPublicFile(id, config) || cleanUrl(id) 
  8.     // ?raw 作為 query, 讀取對應的文件并且返回其字符串 
  9.     return `export default ${JSON.stringify( 
  10.       await fsp.readFile(file, 'utf-8') 
  11.     )}` 
  12.   } 
  13.   ... 

(5)導入腳本作為 Worker ?worker

腳本可以通過 ?worker 或 ?sharedworker 后綴導入為 web worker。上案例:/data/name-worker.js

 
 
 
 
  1. export const nameList = ['Tim', 'John', 'Bob', 'Catherine'] 
  2. addEventListener('message', (e) => { 
  3.   console.log('主線程: ', e.data) 
  4.   postMessage({ 
  5.     word: `Hi,我是 worker~~ 老大,這是你要的名單:${nameList.join(' ')}`, 
  6.     nameList 
  7.   }) 
  8.   close() // 關閉 worker 
  9. }, false) 

/components/name.vue

 
 
 
 
  1. import NameWorker from '../data/name-worker.js?worker' 
  2. export default defineComponent({ 
  3.   mounted () { 
  4.     const worker = new NameWorker() 
  5.     worker.postMessage('Hi, 我是主線程~') // 主線程向 Worker 發(fā)消息 
  6.     worker.onmessage = (e) => { // 接收子線程發(fā)回來的消息 
  7.       if (e.data) { 
  8.         console.log('Worder: ' + e.data.word) 
  9.         this.workerNameList = e.data.nameList 
  10.         worker.terminate() // Worker 完成任務以后,主線程就可以把它關掉 
  11.       } 
  12.     } 
  13.     worker.onerror = (e) => { 
  14.       console.log([ 
  15.         'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message 
  16.       ].join('')) 
  17.     } 
  18.   } 
  19. }) 

這里,就是給 name-worker.js 封裝了一層,提供了 WorkerWrapper 函數(shù)幫你新建了一個 worker 對象

debug 圖如下:

源碼?!景““?!!源碼可真多,我可太暴躁了】

resolvePlugins()里 執(zhí)行webWorkerPlugindev 開發(fā)環(huán)境下:

 
 
 
 
  1. async transform(_, id) { 
  2.     const query = parseWorkerRequest(id) 
  3.     let url: string 
  4.     url = await fileToUrl(cleanUrl(id), config, this) // 原始 url 
  5.     url = injectQuery(url, WorkerFileId) // 加上&worker_file 的 query 標識 
  6.  
  7.     const workerConstructor = 
  8.       query.sharedworker != null ? 'SharedWorker' : 'Worker' 
  9.     const workerOptions = { type: 'module' } 
  10.  
  11.     return `export default function WorkerWrapper() { // 輸出新建 worker 對象的 template 
  12.       return new ${workerConstructor}(${JSON.stringify( 
  13.       url 
  14.     )}, ${JSON.stringify(workerOptions, null, 2)}) 
  15.     }` 

build 生產下:inline 模式和非 inline 模式

 
 
 
 
  1. if (query.inline != null) { 
  2.   // 打包文件作為入口去支持 import 導入 worker 或者行內寫入 
  3.   const rollup = require('rollup') as typeof Rollup 
  4.   const bundle = await rollup.rollup({ 
  5.     input: cleanUrl(id), 
  6.     plugins: config.plugins as Plugin[] 
  7.   }) 
  8.   try { 
  9.     // 在生產構建中將會分離出 chunk,worker 腳本將作為單獨的塊發(fā)出 
  10.     const { output } = await bundle.generate({ 
  11.       format: 'es', 
  12.       sourcemap: config.build.sourcemap 
  13.     }) 
  14.   
  15.     return `const blob = new Blob([atob(\"${Buffer.from(output[0].code).toString('base64')}\")], { type: 'text/javascript;charset=utf-8' }); 
  16.     export default function WorkerWrapper() { 
  17.       const objURL = (window.URL || window.webkitURL).createObjectURL(blob); 
  18.       try { 
  19.         return new Worker(objURL); 
  20.       } finally { 
  21.         (window.URL || window.webkitURL).revokeObjectURL(objURL); 
  22.       } 
  23.     }` 
  24.   } finally { 
  25.     await bundle.close() 
  26.   } 
  27. } else { 
  28.   // 作為分開的 chunk 處理`?worker&inline`,內聯(lián)為 base64 字符串 - 要求 inline 的 worker 
  29.   url = `__VITE_ASSET__${this.emitFile({ 
  30.     type: 'chunk', 
  31.     id: cleanUrl(id) 
  32.   })}__` 
  33.   ....// 同開發(fā)返回的 template 

咦~,那這個/src/data/name-worker.js?worker_file 又通過?worker_file后綴給我們處理啥了?webWorkerPlugin:

 
 
 
 
  1. const WorkerFileId = 'worker_file' 
  2. async transform(_, id) { 
  3.     const query = parseWorkerRequest(id) 
  4.     if (query && query[WorkerFileId] != null) { 
  5.       return { 
  6.         // 其實只是作為 執(zhí)行導入之前生成的 worker.js 文件 的標識....... 
  7.         code: `import '${ENV_PUBLIC_PATH}'\n` + _ 
  8.       } 
  9.     } 

害!五個靜態(tài)處理方式總算是講完了~

二. 總結

vite 的靜態(tài)處理關鍵點就是 :

(1)通過特殊 query(?:worker|sharedworker|raw|url)來區(qū)分不同類型靜態(tài)資源,進行特殊的 transform 處理。

(2)publicDir 限定直接訪問的靜態(tài)資源 本文通過列舉處理點,逐一提供案例+debug 截圖+源碼分析的方式,讓大家理解靜態(tài)處理的使用和底層原理。


當前標題:【vite】你不知道的小妙招,確定不看一下嗎?
分享鏈接:http://www.dlmjj.cn/article/dphocss.html