欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

打包非 JavaScript 靜態(tài)資源詳情

 更新時間:2021年10月21日 11:48:49   作者:Eli Gao  
這篇文章主要介紹了打包非 JavaScript 靜態(tài)資源,打包工具中的自定義導(dǎo)入,種常見的方法是利用已有的靜態(tài)導(dǎo)入語法。有些打包工具可能會通過文件擴(kuò)展名來自動檢測格式,而有些其他打包工具則允許插件使用自定義的 URL Scheme,下面具體內(nèi)舉例說明,需要的朋友可以參考一下

本文翻譯自 https://web.dev/bundling-non-js-resources/,原文未做修改

假設(shè)你正在開發(fā)一個網(wǎng)絡(luò)應(yīng)用程序。在這種情況下,你很可能不僅要處理 JavaScript 模塊,還要處理各種其他資源--Web Workers(它也是 JavaScript ,但它擁有一套獨(dú)立的構(gòu)建依賴圖)、圖片、CSS、字體、WebAssembly 模塊等等。

一種可行的加載靜態(tài)資源的辦法是在 HTML 中直接引用它們,但通常它們在邏輯上是與其他可重用的組件耦合的。例如,自定義下拉菜單的 CSS 與它的 JavaScript 部分相聯(lián)系,圖標(biāo)圖像與工具欄組件相關(guān),而 WebAssembly 模塊與它的 JavaScript 膠水相依賴。在這些情況下,有種更加方便快捷的辦法是直接從它們的 JavaScript 模塊中引用資源,并在加載相應(yīng)的組件時動態(tài)地加載它們。

然而,大多數(shù)大型項(xiàng)目的構(gòu)建系統(tǒng)都會對內(nèi)容進(jìn)行額外的優(yōu)化和重組--例如打包和最小化(minimize)。構(gòu)建系統(tǒng)不能執(zhí)行代碼并預(yù)測執(zhí)行的結(jié)果是什么,也沒理由去遍歷判斷 JavaScript 中每一個可能的字符串是否是一個資源 URL。那么,如何才能讓它們 "看到 "那些由 JavaScript 組件加載的動態(tài)資源,并將它們包含在構(gòu)建產(chǎn)物中呢?

1、打包工具中的自定義導(dǎo)入

一種常見的方法是利用已有的靜態(tài)導(dǎo)入語法。有些打包工具可能會通過文件擴(kuò)展名來自動檢測格式,而有些其他打包工具則允許插件使用自定義的 URL Scheme,比如下面的例子:

// 普通 JavaScript 導(dǎo)入
import { loadImg } from './utils.js';

// 特殊 "URL 導(dǎo)入" 的靜態(tài)資源
import imageUrl from 'asset-url:./image.png';
import wasmUrl from 'asset-url:./module.wasm';
import workerUrl from 'js-url:./worker.js';

loadImg(imageUrl);
WebAssembly.instantiateStreaming(fetch(wasmUrl));
new Worker(workerUrl);

當(dāng)一個打包工具插件發(fā)現(xiàn)一個導(dǎo)入項(xiàng)帶有它所識別的擴(kuò)展名或 URL Scheme(上面的例子中的 asset-url: 和 js-url: )時,它會將引用的資源添加到構(gòu)建圖中,將其復(fù)制到最終目的地,執(zhí)行適用于資源類型的優(yōu)化,并返回最終的 URL,以便在運(yùn)行時使用。

這種方法的好處是:重用 JavaScript 導(dǎo)入語法,保證所有的 URL 都是靜態(tài)的相對路徑,這使得構(gòu)建系統(tǒng)很容易定位這種依賴關(guān)系。

