日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

浏览器中的 ESM

發(fā)布時(shí)間:2023/12/9 HTML 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浏览器中的 ESM 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以加我微信?ruochuan12

早期的web應(yīng)用非常簡單,可以直接加載js的形式去實(shí)現(xiàn)。隨著需求的越來越多,應(yīng)用越做越大,需要模塊化去管理項(xiàng)目中的js、css、圖片等資源。這里有很多大家熟悉的模塊化標(biāo)準(zhǔn), CJS、AMD、CMD、UMD 等等。模塊化提供了我們更好的方式來組織和維護(hù)函數(shù)以及變量。而在 npm 生態(tài)開發(fā)的背景下,CJS 模塊是開發(fā)過程中接觸最多也是無法避免的。但由于瀏覽器并不能直接執(zhí)行基于 CJS 打包的模塊,因此類似 webpack 等打包工具便應(yīng)運(yùn)而生。隨著webpack 大有一統(tǒng)構(gòu)建工具的趨勢下,JavaScript 官方的標(biāo)準(zhǔn)化模塊系統(tǒng)ESM完成了。本文主要介紹下模塊化標(biāo)準(zhǔn)間差異、基本加載原理。

模塊化發(fā)展

1、為何要模塊化

仔細(xì)想想,用 JavaScript 編碼就是管理變量。這一切都是關(guān)于為變量賦值,或?yàn)樽兞刻砑訑?shù)字,或?qū)蓚€(gè)變量組合在一起并將它們放入另一個(gè)變量中。

如果代碼中僅有少量的變量,那么組織起來其實(shí)是很簡單的。一旦有很多的變量,我們會通過函數(shù)作用域去組織變量。因?yàn)楹瘮?shù)作用域的緣故,一個(gè)函數(shù)無法訪問另一個(gè)函數(shù)中定義的變量。

如果只維護(hù)少量變量非常簡單。但是如果有很多的變量,我們就需要用一種方法來幫助做到這一點(diǎn),叫做作用域。由于作用域在 JavaScript 中的工作方式,函數(shù)不能訪問在其他函數(shù)中定義的變量。

這種方式是很有效的。在寫一個(gè)函數(shù)的時(shí)候,只需要考慮當(dāng)前函數(shù),而不必?fù)?dān)心其它函數(shù)可能會改變當(dāng)前函數(shù)的變量。如果想要函數(shù)之間共享變量要怎么辦呢?一種通用的做法是全局作用域。

在 jQuery 時(shí)代這種提升做法相當(dāng)普遍。在我們加載任何 jQuery 插件之前,我們必須確保 jQuery 已經(jīng)存在于全局作用域。

所有的 <script> 必須以正確的順序排列,必須保證被依賴的變量先加載。如果排列錯(cuò)了,那么在運(yùn)行過程中,應(yīng)用將會拋出錯(cuò)誤,并且停止繼續(xù)運(yùn)行。

代碼之間的依賴是不透明的。這使得代碼維護(hù)變得困難。代碼變得充滿不確定性。任何函數(shù)都可能依賴全局作用域中的任何變量。

其次,由于變量存在于全局作用域,所以任何代碼都可以改變它。

2、模塊化的作用

模塊化為你提供了一種更好的方式來組織變量和函數(shù)。可以把相關(guān)的變量和函數(shù)放在一起組成一個(gè)模塊。這種實(shí)現(xiàn)形式可以把函數(shù)和變量放在模塊作用域中。模塊作用域還提供一種暴露變量給其他模塊使用的方式。模塊可以明確地指定哪些變量、類或函數(shù)對外暴露。

對外暴露的過程稱為導(dǎo)出。一旦導(dǎo)出,其他模塊就可以明確地聲稱它們依賴這些導(dǎo)出的變量、類或者函數(shù)。

因?yàn)檫@是一種明確的關(guān)系,所以你可以很簡單地辨別哪些代碼能移除,哪些不能移除。

