在瀏覽器中使用JS module
簡(jiǎn)介
現(xiàn)在苞氮,所有主流瀏覽器都已經(jīng)支持JS module(Chrome舷夺、Edge猖辫、Safari荔仁、Firefox)~這篇文章將為你講解如何在瀏覽器中使用JS module伍宦,如何負(fù)責(zé)的部署它們,以及chrome團(tuán)隊(duì)如何努力的使JS module變的更好乏梁。
什么是JS module
JS module(或者稱(chēng)作ES module雹拄,ECMAScript module)是一個(gè)主要的新特性,或者說(shuō)是一系列新特性掌呜。你可能已經(jīng)使用過(guò)第三方的模塊加載系統(tǒng)滓玖。CommonJs 如 nodeJs 、 AMD 如 requireJs 等等质蕉。這些模塊加載系統(tǒng)都有一個(gè)共同點(diǎn):它們?cè)试S你執(zhí)行導(dǎo)入導(dǎo)出操作势篡。
javascript現(xiàn)在已經(jīng)為模塊化制定了標(biāo)準(zhǔn)語(yǔ)法。有了JS module模暗,你可以用export
關(guān)鍵字去導(dǎo)出任何東西禁悠。你可以導(dǎo)出const
、function
兑宇,或者任何其他變量綁定或聲明碍侦。你需要做的只是在變量聲明前加個(gè)export
或者用export
去聲明它。
// lib.mjs
export const repeat = (string) => `${string} ${string}`;
export function shout(string) {
return `${string.toUpperCase()}!`;
}
你可以使用import
從任何其他模塊導(dǎo)入模塊隶糕。這里瓷产,我們從lib
模塊中引入repeat
和shout
方法,并在main模塊(當(dāng)前模塊)中使用它們枚驻。
// ?? main.mjs
import {repeat, shout} from './lib.mjs';
repeat('hello');
// → 'hello hello'
shout('Modules in action');
// → 'MODULES IN ACTION!'
你也可以使用export default
從模塊中導(dǎo)出一個(gè)默認(rèn)值濒旦。
// ?? lib.mjs
export default function(string) {
return `${string.toUpperCase()}!`;
}
用export default
導(dǎo)出的模塊可以在其它模塊中使用任意名稱(chēng)去import
。
// ?? main.mjs
import repeat from './lib.mjs';
// ^^^^^
// ?? main2.mjs
import shout from './lib.mjs';
// ^^^^^
JS module
和普通的js腳本
有些不同:
-
module
默認(rèn)使用的是嚴(yán)格模式(strick module
) - 不支持html風(fēng)格的注釋
// Error: 不要在javascript中使用html風(fēng)格的注釋 const x = 42; <!-- TODO: Rename x to y. // Error: 使用普通的單行注釋 const x = 42; // TODO: Rename x to y.
- 模塊具有自己的作用域再登。這意味著在模塊中使用
var foo = 42
并不會(huì)創(chuàng)建一個(gè)全局變量foo
尔邓,不能通過(guò)window.foo
去訪問(wèn)。這點(diǎn)和普通的js腳本
不同锉矢。 -
export
和import
關(guān)鍵字僅可在模塊系統(tǒng)中使用----所以不能在普通的js腳本中使用梯嗽。
由于有這些不同點(diǎn),當(dāng)相同的js腳本分別被當(dāng)做JS module
和普通js腳本
執(zhí)行時(shí)沽损,可能有不同的行為表現(xiàn)灯节。所以,javascript運(yùn)行環(huán)境必須知道引入的腳本是不是一個(gè)JS module
。
在瀏覽器中使用JS modules
在web應(yīng)用中显晶,你可以將<script>
標(biāo)簽的type
屬性設(shè)置為module
贷岸,這樣瀏覽器就會(huì)把引入的腳本識(shí)別為JS module
。
<script type="module" src="main.mjs"></script>
<script nomodule src="fallback.js"></script>
瀏覽器會(huì)識(shí)別typ="module"
屬性磷雇,并忽略設(shè)置有nomodule
屬性的腳本偿警。這意味著你可以向支持模塊加載的瀏覽器提供基于JS module
的代碼,同時(shí)讓不支持模塊加載的瀏覽器回退到普通js腳本
模式唯笙。
如果在表現(xiàn)上螟蒸,這種區(qū)分腳本的能力驚人的有用。
想一想:只有現(xiàn)代瀏覽器支持modules崩掘,如果瀏覽器能夠識(shí)別你的模塊代碼七嫌,那么它肯定也支持在模塊化標(biāo)準(zhǔn)之前的新的js特性,比如:箭頭函數(shù)苞慢,async-await
诵原。
你不需要再去編譯那些使用新特性寫(xiě)的代碼!能為現(xiàn)代瀏覽器提供更小挽放、很大程度上不需要再編譯的代碼绍赛。只有不支持模塊加載的瀏覽器會(huì)請(qǐng)求設(shè)置nomodule
的腳本。
特定于瀏覽器環(huán)境下辑畦, JS module
和普通js腳本
的區(qū)別
前面已經(jīng)說(shuō)過(guò)吗蚌,JS module
和普通js加載
是不同的。
在上邊我們列舉了一些平臺(tái)無(wú)關(guān)的差異纯出,在瀏覽器環(huán)境中它們還有一些不同點(diǎn)蚯妇。
比如,JS module
只會(huì)被瀏覽器解析并執(zhí)行一次暂筝,普通js腳本
每一次通過(guò)<script>
引入箩言,瀏覽器都會(huì)去解析和執(zhí)行它。
<script src="classic.js"></script>
<script src="classic.js"></script>
<!-- classic.js 會(huì)被多次解析 -->
<script type="module" src="module.mjs"></script>
<script type="module" src="module.mjs"></script>
<script type="module">import './module.mjs';</script>
<!-- module.mjs 只會(huì)被解析一次 -->
而且乖杠,JS module
腳本和依賴(lài)有了跨域限制分扎,這意味著任何跨域的JS module
腳本都必須有正確的http頭部信息澄成。如:Access-Control-Allow-Origin: *
胧洒。而普通的js腳本
并沒(méi)有這些限制。
另一個(gè)不同與async
屬性有關(guān)墨状,async
屬性可以使js腳本的下載不會(huì)阻塞HTML解析(就像defer)卫漫,但同時(shí)async
屬性也會(huì)使得腳本在加載完成后立即執(zhí)行(defer是等到html解析完成后執(zhí)行),不能保證腳本的執(zhí)行順序肾砂,也不會(huì)等待html解析完成列赎。
async
屬性在內(nèi)聯(lián)普通js腳本
不生效,不過(guò)在內(nèi)聯(lián)JS module
模式下可以生效镐确。
關(guān)于文件擴(kuò)展名
你可能已經(jīng)注意到我們?cè)趯?xiě)模塊代碼時(shí)是用.mjs
作為文件擴(kuò)展名的包吝。當(dāng)然饼煞,在web中,只要http的響應(yīng)頭中提供了JavaScript MIME typetext/javascript
字段诗越,文件擴(kuò)展名并不是特別重要砖瞧。
而且,瀏覽器通過(guò)<script>
標(biāo)簽上的type
屬性就可以知道這是不是一個(gè)JS module
模塊嚷狞。
但是块促,我們?nèi)匀煌扑]使用.mjs
作為文件擴(kuò)展名,原因有以下兩個(gè)方面:
- 在開(kāi)發(fā)中床未,我們可以很容易的通過(guò)擴(kuò)展名去辨識(shí)文件是一個(gè)模塊而不是一個(gè)普通的腳本文件(僅僅靠查看代碼去辨別不會(huì)總行得通)竭翠。正如前邊提到的,瀏覽器對(duì)待模塊代碼和普通腳本文件是完全不同的薇搁。
- 符合node.js規(guī)范斋扰。nodeJs實(shí)驗(yàn)?zāi)K僅僅支持
.mjs
擴(kuò)展名的文件。
模塊說(shuō)明符(Module specifiers)
當(dāng)我們使用import
時(shí)啃洋,最后邊用來(lái)說(shuō)明模塊位置的字符串叫做 module specifiers 或 import specifier褥实,在我們前面的例子中, module specifier 是 './lib.mjs'
import {shout} from './lib.mjs';
// ^^^^^^^^^^^
在瀏覽器中裂允,模塊說(shuō)明符還有一些限制损离。
目前是不支持 裸模塊 (指像在node中只通過(guò)包名引入)的。這個(gè)規(guī)定讓瀏覽器可以允許自定義模塊加載器對(duì)像下面這樣的空模塊說(shuō)明符賦予特殊的意義绝编。
// Not supported (yet):
import {shout} from 'jquery';
import {shout} from 'lib.mjs';
import {shout} from 'modules/lib.mjs';
下面這些引用方式是合法的
// Supported:
import {shout} from './lib.mjs';
import {shout} from '../lib.mjs';
import {shout} from '/modules/lib.mjs';
import {shout} from 'https://simple.example/modules/lib.mjs';
到現(xiàn)在為止僻澎,模塊說(shuō)明符必須是完整的URL,或以/
./
../
開(kāi)頭的相對(duì)URL十饥。
模塊默認(rèn)是延遲執(zhí)行的(defer)
普通js腳本默認(rèn)會(huì)阻塞html解析窟勃。你可以加一個(gè)defer屬性,讓腳本的下載和html解析并發(fā)執(zhí)行逗堵。
JS module
腳本默認(rèn)就有defer屬性秉氧,所以,沒(méi)有必要再加一個(gè)defer
屬性到<script type="module">
標(biāo)簽上!
不僅僅是主模塊蜒秤,所有模塊的加載都和html解析是并行的汁咏。
其他模塊特性
Dynamic import()
到現(xiàn)在,我們只用了靜態(tài)的import
作媚。使用靜態(tài)模塊攘滩,在主程序運(yùn)行之前,所有的模塊代碼都必須加載并執(zhí)行完畢纸泡。
有時(shí)漂问,你并不想在一開(kāi)始就加載某個(gè)模塊,而是想在需要的時(shí)候隨時(shí)動(dòng)態(tài)去請(qǐng)求(如:當(dāng)用戶點(diǎn)擊一個(gè)鏈接或標(biāo)簽),這樣做能減少應(yīng)用的初始加載時(shí)間蚤假,提升頁(yè)面性能栏饮。
Dynamic import()
就可以用來(lái)解決這種問(wèn)題~
<script type="module">
(async () => {
const moduleSpecifier = './lib.mjs';
const {repeat, shout} = await import(moduleSpecifier);
repeat('hello');
// → 'hello hello'
shout('Dynamic import in action');
// → 'DYNAMIC IMPORT IN ACTION!'
})();
</script>
和靜態(tài)import
不一樣,動(dòng)態(tài)import()
也可以在普通的腳本文件中使用磷仰。這提供了一種在現(xiàn)有代碼中逐步使用模塊加載的方式抡爹。更多信息,點(diǎn)擊Dynamic import()查看
import.meta
另一個(gè)模塊相關(guān)的新特性是import.meta
芒划,從這個(gè)屬性我們可以獲得當(dāng)前模塊的元數(shù)據(jù)冬竟。你所能得到的確切元數(shù)據(jù)并沒(méi)有作為ECMAScript規(guī)范的一部分。它取決于你的宿主環(huán)境民逼,在瀏覽器和NodeJs中你可能得到不同的元數(shù)據(jù)泵殴,比如:
下面是一個(gè)瀏覽器中使用import.meta
的例子。默認(rèn)情況下拼苍,圖片相對(duì)于HTML文檔的當(dāng)前url加載的笑诅。import.meta.url
使得我們可以相對(duì)于當(dāng)前模塊的路徑去加載圖片。
function loadThumbnail(relativePath) {
const url = new URL(relativePath, import.meta.url);
const image = new Image();
image.src = url;
return image;
}
const thumbnail = loadThumbnail('../img/thumbnail.png');
container.append(thumbnail);
性能建議
保持使用打包工具
JS modules
使得不使用打包工具(webpack, Rollup, 或Parcel)開(kāi)發(fā)網(wǎng)站成為可能疮鲫。在下列場(chǎng)景中吆你,你就可以直接使用JS module
去開(kāi)發(fā)應(yīng)用。
- 本地開(kāi)發(fā)環(huán)境中
- 在總模塊少于100和依賴(lài)樹(shù)相對(duì)較淺(即俊犯,最大深度小于5)的小型Web App中
然而妇多,我們?cè)趯?duì)chrome加載管道進(jìn)行瓶頸分析時(shí),加載了由大約300模塊組成的模塊化庫(kù)燕侠,此時(shí)打包應(yīng)用程序的加載性能優(yōu)于未打包應(yīng)用程序者祖。
其中一個(gè)原因是因?yàn)殪o態(tài)的import / export
是可以靜態(tài)分析的,因此绢彤,打包工具可以通過(guò)消除未使用的export
來(lái)優(yōu)化代碼七问。靜態(tài)的import
和export
不僅僅是語(yǔ)法,更是一種新的工具特性!
同樣的chrome開(kāi)發(fā)者工具的代碼覆蓋率特性可以幫助你識(shí)別你是否將不必要的代碼推送給了用戶茫舶。我們還建議開(kāi)發(fā)者使用代碼分割工具分割代碼械巡,將首屏渲染不需要的腳本延遲加載。
打包和不打包的權(quán)衡
在web開(kāi)發(fā)中饶氏,每一件事都需要去做權(quán)衡讥耗。未打包的代碼可能會(huì)用戶降低首次訪問(wèn)頁(yè)面的性能(冷緩存),但與一個(gè)沒(méi)有做代碼分割的包相比嚷往,它可以提高后續(xù)訪問(wèn)的加載性能葛账。
對(duì)一個(gè)200kb的代碼庫(kù),將其中一個(gè)細(xì)粒度的模塊分割出來(lái)皮仁,將其作為用戶后續(xù)訪問(wèn)從服務(wù)器獲取的唯一內(nèi)容比每次都要下載整個(gè)代碼庫(kù)好得多。
使用更細(xì)粒度的模塊
養(yǎng)成寫(xiě)更小、細(xì)粒度模塊代碼的習(xí)慣贷祈。在開(kāi)發(fā)中趋急, 每個(gè)(文件)模塊只含有少數(shù)幾個(gè)導(dǎo)出 要比 將多個(gè)導(dǎo)出寫(xiě)到一個(gè)文件 好的多。
考慮這樣一種情況势誊,util.mjs
文件導(dǎo)出三個(gè)方法分別是:drop
呜达,pluck
和zip
:
export function drop() { /* … */ }
export function pluck() { /* … */ }
export function zip() { /* … */ }
如果你的代碼只需要pluck
方法,你可能要這樣寫(xiě):
import { pluck } from './util.mjs';
在這種情況下(沒(méi)有進(jìn)行構(gòu)建時(shí)打包)粟耻,即使你只需要pluck
一個(gè)導(dǎo)出查近,瀏覽器仍然需要去下載、解析和編譯整個(gè)utils.mjs
文件挤忙。真是糟糕呢~
如果pluck
沒(méi)有和drop
霜威、zip
有任何共享模塊的話,最好的做法是將它拆分為更細(xì)粒度的模塊文件./pluck.mjs
册烈。
export function pluck() { /* … */ }
這樣戈泼,我們可以只導(dǎo)入pluck
,而不用瀏覽器去處理drop
和zip
模塊:
import { pluck } from './pluck.mjs';
提示:您可以在此處使用命名導(dǎo)出
export default
這樣不僅能使你的代碼保持良好和簡(jiǎn)單赏僧,還能減少打包工具處理無(wú)用代碼的時(shí)間大猛。如果其中一個(gè)模塊沒(méi)有被使用,那它永遠(yuǎn)不會(huì)被import淀零,所以瀏覽器永遠(yuǎn)不會(huì)使用它挽绩。而那些被使用的模塊會(huì)被瀏覽器每個(gè)單獨(dú)緩存下來(lái)。
使用更細(xì)粒度的模塊拆分可以讓你的代碼為將來(lái)或許可以直接使用原生打包解決方案做好準(zhǔn)備驾中。
預(yù)加載模塊
你可以使用<link rel="modulepreload">
進(jìn)一步優(yōu)化你的模塊的加載(delivery)琼牧。
這樣,瀏覽器可以預(yù)加載和預(yù)編譯模塊以及它的依賴(lài)哀卫。
<link rel="modulepreload" href="lib.mjs">
<link rel="modulepreload" href="main.mjs">
<script type="module" src="main.mjs"></script>
<script nomodule src="fallback.js"></script>
這種方式對(duì)有大型依賴(lài)樹(shù)的應(yīng)用至關(guān)重要巨坊。沒(méi)有rel="modulepreload"
,瀏覽器需要發(fā)起多次http請(qǐng)求去得到整個(gè)依賴(lài)樹(shù)此改。然后趾撵,如果你用rel="modulepreload"
聲明了整個(gè)應(yīng)用的腳本列表,瀏覽器就不需要去逐步的去解析并請(qǐng)求這些依賴(lài)共啃。
使用HTTP/2
盡可能的使用HHTP/2總是很好的性能建議占调,即使僅僅是去使用它的多路復(fù)用特性。
使用HTTP/2多路復(fù)用移剪,可以同時(shí)處理多個(gè)請(qǐng)求和響應(yīng)信息究珊,這對(duì)模塊依賴(lài)樹(shù)的加載很有利。
Chrome團(tuán)隊(duì)研究過(guò)HTTP/2的另一個(gè)新特性纵苛,HTTP/2服務(wù)端推送剿涮,是否能成為部署高度模塊化應(yīng)用的解決方案言津。不幸的是,HTTP/2 服務(wù)端推送難做到取试,web服務(wù)器和瀏覽器的實(shí)現(xiàn)目前還沒(méi)有針對(duì)高度模塊化的web應(yīng)用實(shí)例進(jìn)行優(yōu)化悬槽。
比如,我們很難去做到只推送用戶沒(méi)有緩存的數(shù)據(jù)瞬浓,而且通過(guò)向服務(wù)端去發(fā)送整個(gè)客戶端的緩存狀態(tài)會(huì)造成一種隱私風(fēng)險(xiǎn)初婆。
無(wú)論如何,繼續(xù)使用HTTP/2猿棉!只需要記住HTTP/2服務(wù)端推送(很不幸)不是一個(gè)好辦法磅叛。
JS modules的使用現(xiàn)狀
JS modules正逐漸的被web開(kāi)發(fā)者接受,我們的用戶統(tǒng)計(jì)數(shù)據(jù)顯示當(dāng)前有0.08%的頁(yè)面在使用<script type="module">
萨赁,這個(gè)數(shù)據(jù)排除了其他使用方式弊琴,如import()
或 worklets
對(duì)于JS modules,接下來(lái)我們會(huì)做什么
Chrome團(tuán)隊(duì)正在努力從多方面去提升JS modules的開(kāi)發(fā)體驗(yàn)位迂,下面我們來(lái)講講其中的一部分访雪。
更快更確定的模塊解析算法
我們對(duì)模塊解析算法進(jìn)行了修改,解決了速度和確定性方面的不足掂林。新算法現(xiàn)在已經(jīng)同時(shí)存在于HTML規(guī)范和ECMAScript規(guī)范中臣缀,而且已經(jīng)在Chrome 63中實(shí)現(xiàn)。希望這個(gè)改進(jìn)能在其他瀏覽器中盡快實(shí)現(xiàn)泻帮。
新算法更加的高效和快速精置。舊算法在依賴(lài)關(guān)系計(jì)算上的復(fù)雜度是二次方的(n2),舊的Chrome也是如此锣杂,新的算法是線性的(n)脂倦。
而且,新算法以一種確定的方式去報(bào)告解析錯(cuò)誤元莫。給定一個(gè)包含多個(gè)錯(cuò)誤的依賴(lài)關(guān)系圖赖阻,對(duì)造成解析失敗的根本原因,舊算法多次運(yùn)行可能報(bào)告不同的錯(cuò)誤踱蠢。這對(duì)調(diào)試造成了不必要的麻煩火欧。而新算法保證每次都報(bào)告相同的錯(cuò)誤信息。
Worklets and web workers
Chrome現(xiàn)在在實(shí)現(xiàn)worklets茎截,這將允許web開(kāi)發(fā)者去自定義瀏覽器底層的硬編碼邏輯苇侵。使用worklets,web開(kāi)發(fā)者可以將一個(gè)JS模塊提供給渲染管道或者音頻管道(未來(lái)可能會(huì)有更多的管道支持)企锌。
Chrome 65 支持使用PaintWorklet
去控制DOM元素的繪制榆浓。
const result = await css.paintWorklet.addModule('paint-worklet.mjs');
Chrome 66 支持 AudioWorklet
,允許你控制用自己的代碼控制音頻進(jìn)程撕攒。同時(shí)這個(gè)版本還開(kāi)始了一個(gè) 實(shí)驗(yàn)性質(zhì)的AnimationWorklet
陡鹃,讓開(kāi)發(fā)者能夠創(chuàng)建scroll-linked和其它高性能的程序動(dòng)畫(huà)(這塊不太理解)烘浦。
最后, LayoutWorklet
(又叫做 the CSS Layout API)已經(jīng)應(yīng)用在Chrome 67上杉适。
我們正在努力為Chrome添加支持谎倔,使得開(kāi)發(fā)者可以在專(zhuān)用的web Workers中使用JS modules柳击。你現(xiàn)在就可以嘗試這個(gè)新特性:chrome://flags/#enable-experimental-web-platform-features enabled.
(在chrome輸入欄輸入開(kāi)啟)猿推。
const worker = new Worker('worker.mjs', { type: 'module' });
JS module對(duì)shared wrokers和service workers的支持也會(huì)很快到來(lái):
const worker = new SharedWorker('worker.mjs', { type: 'module' });
const registration = await navigator.serviceWorker.register('worker.mjs', { type: 'module' });
包名映射(Package name maps)
在Node.js/npm中,我們常用模塊的包名去引入模塊捌肴。如:
import moment from 'moment';
import { pluck } from 'lodash-es';
目前蹬叭,按照HTML規(guī)范,這樣的 裸模塊 會(huì)拋出異常状知。我們的 包名映射建議允許這樣的代碼在瀏覽器中正常工作秽五,包括生產(chǎn)環(huán)境中。包名映射是一種json數(shù)據(jù)饥悴,能幫助瀏覽器將 裸模塊 形式的說(shuō)明符轉(zhuǎn)換成完整的url坦喘。
包名映射現(xiàn)在還在提案階段。盡管我們已經(jīng)思考了很多關(guān)于如何處理各種用例的問(wèn)題西设,但我們?nèi)匀辉谂c社區(qū)進(jìn)行溝通瓣铣,而且還沒(méi)有寫(xiě)出一個(gè)完整的規(guī)范。歡迎大家提任何反饋(最下方我會(huì)給出原文鏈接)贷揽。
Web打包:原生捆綁包
Chrome開(kāi)發(fā)團(tuán)隊(duì)正在探索一種原生的web打包格式作為一種新方式去發(fā)布web應(yīng)用棠笑。原生web打包的核心特性是:
Signed HTTP Exchanges允許瀏覽器信任一個(gè)簽名的HTTP請(qǐng)求/響應(yīng)是被當(dāng)前源要求生成的。
Bundled HTTP Exchanges,也就是禽绪,一個(gè)交換集蓖救,每個(gè)交換集可以是已簽名的或者未簽名的,其中有一些元數(shù)據(jù)描述如何將bundled解釋為一個(gè)整體印屁。
組合起來(lái)循捺,這樣的web打包格式將使多個(gè)同源資源安全地嵌入到單個(gè)HTTP GET響應(yīng)中。
現(xiàn)在的打包工具雄人,如webpack, Rollup, or Parcel 目前只會(huì)發(fā)出一個(gè)javascript包从橘,丟失了原始獨(dú)立模塊和資源的語(yǔ)義。使用原生捆綁包柠衍,瀏覽器可以將資源解包到他們的原始形式洋满。
簡(jiǎn)單來(lái)說(shuō),你可以將Bundled HTTP Exchange想象成一組資源珍坊,可以通過(guò)一個(gè)目錄(manifest)以任何順序訪問(wèn)它牺勾,而且,所包含的資源可以根據(jù)他們的相對(duì)重要性進(jìn)行有效的存儲(chǔ)和標(biāo)記阵漏,同時(shí)保持了單個(gè)文件的概念驻民。
由于這個(gè)特點(diǎn)翻具,原生捆綁包可以提升調(diào)試體驗(yàn)。在從devtools中查看資源時(shí)回还,瀏覽器可以在不需要復(fù)雜的代碼映射的情況下確定原始模塊裆泳。
原生捆綁包的透明性提供了各種優(yōu)化機(jī)會(huì)。比如柠硕,如果瀏覽器本地已經(jīng)有了一部分捆綁包的緩存工禾,那么它可以將該信息告訴web服務(wù)器,然后只需要下載缺失的部分蝗柔。
Chrome已經(jīng)支持了一部分提議(SignedExchanges)但是捆綁包以及對(duì)高度模塊化應(yīng)用的應(yīng)用仍處于探索階段闻葵。
Your feedback is highly welcome on the repository or via email to loading-dev@chromium.org!
分層API(Layered APIs)
發(fā)布新特性和web API需要持續(xù)的維護(hù)和運(yùn)行時(shí)成本 ---- 每一個(gè)新特性都會(huì)污染瀏覽器命名空間癣丧,增加啟動(dòng)成本槽畔,在代碼中引入新的bug。
Layered APIs是為實(shí)現(xiàn)通過(guò)瀏覽器以可擴(kuò)展的方式實(shí)現(xiàn)和交付更高級(jí)別的api做的努力胁编。JS modules 是實(shí)現(xiàn)分層api的關(guān)鍵技術(shù):
- 由于模塊是顯式導(dǎo)入的厢钧,因此需要通過(guò)模塊公開(kāi)分層api,從而確保開(kāi)發(fā)人員只為他們使用的分層api負(fù)責(zé)嬉橙。
- 由于模塊加載是可配置的早直,所以分層api可以有一個(gè)內(nèi)置機(jī)制,用于在不支持分層api的瀏覽器中自動(dòng)加載polyfill憎夷。
modules 和 layered APIs 如何一起工作的細(xì)節(jié)我們還在制定當(dāng)中莽鸿,不過(guò)當(dāng)前的建議看起來(lái)像下邊這樣:
<script
type="module"
src="std:virtual-scroller|https://example.com/virtual-scroller.mjs"
></script>
這個(gè)<script>
標(biāo)簽會(huì)從瀏覽器內(nèi)置的分層API集(std:virtual-scroller
)或者從指向回滾到polyfill的url中去加載virtual-scroller
API。這個(gè)API可以做任何JS模塊在web瀏覽器中可以做的事情拾给。其中一個(gè)例子就是定義一個(gè)自定義<virtual-scroller>
元素祥得,因此下面的HTML將可以按照你想要的方式逐步加強(qiáng)。
<virtual-scroller>
<!-- Content goes here. -->
</virtual-scroller>
原文鏈接
如有錯(cuò)誤蒋得,歡迎指正