這裡指的 ES Modules (esm)是指原始碼中使用 'import','export' 方式匯入或匯出模組.
這種方式成為標準已經好幾年了, 各大瀏覽器廠商全部支援這種寫法:
<script type="module">
import mod from 'https://dev.jspm.io/npm:some-module';
</script>
複製程式碼
問題: 模組開發者釋出什麼樣的的檔案才能最好的支援這種方式.
我們知道以往的通用做法是使用 require
, module.exports
, 如果你的模組是這種方式, 那 jspm.io 可以解決多數相容性問題(畢竟具體寫法有很多, jspm 不一定能全部理解和正確處理).
顯然 jspm 為這種載入方式付出了額外的工作, 伺服器端進行轉換, 二次包裝, 甚至多次請求.
那麼如何使這種成本最低, 也就是所謂的正確姿勢?
兩種方法:
- 採用同時相容 CJS 和 esm 的格式, 優點: 一個檔案解決相容性
- 分離檔案, '.js' 檔案使用傳統 CJS 風格, '.mjs' 檔案使用 esm 格式, 優點: 乾淨
第一種方式的例子: https://unpkg.com/@babel/parser@7.0.0-beta.48/lib/index.js
這是社群使用的相容方式: Object.defineProperty(exports, '__esModule', { value: true });
第二種會有兩個檔案: '.js' 和 '.mjs' 的, 其中 '.js' 的不包含 'import','export', '.mjs' 至少要包含 'export'
打包工具通常都支援多種方式(打包工具就是幹這個的), 比如 rollupjs
糟糕的方法:
副檔名是 '.js', 裡面卻使用了 'import','export'. 正如前文所述, 會增加載入成本, 這方法過時了.
副檔名是 '.mjs' 裡面卻使用 'require' 或者沒有使用 'export'. 這完全誤用了 '.mjs', 這樣用就失去了 '.mjs' 被創造出來意義.
現實中, 很多專案在打包的時候不會考慮到載入成本, 這是一種慣性, 隨著時間的推移可能會改變, 也可能會更糟糕. 因為如果多數開發者都不在乎 '.mjs' 這個副檔名的話, 問題只會越來越混亂.