然而,它有一個明顯的缺點(diǎn):這種代碼不能直接在瀏覽器中工作,因?yàn)闉g覽器不知道如何處理那些自定義的導(dǎo)入方案或擴(kuò)展名。當(dāng)然,如果你可以控制所有的代碼,并且本來就要依靠打包工具進(jìn)行開發(fā),這聽起來還不錯。然而為了減少麻煩,直接在瀏覽器中使用 JavaScript 模塊的情況越來越普遍(至少在開發(fā)過程中是這樣)。一個小 demo 可能根本就不需要打包工具,即使在生產(chǎn)中也不需要。

2、瀏覽器和打包工具中通用的導(dǎo)入語法

如果你正在開發(fā)一個可重用的組件,你會希望它在任何環(huán)境下都能發(fā)揮作用,無論它是直接在瀏覽器中使用還是作為一個更大的應(yīng)用程序的一部分預(yù)先構(gòu)建。大多數(shù)現(xiàn)代的打包工具都接受下面這個JavaScript 模塊導(dǎo)入語法:

new URL('./relative-path', import.meta.url)

它看著像是一種特殊的語法,然而它確實(shí)是一種有效的 JavaScript 表達(dá)式,可以直接在瀏覽器中使用,也可以被打包工具靜態(tài)地檢測出來并加以處理。

使用這個語法,前面的例子可以改寫為:

// regular JavaScript import
import { loadImg } from './utils.js';
loadImg(new URL('./image.png', import.meta.url));
WebAssembly.instantiateStreaming(
  fetch(new URL('./module.wasm', import.meta.url)),
  { /* … */ }
);
new Worker(new URL('./worker.js', import.meta.url));


讓我們分析一下它是什么原理: new URL(...) 構(gòu)造函數(shù)會基于第二個參數(shù)里的絕對URL,解析出第一個參數(shù)中相對 URL 所對應(yīng)的 URL。在我們的例子中,第二個參數(shù)是 import.meta.url [1] ,它是當(dāng)前 JavaScript 模塊的 URL ,所以第一個參數(shù)可以是相對于它的任何路徑。

它的優(yōu)點(diǎn)和劣勢都類似于 動態(tài)導(dǎo)入。雖然可以使用 import(...) 導(dǎo)入內(nèi)容,如 import(someUrl) ,但打包工具會特殊處理帶有靜態(tài) URL import('./some-static-url.js') 的導(dǎo)入方式:把它作為一種在編譯時預(yù)處理已知依賴關(guān)系的導(dǎo)入方式,把 代碼分塊 并動態(tài)加載。

同樣,你可以使用 new URL(...) ,如 new URL(relativeUrl, customAbsoluteBase) ,然而 new URL('...', import.meta.url) 語法可以明確地告訴打包工具預(yù)處理依賴,并將其與主 JavaScript 資源打包在一起。

3、模棱兩可的相對URL

你可能會想,為什么打包工具不能檢測到其他常見的語法--例如,沒有 new URL 包裝的 fetch('./module.wasm') ?

原因是,與 import 關(guān)鍵字不同,任何動態(tài)請求都是相對于文檔本身的,而不是相對于當(dāng)前的JavaScript文件進(jìn)行解析。比方說,我們有以下結(jié)構(gòu):

index.html:

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


src/

main.js

module.wasm

如果你想從 main.js 中加載 module.wasm ,你的第一反應(yīng)可能是使用 fetch('./module.wasm') 這樣的相對路徑引用。

然而,fetch不知道它所執(zhí)行的 JavaScript 文件的 URL,相反,它是相對于文檔來解析 URL 的。因此, fetch('./module.wasm') 最終會試圖加載 http://example.com/module.wasm ,而不是預(yù)期的 http://example.com/src/module.wasm ,從而造成失?。ㄟ\(yùn)氣更不好的情況下,還可能默默地加載一個與你預(yù)期不同的資源)。

通過將相對的URL包裝成 new URL('...', import.meta.url) ,你可以避免這個問題,并保證任何提供的URL在傳遞給任何loader之前都是相對于 當(dāng)前 JavaScript 模塊的 URL(import.meta.url) 解析的。

