偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

在瀏覽器中,把 Vite 跑起來(lái)了!

系統(tǒng) 瀏覽器
大家好,我是 ssh,前幾天在推上沖浪的時(shí)候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運(yùn)行起來(lái)了。這引起了我的興趣,如何把重度依賴 node 的一個(gè) Vite 跑在瀏覽器上?

大家好,我是 ssh,前幾天在推上沖浪的時(shí)候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運(yùn)行起來(lái)了。這引起了我的興趣,如何把重度依賴 node 的一個(gè) Vite 跑在瀏覽器上?接下來(lái),就和我一起探索揭秘吧。

簡(jiǎn)而言之的原理

  • Service Worker[2]:用來(lái)取代 Vite 的 HTTP 服務(wù)器。
  • Web Worker[3]:運(yùn)行 browser-vite 來(lái)處理主線程。
  • 文件系統(tǒng)被一個(gè) in-memory 的模擬文件系統(tǒng)替代。
  • 轉(zhuǎn)換特殊擴(kuò)展名 (.ts, .tsx, .scss…) 的導(dǎo)入。

遇到的挑戰(zhàn)

沒(méi)有真正的文件系統(tǒng)

Vite[4] 用文件系統(tǒng)完成了很多工作。讀取項(xiàng)目的文件、監(jiān)聽(tīng)文件改變、globs 的處理等等……在瀏覽器的模擬實(shí)現(xiàn)的內(nèi)存文件系統(tǒng)中,這些就很難實(shí)現(xiàn)了,所以 browser-vite 刪除了監(jiān)聽(tīng)、globs 和配置文件來(lái)把復(fù)雜性降低。

項(xiàng)目文件被保存在內(nèi)存文件系統(tǒng)中,所以 broswer-vite 和 vite plugins 可以正常處理它們。

沒(méi)有 “node_modules”

Vite 依賴 node_modules 的存在來(lái)解析依賴。在啟動(dòng)時(shí)會(huì)把他們預(yù)打包(Dependencing Pre-Bundling)[5]來(lái)優(yōu)化。

同樣為了降低復(fù)雜度,所以 broswer-vite 非常小心的從 Vite 中刪除了 node_modules 解析和依賴預(yù)打包。

所以使用 browser-vite 的用戶需要?jiǎng)?chuàng)建一個(gè) Vite plugin[6] 來(lái)解析裸模塊導(dǎo)入。

正則表達(dá)式“后行斷言”

Vite 中的一些代碼用了后行斷言[7]。在 Node.js 里沒(méi)問(wèn)題,但是 Safari 不支持。

所以作者重寫(xiě)了這些正則。

熱更新(HMR)

Vite 用了 WebSockets[8] 來(lái)在服務(wù)端(node)和客戶端(browser)之間同步代碼變更。

在 browser-vite 中,服務(wù)端是 ServiceWorker + Vite worker,客戶端是 iframe。所以作者把 WebSockets 切換成了對(duì) iframe 使用 post message。

如何使用

截止本文撰寫(xiě)時(shí)間為止,這個(gè)工具還沒(méi)有做到開(kāi)箱即用,如果想使用的話,需要閱讀很多 Vite 內(nèi)部的處理細(xì)節(jié)。

如果感興趣的話,可以保持關(guān)注 browser-vite’s README[9] 來(lái)獲取最新的使用方式。

安裝

安裝 browser-vite npm 包。

  1. $ npm install --save browser-vite 

或者

  1. $ npm install --save vite@npm:browser-vite 

來(lái)將 "vite" 的 import 改寫(xiě)到 "browser-vite"

iframe - browser-vite 的窗口

需要一個(gè) iframe 來(lái)顯示由 browser-vite 提供的內(nèi)部頁(yè)面。

Service Worker - 瀏覽器內(nèi)的 Web 服務(wù)器

Service Worker 會(huì)捕獲到來(lái)自 iframe 的特定 url 請(qǐng)求。

