For English reader: https://github.com/othree/til/blob/master/js/esm-package.md
這個問題我卡蠻久了,最近才解決加上找好一些資訊的來源,目標就是要讓一個 NPM package 同時提供 CommonJS module 和 ES module 的版本,現在很多地方可以用 ES module 了,像是 Node.js 自己有經有在測試用 mjs 副檔名,webpack 和 rollup 也都支援 ES module 的 bundle,而且要 tree shaking 的功能也需要使用 ES module,用以前的 CommonJS 是不支援的,不多廢話,直接看怎樣做吧:
{
"name": "smartypants",
"version": "0.1.1",
"main": "smartypants",
"module": "smartypants.es6.js",
"jsnext:main": "smartypants.es6.js",
...
}
package.json 這樣寫,然後需要提供以下三個檔案:
-rw-r--r-- 1 othree staff 21874 Jul 14 10:38 smartypants.es6.js
-rw-r--r-- 1 othree staff 24885 Jan 9 17:12 smartypants.js
-rw-r--r-- 1 othree staff 21874 Jul 14 10:38 smartypants.mjs
這段是我從 smartypants.js 那邊拿來的,重點在:
main
裡面的檔名不寫副檔名,該檔名要同時提供js
和mjs
兩種- 多加上
module
這筆設定
說明一下,Node.js 現在判斷是哪種模組格式的方式是看副檔名,所以一定要mjs
的檔案才會當成 ES module,然後剛好解析main
檔案時的副檔名會自動補,所以就乾脆拿掉,同時提供smartypants.js
和smartypants.mjs
兩個檔案,其實都是main
用的;再來是module
這個設定和 Node.js 以及 NPM 無關,其實是 rollup 提出來的 pkg.module,rollup 如果在解析模組實有看到這個設定,就可以把這個檔案拿來用,當時設計是這個設定 ES module,以前的 main 則是 CommonJS module,雖然是 rollup 提出的,不過 webpack 現在也支援了,範例中還有一筆jsnext:main
則是比較早期用的 key。
再更進階一點,還有目標對象的問題,就是產出是瀏覽器用的還是 server 端用的,以前這問題不太常見,不過隨著 server side rendering 越來越普及,這問題就開始比較多人關注了,webpack 就有支援 bundle 的目標對象,也有支援 pkg.browser 設定,webpack 的 issue #5673 有不少討論,有興趣的可以參考看看,不過要注意的是browser
似乎是第一順位,設定的時候要小心點。