Slide 1

Slide 1 text

ESM移行は無理だけどおれも Sindreのライブラリが使いたい! ワインと鍋.js

Slide 2

Slide 2 text

About me ● @__sosukesuzuki ● Ubie ( ユビー ) ● Prettier ● Babel ● 筑波大学 (B3?B4)

Slide 3

Slide 3 text

前提 ● Prettierの話です ○ CommonJS で書かれてる ○ Node.js でソースコードをそのまま実行できる必要がある ○ 配布するときはガッツリバンドルする ● この方法を推奨するものではありません

Slide 4

Slide 4 text

2021年、世はECMAScript Modules時代に突入(?) ● 2021年4月Node.js 10がEoLを迎えた ● パッケージメンテナーはNode.js 10のサポートを終了し、Node.js 12以降のみをサポートするようになる ● Node.js 12はECMAScript Modulesを完全にサポートするバージョンである ● これはつまり、世はECMAScript Modules時代!!(?)

Slide 5

Slide 5 text

少なくともSindre SorhusはESM時代に突入! ● 多くのNode.js用ライブラリの作者・メンテナーとして知られる Sindre SorhusはESMを強く推している ○ ky, got, execa, tempy, chalk, type-fest, mem, etc… ○ 自身のライブラリを続々と ESMへ移行したり、そのためのガイドを書いたりしている ● ESMのみをサポートするライブラリを使うためには、基本的には使う側も ESMに移行する必要がある ● 彼のライブラリに依存せずに自分のライブラリをメンテナンスするのはなかなか難しい ● 多くのライブラリメンテナーも (自動的に)ESM時代に片足突っ込んでしまった! ● ちなみに、unified とか remark の作者の wooorm も ESM 派

Slide 6

Slide 6 text

少なくともSindre SorhusはESM時代に突入! https://medium.com/sindre-sorhus/get-ready-for-esm-aa53530b3f77

Slide 7

Slide 7 text

すぐにESM移行をするのはキツイ! ● ECMAScript Modulesに移行することはややめんどい ○ 全部書き換える必要がある、コードがでかいとめんどい ○ dynamic require をそのまま dynamic import に置き換えることはできない (Promise) ○ パッケージの配布方法やビルドスクリプトを変更する必要があるかもしれない ○ 短期的なメリットはほとんどない ■ 別にCommonJSでも動く ■ Sindre のライブラリが使えなくても死なない ● メジャーアップデートをする必要がある ○ 色々予定や覚悟がね ...

Slide 8

Slide 8 text

残された選択肢 ● Sindre SorhusライブラリについてはCommonJSをサポートする最後のバージョンを使い続ける ● Sindre Sorhusライブラリと同じような機能を持つライブラリを自作する or 探す ● 重い腰をあげてECMAScript Modules移行を決行する

Slide 9

Slide 9 text

残された選択肢 ● Sindre SorhusライブラリについてはCommonJSをサポートする最後のバージョンを使い続ける ● Sindre Sorhusライブラリと同じような機能を持つライブラリを自作する or 探す ● 重い腰をあげてECMAScript Modules移行を決行する ● 気合でCommonJSからESMパッケージを使う

Slide 10

Slide 10 text

気合でCommonJSからESMパッケージを使う ● CommonJSからESMパッケージをrequireすることはできない ○ dynamic importすればできるけど、全部 Promiseになるのでやりたくない ● なので、ESMパッケージをCommonJSにしてしまおう

Slide 11

Slide 11 text

ESMパッケージをCommonJSにする ● あらかじめESMパッケージのリストを用意しておく ○ https://github.com/prettier/prettier/blob/main/scripts/vendors/vendors.mjs ○ const vendors = [“chalk”, /* その他 */, “tempy”]; ● vendorsを全部esbuildでCJSに変換する! ○ esbuild速すぎる ○ require.resolve(vendor)を entry point にしてCommonJSファイルへとバンドルする ● ./vensors にCJSファイルを置く ○ ついでの型定義ファイルも (存在すれば)いい感じに生成しておく ● (ライセンス情報を残しておく )

Slide 12

Slide 12 text

ESMパッケージをCommonJSにする ● というようなことをやってくれるスクリプトを書く ○ https://github.com/prettier/prettier/tree/main/scripts/vendors ○ npm scripts に vendors:bundle として登録してある

Slide 13

Slide 13 text

ESMパッケージをCommonJSにする ./node_modules chalk (ESM) execa (ESM) got (ESM) ./vendros chalk (CJS) execa (CJS) got (CJS) esbuild

Slide 14

Slide 14 text

ESMパッケージをCommonJSにする ● ./vendors の中身はこんな感じ ○ パッケージ名.js と パッケージ名.d.ts が並んでる

Slide 15

Slide 15 text

ESMパッケージをCommonJSにする ● depandabotとかで勝手にpackage.jsonのバージョンが更新されると node_modulesとvendorsでバージョ ンの整合性がとれないことがある ● そういのはGitHub Actionsではじいてる ○ - run: yarn run vendors:bundle && echo "Listing changed files:" && git diff --name-only --exit-code && echo "No files changed." ● GitHub Actionsが落ちたら、メンテナーの手作業で yarn verndors:bundle の結果を追 push する

Slide 16

Slide 16 text

この方法のダメな点 ● 謎のレイヤーが挟まってデバッグしにくい ● 謎のレイヤー自体のメンテコストがある ● ESMパッケージを全部CJSにバンドルしてしまうのでTree Shakingとかない ○ https://sosukesuzuki.dev/posts/how-to-reduce-prettier-size/ で紹介したような手作業 Tree Shakingでサイズを 落とすしかない ● 標準の仕組みに乗っかれないのは嫌な気持ちになる ● ビルド職人みたいな人がいないと厳しそう

Slide 17

Slide 17 text

やめよう!! ● Prettier v3 ではコードベースのECMAScript Modules移行が行われるのでこの仕組みともおさらばでき る ○ prettier/prettier/package.json の type は module ○ prettier/prettier/dist/package.json の type は commonjs ● うれしいね ● 2022年9月にリリースしたい気持ちでいっぱいです