擁有了在模塊之間導(dǎo)出和導(dǎo)入變量的能力之后,你就可以把代碼分割成更小的、可以獨(dú)立運(yùn)行地代碼塊了。基于這些代碼塊,你就可以像搭樂高積木一樣,創(chuàng)建所有不同類型的應(yīng)用。比較流程的規(guī)范有CommonJS,AMD,CMD,ES,UMD等

3、現(xiàn)有模塊標(biāo)準(zhǔn)

CJS?是?CommonJS?的縮寫。只適用于node端:

const _ = require('lodash'); module.exports = function doSomething(n) {}

AMD?代表異步模塊定義。在瀏覽器端有效:

define(['dep1', 'dep2'], function (dep1, dep2) {return function () {}; });

UMD?代表通用模塊定義(Universal Module Definition):

(function (root, factory) {if (typeof define === 'function' && define.amd) {// AMD. Register as an anonymous module.define([], factory);} else if (typeof module === 'object' && module.exports) {// Node. Does not work with strict CommonJS, but// only CommonJS-like environments that support module.exports,// like Node.module.exports = factory();} else {// Browser globals (root is window)root.returnExports = factory();} }(typeof self !== 'undefined' ? self : this, function () {// Just return a value to define the module export.// This example returns an object, but the module// can return a function as the exported value.return {}; }));

什么是 ESM

簡介

ESM是ES6提出的標(biāo)準(zhǔn)模塊系統(tǒng),ECMAScript modules。JS自己的模塊體系

<script type="module">import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js';class App extends Component {state = {count: 0}add = () => {this.setState({ count: this.state.count + 1 });}render() {return html`<div class="app"><div>count: ${this.state.count}</div><button onClick=${this.add}>Add Todo</button></div>`;}}render(html`<${App} page="All" />`, document.body); </script>

思考:上述代碼和在webpack中開發(fā)有啥區(qū)別?

2、瀏覽器端技術(shù)實(shí)現(xiàn)

回顧下Webpack執(zhí)行流程

  • 本地模塊化解析(通過webpack或者babel,將import解析成cjs)

  • 將各個(gè)庫打包成一個(gè)js boundle

  • 開啟服務(wù),托管資源

  • 瀏覽器獲取資源

  • 執(zhí)行代碼

  • 瀏覽器端ESM執(zhí)行流程

  • 開啟服務(wù),托管資源(ES源碼)

  • 加載入口文件,瀏覽器模塊化解析

  • 構(gòu)建

  • 遍歷依賴樹,先解析文件,然后找出依賴,最后又定位并加載這些依賴,如此往復(fù)。(下載所有的js)

  • 模塊映射

    當(dāng)加載器要從一個(gè) URL 加載文件時(shí),它會把 URL 記錄到模塊映射中,并把它標(biāo)記為正在下載的文件。然后它會發(fā)出這個(gè)文件請求并繼續(xù)開始獲取下一個(gè)文件。

  • 解析模塊
    所有的模塊都按照嚴(yán)格模式來解析的。不同文件類型按照不同的解析方式稱。在瀏覽器中,通過 type="module" 屬性告訴瀏覽器這個(gè)文件需要被解析為一個(gè)模塊。不過在 Node 中,我們并不使用 HTML 標(biāo)簽,所以也沒辦法通過 type 屬性來辨別。社區(qū)提出一種解決辦法是使用 .mjs 拓展名。

  • 運(yùn)行
    采用深度優(yōu)先的后序遍歷方式,順著關(guān)系圖到達(dá)最底端沒有任何依賴的模塊,然后設(shè)置它們的導(dǎo)出。模塊映射會以 URL 為索引來緩存模塊,以確保每個(gè)模塊只有一個(gè)模塊記錄。這保證了每個(gè)模塊只會運(yùn)行一次。

  • 3、為什么火起來

    • ES語法基本確定

    • http2普及

    • 新瀏覽器普及

    • 開發(fā)與發(fā)布代碼一致

    • 啟動快

    • 全新加載模式

    目前瀏覽器支持:

    目前只有5%的瀏覽器不兼容es相關(guān)規(guī)范。

    4、為什么還沒火起來

    • 部分瀏覽器的兼容性

    • 歷史包袱悠久

    • 生態(tài)不完善

    實(shí)戰(zhàn)

    當(dāng)我們在項(xiàng)目中使用需要考慮以下幾個(gè)問題點(diǎn)

    1. 代碼開發(fā)需要基于es開發(fā)

    let a = 1; new Promise() () => {} ...

    2. 依賴庫加載

    • node_modules代碼服務(wù)化

    • 兼容cjs

  • 加載包內(nèi)部es目錄

  • cjstoesm

    • CDN(network for npm)

  • https://unpkg.com/

  • https://www.skypack.dev/

  • 3. 兼容不支持的瀏覽器

    • type="module"實(shí)現(xiàn)

      • 如果瀏覽器不支持,他只識別type="text/javascript"不識別 type="module" ,故不下載js;如果支持,則會下載js

      • 如果瀏覽器不支持,則會忽略nomodule,下載js;如果支持,則不會下載js

    <script type="module" src="app.js"></script> <script nomodule src="app-bundle.js"></script>
    • systemjs實(shí)現(xiàn)https://github.com/systemjs/systemjs

    <script src="system.js"></script> <script type="systemjs-importmap"> {"imports": {"lodash": "https://unpkg.com/lodash@4.17.10/lodash.js"} } </script> <script type="systemjs-module" src="/js/main.js"></script>

    4. jsx支持

    • 通過其他開源庫

    <script type="module">import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.module.js';class App extends Component {render() {return html`<div class="app"></div>`;}}render(html`<${App} page="All" />`, document.body); </script>
    • 本地語法糖解析

    <APP {...Props}/> => React.createElement(App, {...props})

    現(xiàn)有腳手架

    1. snowpack

    • 托管node_modules

    • 支持圖片、css等資源

    • JSX 和 Typescript 編譯

    • HMR

    • ...

    2. vite

    https://cn.vitejs.dev/guide/

    目前snowpack的作者后續(xù)可能不再維護(hù)了,所以推薦大家使用vite

    ESM 未來

    2018 年 5 月 Firefox 60 發(fā)布后,所有的主流瀏覽器就都默認(rèn)支持 ESM 了。Node 也正在添加 ESM 支持,為此還成立了工作小組來專門研究 CJS 和 ESM 之間的兼容性問題。所以,在未來你可以直接在 <script> 標(biāo)簽中使用 type="module",并且在代碼中使用 import 和 export 。同時(shí),更多的模塊功能也正在研究中。比如動態(tài)導(dǎo)入提案已經(jīng)處于 Stage 3 狀態(tài);import.meta也被提出以便 Node.js 對 ESM 的支持;模塊定位提案 也致力于解決瀏覽器和 Node.js 之間的差異。

    相信在不久的未來,跟模塊一起玩耍將會變成一件更加愉快的事!

    node v10以上版本全部支持ESM https://kentcdodds.com/blog/super-simple-start-to-es-modules-in-node-js

    相關(guān)參考

    ECMAScript modules in browsers https://jakearchibald.com/2017/es-modules-in-browsers/

    JavaScript 模塊現(xiàn)狀 https://zhuanlan.zhihu.com/p/26567790

    基于esm、html、unpkg的前端開發(fā)模式:https://github.com/developit/htm

    How I Build JavaScript Apps In 2021:https://timdaub.github.io/2021/01/16/web-principles/

    Find out how much turning on modern JS could save. https://estimator.dev/

    什么是amd、commonjs、umd、esm? https://zhuanlan.zhihu.com/p/96718777

    ES modules: A cartoon deep-dive:https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/

    import.map:https://github.com/WICG/import-maps

    面對 ESM 的開發(fā)模式,webpack 還有還手之力嗎? https://topic.atatech.org/articles/202736


    總結(jié)

    以上是生活随笔為你收集整理的浏览器中的 ESM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。