一個(gè)使用 workbox[10] 的例子:

  1. workbox.routing.registerRoute( 
  2.   /^https?:\/\/HOST/BASE_URL\/(\/.*)$/, 
  3.   async ({ 
  4.     request, 
  5.     params, 
  6.     url, 
  7.   }: import('workbox-routing/types/RouteHandler').RouteHandlerCallbackContext): Promise<Response> => { 
  8.     const req = request?.url || url.toString(); 
  9.     const [pathname] = params as string[]; 
  10.     // send the request to vite worker 
  11.     const response = await postToViteWorker(pathname) 
  12.     return response; 
  13.   } 
  14. ); 

大多數(shù)情況下,對(duì) "Vite Worker" 發(fā)送消息用的是 postMessage[11] 和 broadcast-channel[12]。

Vite Worker - 處理請(qǐng)求

Vite Worker是一個(gè) Web Worker,它會(huì)處理 Service Worker 捕獲的請(qǐng)求。

創(chuàng)建 Vite 服務(wù)器的示例:

  1. import { 
  2.   transformWithEsbuild, 
  3.   ModuleGraph, 
  4.   transformRequest, 
  5.   createPluginContainer, 
  6.   createDevHtmlTransformFn, 
  7.   resolveConfig, 
  8.   generateCodeFrame, 
  9.   ssrTransform, 
  10.   ssrLoadModule, 
  11.   ViteDevServer, 
  12.   PluginOption 
  13. from 'vite'
  14.  
  15. export async function createServer = async () => { 
  16.   const config = await resolveConfig( 
  17.     { 
  18.       plugins: [ 
  19.         // virtual plugin to provide vite client/env special entries (see below) 
  20.         viteClientPlugin, 
  21.         // virtual plugin to resolve NPM dependencies, e.g. using unpkg, skypack or another provider (browser-vite only handles project files) 
  22.         nodeResolvePlugin, 
  23.         // add vite plugins you need here (e.g. vue, react, astro ...) 
  24.       ] 
  25.       base: BASE_URL, // as hooked in service worker 
  26.       // not really used, but needs to be defined to enable dep optimizations 
  27.       cacheDir: 'browser'
  28.       root: VFS_ROOT, 
  29.       // any other configuration (e.g. resolve alias) 
  30.     }, 
  31.     'serve' 
  32.   ); 
  33.   const plugins = config.plugins; 
  34.   const pluginContainer = await createPluginContainer(config); 
  35.   const moduleGraph = new ModuleGraph((url) => pluginContainer.resolveId(url)); 
  36.  
  37.   const watcher: any = { 
  38.     on(what: string, cb: any) { 
  39.       return watcher; 
  40.     }, 
  41.     add() {}, 
  42.   }; 
  43.   const server: ViteDevServer = { 
  44.     config, 
  45.     pluginContainer, 
  46.     moduleGraph, 
  47.     transformWithEsbuild, 
  48.     transformRequest(url, options) { 
  49.       return transformRequest(url, server, options); 
  50.     }, 
  51.     ssrTransform, 
  52.     printUrls() {}, 
  53.     _globImporters: {}, 
  54.     ws: { 
  55.       send(data) { 
  56.         // send HMR data to vite client in iframe however you want (post/broadcast-channel ...) 
  57.       }, 
  58.       async close() {}, 
  59.       on() {}, 
  60.       off() {}, 
  61.     }, 
  62.     watcher, 
  63.     async ssrLoadModule(url) { 
  64.       return ssrLoadModule(url, server, loadModule); 
  65.     }, 
  66.     ssrFixStacktrace() {}, 
  67.     async close() {}, 
  68.     async restart() {}, 
  69.     _optimizeDepsMetadata: null
  70.     _isRunningOptimizer: false
  71.     _ssrExternals: [], 
  72.     _restartPromise: null
  73.     _forceOptimizeOnRestart: false
  74.     _pendingRequests: new Map(), 
  75.   }; 
  76.  
  77.   server.transformIndexHtml = createDevHtmlTransformFn(server); 
  78.  
  79.   // apply server configuration hooks from plugins 
  80.   const postHooks: ((() => void) | void)[] = []; 
  81.   for (const plugin of plugins) { 
  82.     if (plugin.configureServer) { 
  83.       postHooks.push(await plugin.configureServer(server)); 
  84.     } 
  85.   } 
  86.  
  87.   // run post config hooks 
  88.   // This is applied before the html middleware so that user middleware can 
  89.   // serve custom content instead of index.html. 
  90.   postHooks.forEach((fn) => fn && fn()); 
  91.  
  92.   await pluginContainer.buildStart({}); 
  93.   await runOptimize(server); 
  94.    
  95.   return server; 

通過(guò) browser-vite 處理請(qǐng)求的偽代碼:

  1. import { 
  2.   transformRequest, 
  3.   isCSSRequest, 
  4.   isDirectCSSRequest, 
  5.   injectQuery, 
  6.   removeImportQuery, 
  7.   unwrapId, 
  8.   handleFileAddUnlink, 
  9.   handleHMRUpdate, 
  10. from 'vite/dist/browser'
  11.  
  12. ... 
  13.  
  14. async (req) => { 
  15.   let { url, accept } = req 
  16.   const html = accept?.includes('text/html'); 
  17.   // strip ?import 
  18.   url = removeImportQuery(url); 
  19.   // Strip valid id prefix. This is prepended to resolved Ids that are 
  20.   // not valid browser import specifiers by the importAnalysis plugin. 
  21.   url = unwrapId(url); 
  22.   // for CSS, we need to differentiate between normal CSS requests and 
  23.   // imports 
  24.   if (isCSSRequest(url) && accept?.includes('text/css')) { 
  25.     url = injectQuery(url, 'direct'); 
  26.   } 
  27.   let path: string | undefined = url; 
  28.   try { 
  29.     let code; 
  30.     path = url.slice(1); 
  31.     if (html) { 
  32.       code = await server.transformIndexHtml(`/${path}`, fs.readFileSync(path,'utf8')); 
  33.     } else { 
  34.       const ret = await transformRequest(url, server, { html }); 
  35.       code = ret?.code; 
  36.     } 
  37.     // Return code reponse 
  38.   } catch (err: any) { 
  39.     // Return error response 
  40.   } 

查看 Vite 內(nèi)部中間件源碼[13] 獲取更多細(xì)節(jié)。

和 Stackblitz WebContainers 相比如何

["WebContainers"](https://blog.stackblitz.com/posts/introducing-webcontainers/ ""WebContainers""):在瀏覽器中運(yùn)行 Node.js

Stackblitz 的 WebContainers 也可以在瀏覽器中運(yùn)行Vite。你可以去優(yōu)雅的去 vite.new 擁有一個(gè)工作環(huán)境。

作者表示自己不是 WebContainers 方面的專家,但簡(jiǎn)而言之,browser-vite 在 Vite 級(jí)別上模擬了 FS 和 HTTPS 服務(wù)器,WebContainers 在 Node.js 級(jí)別上模擬了 FS 和其他很多東西,而 Vite 只需做一些額外的修改就可在上面運(yùn)行。

它可以將 node_modules 存儲(chǔ)在瀏覽器的 WebContainer 中。但它不會(huì)直接運(yùn)行 npm 或 yarn,可能是因?yàn)闀?huì)占用太多空間。他們將這些命令鏈接到 Turbo[14] ———— 他們的包管理器。

WebContainers 也可以運(yùn)行其他框架,如 Remix[15]、SvelteKit[16] 或 Astro[17]。

這很神奇?這是令人興奮的?? 作者對(duì) WebContainer 的團(tuán)隊(duì)表示巨大的尊重,Stackblitz 團(tuán)隊(duì)牛逼!

WebContainers 的一個(gè)缺點(diǎn)是,它目前只能在 Chrome 上運(yùn)行[18],但可能很快就會(huì)在 Firefox 上運(yùn)行[19]。browser-vite 目前適用于 Chrome、Firefox和Safari瀏覽器。

簡(jiǎn)而言之,WebContainers在較低的抽象級(jí)別上運(yùn)行Vite。browser-vite在更高的抽象層次上運(yùn)行,非常接近Vite本身。

打個(gè)比方,對(duì)于那些復(fù)古游戲玩家來(lái)說(shuō),browser-vite 有點(diǎn)像 UltraHLE(任天堂 N64 模擬器)?????

(*) gametechwiki.com: 高/低層級(jí)模擬器[20]

作者接下來(lái)的計(jì)劃

browser-vite 是作者計(jì)劃的解決方案中的核心。打算逐步推廣到他們的全系列產(chǎn)品中:

  • Backlight.dev
  • Components.studio
  • WebComponents.dev
  • Replic.dev (即將發(fā)布的新應(yīng)用)

展望未來(lái),作者將繼續(xù)在 browser-vite 中投入,并向上游報(bào)告。上個(gè)月他們還宣布向 Evan You 和 Patak贊助來(lái)支持 Vite[21],以支持這個(gè)超贊的項(xiàng)目。

想知道更多?

GitHub庫(kù):browser-vite[22]

加入 Discord[23], 有一個(gè) #browser-vite 的頻道。??

參考資料

https://divriots.com/blog/vite-in-the-browser

https://github.com/divriots/browser-vite

https://blog.stackblitz.com/posts/introducing-webcontainers/

參考資料

[1]browser-vite: https://github.com/divriots/browser-vite

[2]Service Worker: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

[3]Web Worker: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers

[4]Vite: https://vitejs.dev/

[5]預(yù)打包(Dependencing Pre-Bundling): https://vitejs.dev/guide/dep-pre-bundling.html

[6]Vite plugin: https://vitejs.dev/guide/api-plugin.html

[7]

后行斷言: https://www.regular-expressions.info/lookaround.html

[8]WebSockets: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

[9]browser-vite’s README: https://github.com/divriots/browser-vite/blob/browser-vite/README.md#usage

[10]workbox: https://developers.google.com/web/tools/workbox

[11]postMessage: https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage

[12]broadcast-channel: https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API

[13]Vite 內(nèi)部中間件源碼: https://github.com/vitejs/vite/tree/main/packages/vite/src/node/server/middlewares

[14]Turbo: https://developer.stackblitz.com/docs/platform/turbo/

[15]Remix: https://blog.stackblitz.com/posts/remix-runs-on-webcontainers/

[16]SvelteKit: https://blog.stackblitz.com/posts/sveltekit-supported-in-webcontainers/

[17]Astro: https://blog.stackblitz.com/posts/astro-support/

[18]只能在 Chrome 上運(yùn)行: https://developer.stackblitz.com/docs/platform/browser-support

[19]在 Firefox 上運(yùn)行: https://developer.stackblitz.com/docs/platform/browser-support/#testing-on-firefox

[20]gametechwiki.com: 高/低層級(jí)模擬器: https://emulation.gametechwiki.com/index.php/High/Low_level_emulation

[21]向 Evan You 和 Patak贊助來(lái)支持 Vite: https://divriots.com/blog/supporting-vitejs

[22]browser-vite: https://github.com/divriots/browser-vite

[23]Discord: https://discord.gg/XkQxSU9

本文轉(zhuǎn)載自微信公眾號(hào)「前端從進(jìn)階到入院」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系前端從進(jìn)階到入院公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: 前端從進(jìn)階到入院
相關(guān)推薦

2009-04-29 14:40:17

2023-08-03 09:02:32

LangChain開(kāi)發(fā)GLM

2021-01-22 14:03:34

Flutter系統(tǒng)鴻蒙

2023-03-02 23:09:53

Node.jsC++JS

2010-07-13 09:31:08

RubyRuby on Rai

2011-05-04 11:26:47

優(yōu)化

2021-11-10 10:00:48

鴻蒙HarmonyOS應(yīng)用

2021-01-12 11:12:58

大數(shù)據(jù)智慧交通

2024-05-27 09:01:22

2022-12-06 09:03:44

代碼fork系統(tǒng)

2015-08-04 17:46:19

戴爾anycloud云計(jì)算

2017-11-17 15:25:02

Java線程安全

2012-05-15 13:29:20

HTML5

2023-01-31 07:42:29

代碼JDKMaven

2014-04-18 17:12:00

樂(lè)跑手環(huán)

2022-04-25 10:26:11

Python代碼瀏覽器

2012-02-21 13:50:29

瀏覽器遙控器

2023-05-17 00:10:55

GPU瀏覽器解鎖

2021-04-21 08:28:06

微軟EdgeGoogle

2019-09-03 08:00:00

電腦硬盤(pán)程序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)