只要用 fetch(new URL('./module.wasm', import.meta.url)) 代替 fetch('./module.wasm') ,就可以成功地加載預(yù)期的 WebAssembly 模塊,同時給打包工具一個在構(gòu)建時找到這些相對路徑的可靠方法。

4、工具鏈中的支持

4.1 打包工具

下面這些打包工具已經(jīng)支持 new URL 語法:

  • Webpack v5
  • Rollup (通過插件支持: @web/rollup-plugin-import-meta-assets  支持通用資源,而 @surma/rollup-plugin-off-main-thread 支持 Workers.)
  • Parcel v2 (beta) (譯者注:在本譯文發(fā)布時,Parcel V2已經(jīng)正式發(fā)布:https://parceljs.org/blog/v2
  • Vite

5、 WebAssembly

當(dāng)使用 WebAssembly 時,你通常不會手動加載 Wasm 模塊,而是導(dǎo)入由工具鏈發(fā)出的 JavaScript 膠水代碼。下面的工具鏈可以替你生成 new URL(...) 語法:

5.1  通過Emscripten編譯的C/C++

當(dāng)使用 Emscripten 工具鏈時,我們可以通過以下選項(xiàng)要求它輸出 ES6 模塊膠水代碼,而非普通 JS 代碼:

$ emcc input.cpp -o output.mjs
## 如果你不想用mjs擴(kuò)展名:
$ emcc input.cpp -o output.js -s EXPORT_ES6


當(dāng)使用這個選項(xiàng)時,輸出的膠水代碼將使用new URL(..., import.meta.url) 語法,這樣打包工具可以自動找到相關(guān)的 Wasm 文件。

通過添加 -pthread 參數(shù),這個語法也可以支持 WebAssembly 線程的編譯

$ emcc input.cpp -o output.mjs -pthread
## 如果你不想用mjs擴(kuò)展名:
$ emcc input.cpp -o output.js -s EXPORT_ES6 -pthread


在這種情況下,生成的Web Worker將以同樣的方式被引用,并且也能被打包工具和瀏覽器正確加載。

5.2 通過 wasm-pack / wasm-bindgen 編譯的 Rust

wasm-pack  --WebAssembly 的主要 Rust 工具鏈,也有幾種輸出模式。

默認(rèn)情況下,它將輸出一個依賴于 WebAssembly ESM 集成提議 的 JavaScript 模塊。在寫這篇文章的時候,這個提議仍然是實(shí)驗(yàn)性的,只有在使用 Webpack 打包時,輸出才會有效。

或者,我們可以通過 -target web 參數(shù)要求 wasm-pack 通過輸出一個與瀏覽器兼容的 ES6 模塊:

$ wasm-pack build --target web


輸出將使用前面所說的 new URL(..., import.meta.url) 語法,而且 Wasm 文件也會被打包工具自動發(fā)現(xiàn)。

如果你想通過 Rust 使用 WebAssembly 線程,這就有點(diǎn)復(fù)雜了。請查看指南的 相應(yīng)部分 [13] 以了解更多。

簡而言之,你不能使用任意的線程 API,但如果你使用 Rayon [14] ,你可以試試 wasm-bingen-rayon [15] 適配器,這樣它就可以生成 Web 上可以運(yùn)行的 Worker 。 wasm-bindgen-rayon 使用的 JavaScript 膠水 也包括 [16] new URL (...)語法,因此 Workers 也能被打包工具發(fā)現(xiàn)和引入。

6、未來的導(dǎo)入方式

6.1  import.meta.resolve

有一個潛在的未來改進(jìn)是專門的 import.meta.resolve(...) 語法。它將允許以一種更直接的方式解析相對于當(dāng)前模塊的內(nèi)容,而不需要額外的參數(shù)。

// 現(xiàn)在的語法
new URL('...', import.meta.url)

// 未來的語法
await import.meta.resolve('...')

它還能與導(dǎo)入依賴圖(import maps)還有自定義解析器更好地整合,因?yàn)樗?import 語法通過同一個模塊解析系統(tǒng)處理。這對打包工具來說也是一個更可靠的信號,因?yàn)樗且粋€靜態(tài)語法,不依賴于像 URL 這樣的運(yùn)行時 API 。

