自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在瀏覽器中,把 Vite 跑起來了!

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

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

簡而言之的原理

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

遇到的挑戰(zhàn)

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

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

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

沒有 “node_modules”

Vite 依賴 node_modules 的存在來解析依賴。在啟動時會把他們預打包(Dependencing Pre-Bundling)[5]來優(yōu)化。

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

所以使用 browser-vite 的用戶需要創(chuàng)建一個 Vite plugin[6] 來解析裸模塊導入。

正則表達式“后行斷言”

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

所以作者重寫了這些正則。

熱更新(HMR)

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

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

如何使用

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

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

安裝

安裝 browser-vite npm 包。

  1. $ npm install --save browser-vite 

或者

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

來將 "vite" 的 import 改寫到 "browser-vite"

iframe - browser-vite 的窗口

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

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

Service Worker 會捕獲到來自 iframe 的特定 url 請求。

一個使用 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ù)情況下,對 "Vite Worker" 發(fā)送消息用的是 postMessage[11] 和 broadcast-channel[12]。

Vite Worker - 處理請求

Vite Worker是一個 Web Worker,它會處理 Service Worker 捕獲的請求。

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

  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; 

通過 browser-vite 處理請求的偽代碼:

  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] 獲取更多細節(jié)。

和 Stackblitz WebContainers 相比如何

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

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

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

它可以將 node_modules 存儲在瀏覽器的 WebContainer 中。但它不會直接運行 npm 或 yarn,可能是因為會占用太多空間。他們將這些命令鏈接到 Turbo[14] ———— 他們的包管理器。

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

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

WebContainers 的一個缺點是,它目前只能在 Chrome 上運行[18],但可能很快就會在 Firefox 上運行[19]。browser-vite 目前適用于 Chrome、Firefox和Safari瀏覽器。

簡而言之,WebContainers在較低的抽象級別上運行Vite。browser-vite在更高的抽象層次上運行,非常接近Vite本身。

打個比方,對于那些復古游戲玩家來說,browser-vite 有點像 UltraHLE(任天堂 N64 模擬器)?????

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

作者接下來的計劃

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

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

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

想知道更多?

GitHub庫:browser-vite[22]

加入 Discord[23], 有一個 #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]預打包(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 上運行: https://developer.stackblitz.com/docs/platform/browser-support

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

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

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

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

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

本文轉(zhuǎn)載自微信公眾號「前端從進階到入院」,可以通過以下二維碼關注。轉(zhuǎn)載本文請聯(lián)系前端從進階到入院公眾號。

 

責任編輯:武曉燕 來源: 前端從進階到入院
相關推薦

2023-08-03 09:02:32

LangChain開發(fā)GLM

2009-04-29 14:40:17

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應用

2024-05-27 09:01:22

2021-01-12 11:12:58

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

2022-12-06 09:03:44

代碼fork系統(tǒng)

2015-08-04 17:46:19

戴爾anycloud云計算

2012-05-15 13:29:20

HTML5

2017-11-17 15:25:02

Java線程安全

2023-01-31 07:42:29

代碼JDKMaven

2014-04-18 17:12:00

樂跑手環(huán)

2022-04-25 10:26:11

Python代碼瀏覽器

2023-05-17 00:10:55

GPU瀏覽器解鎖

2021-04-21 08:28:06

微軟EdgeGoogle

2019-09-03 08:00:00

電腦硬盤程序

2012-02-21 13:50:29

瀏覽器遙控器
點贊
收藏

51CTO技術棧公眾號