import.meta.resolve 已經(jīng)作為一個 實(shí)驗(yàn)性功能 在 Node.js 中實(shí)現(xiàn)了,但是關(guān)于它在 Web 上應(yīng)該如何工作 還有一些問題沒有定論。

6.2 導(dǎo)入斷言

導(dǎo)入斷言(import assertions)是一項(xiàng)新功能,允許導(dǎo)入 ECMAScript 模塊以外的類型,不過現(xiàn)在只支持JSON 類型。

foo.json

{ "answer": 42 }


main.mjs

import json from './foo.json' assert { type: 'json' };
console.log(json.answer); // 42


(譯者注:關(guān)于這個不太符合直覺的語法選擇也有點(diǎn)意思 https://github.com/tc39/proposal-import-assertions/issues/12)

它們也可能被打包工具使用,并取代目前由new URL語法所支持的場景,但導(dǎo)入斷言中的類型需要一個一個被支持,目前被支持的只有 JSON,CSS 模塊即將被支持,但其他類型的資源導(dǎo)入仍然需要一個更通用的解決方案。

要想了解更多關(guān)于這個功能的信息,請查看 v8.dev上的功能解釋 [19] 。

7、小結(jié)

正如你所看到的,有各種方法可以在網(wǎng)絡(luò)上包含非 JavaScript 資源,但它們有各自的優(yōu)缺點(diǎn),而且都不能同時在所有工具鏈中工作。一些未來的提議可能會讓我們用專門的語法來導(dǎo)入這些資源,但我們還沒有走到這一步。

在那一天到來之前, new URL(..., import.meta.url) 語法是最有希望的解決方案,并且今天已經(jīng)可以在瀏覽器、各種捆綁器和 WebAssembly 工具鏈中工作。

到此這篇關(guān)于打包非 JavaScript 靜態(tài)資源詳情的文章就介紹到這了,更多相關(guān)打包非 JavaScript 靜態(tài)資源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

8、參考資料

[1];import.meta.url: https://v8.dev/features/modules#import-meta

[2];動態(tài)導(dǎo)入: https://v8.dev/features/dynamic-import

[3]:代碼分塊: https://web.dev/reduce-javascript-payloads-with-code-splitting/

[4]:Webpack v5: https://webpack.js.org/guides/asset-modules/#url-assets

[5]:Rollup: https://rollupjs.org/

[6]:@web/rollup-plugin-import-meta-assets: https://modern-web.dev/docs/building/rollup-plugin-import-meta-assets/

[7]:@surma/rollup-plugin-off-main-thread: https://github.com/surma/rollup-plugin-off-main-thread

[8]:Parcel v2 (beta): https://v2.parceljs.org/languages/javascript/#url-dependencies

[9]:Vite: https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url

[10]:WebAssembly: https://web.dev/webassembly-threads/#c

[11]:wasm-pack: https://github.com/rustwasm/wasm-pack

[12]:WebAssembly ESM 集成提議: https://github.com/WebAssembly/esm-integration

[13]:相應(yīng)部分: https://web.dev/webassembly-threads/#rust

[14]:Rayon: https://github.com/rayon-rs/rayon

[15]:wasm-bingen-rayon: https://github.com/GoogleChromeLabs/wasm-bindgen-rayon

[16]:也包括: https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/4cd0666d2089886d6e8731de2371e7210f848c5d/demo/index.js#L26

[17]:實(shí)驗(yàn)性功能: https://nodejs.org/api/esm.html#esm_import_meta_resolve_specifier_parent

[18]:還有一些問題沒有定論: https://github.com/WICG/import-maps/issues/79

[19]:v8.dev上的功能解釋: https://v8.dev/features/import-assertions

您可能感興趣的文章:

相關(guān)文章

最新評論