ES5で書かれたライブラリをES6に書き換える手順
textlint 3.6.1でコードベースをES6に書き直して、特に問題無く動いてるっぽいのでどういう手順で書き換えたかについての話。
具体的な作業は以下に残ってます。
事前準備
- テストを書く
テストが書かれてると変換した時にエラーがスグ発見できるのでカバレッジが高いテストがあると安心して変換出来ます。
面倒な時はExampleテストを追加してみるといい気がします。
そのライブラリのユースケースを考えて幾つかのパターンを実行出来るExampleテストを作っておくと、普通に実行してエラーにならないことが保証できるのでカバレッジが上げやすい気がします。
textlintの場合は普通にコマンドラインで叩く場合、.textlintrcの設定ファイルを使う場合、--rulesdir
を使う場合と3つぐらいのExampleテストを事前に追加しました。
xto6で書き換え
まずxto6を使って大雑把にコードをES6に書き換えました。
まず、lib/
に現状のES5なコードを置いておいて、ES6のコードを置くsrc/
ディレクトリを作っておきます。
.
├── LICENSE
├── lib (ES5のコード)
├── src (ES6用のディレクトリ)
└── test
そうしたら、lib/
ディレクトリ内で以下のようにしてそれぞれファイルを変換した感じです。
find . -type f -not -path "*node_modules*" -name "*.js" -print0 | xargs -0 -I % xto6 % -o ../src/%
これで、const
とかclass
とかの書き換えはある程度いい感じにできますが、
いくつか変換バグ的なものもありました。
- コンストラクタ関数の仮引数が消える
- classに変換された時になぜか仮引数が消えるので付け加えた
try/catch
内でのvar
がlet
やconst
になって解決できなくなる- Babelとかでコンパイルすれば普通にわかるのでそれで直せる
とかぐらいで、escodegenがまだES6をフルサポートしてないのもあるので、全ての変換が上手く出来るわけではないですが、意外といい感じに変換してくれると思います。 ある程度テスト書かれてれば、テストが落ちやすい部分だったのでどこが間違ってるのか分からない的な変換はなかったと思います。
テストをES6対応する
元々のテストは以下の構成でした。
これをテストからそのままsrc/
にあるES6のファイルを使ってテスト出来るように以下の構成に変更しました。
テストからlib/
を参照している場合はsrc/
に書き換えたのと、mocha.opts
ファイルを一行変更しただけで済みました。
- --require intelli-espower-loader
+ --compilers js:espower-babel/guess
細かいリファクタリング
xto6みたいに構造的にそのまま一致しない場合は変換できないので、いいタイミングだったので一緒にリファクタリングした。
- static methodベースだったものをclassに変更
パッケージの情報を書き換え
ライブラリをES6で書いて公開する所から始めようでやっているES6で書いたライブラリ構成になるということなので、package.json
を色々書き換えます。
"main"
のパスが変わってるなら変更.gitignore
に/lib
を追加lib/
をGitの管理下から外す(git rm)
JSCSでスタイルチェック
元々JSCSを導入してありましたが、 JSCSはES6も対応してるので、特に設定は必要なくそのままES6でも使えます。
jscs -x src/
xto6
でファイル末尾の改行が消えるので、jscsの–fix (-x)オプションを使えば直せます。
おわり
後はマージしてpublishしただけです。
textlintは元々処理をモジュールで分けて使ってるので、コアとなるのは1000行程のプロジェクトです。
実際にやってみてES6だと100行弱ぐらいは減ってたので1割弱ぐらいはコードベースが小さくなる気がします。 大部分はxto6の自動的な書き換えでよくて、単純にES6で動くだけの変換なら30分ぐらいでできた気がします(併せて色々リファクタリングしたのでもうちょっとかかった)
書き換えたくなった理由としては、デフォルト引数使いたい場面やArrow Function使えばこのthat
いらないのにと思ったり、これclassで良いよな的な状況がちょくちょくでてきたので書き換えました。
書き換えしなくてもBabelで変換するだけならES5のコードそのものをBabelで変換しても問題ないはずですが、中途半端に追加していくのはダルそうだったのでザクっと変換しました。
書き換えするのにあるといいのは、カバレッジが高いテストコードですが、今回はそれの補強材としてExampleテストを幾つか追加してから変換しました。
textlintの作りはESLintの作りを大体継承してますが、 ES5だとやっぱり見た目からどういう状態を持ってるのかが分かりにくい問題が起きやすい部分があると思います。
特にeslint.jsはapi
という巨大なシングルトンみたいな感じになっています。
このシングルトンの扱いをclass自体とそれをnewしたシングルトンオブジェクトをそれぞれexportするというパターンに修正したかったのもあります。
- textlint/textlint.js at 4a28a282e86d3b4b8f9c9f9449c512ec8bc560a0 · azu/textlint
- テストを考慮した singleton の ES6 export ::ハブろぐ
今回のES5 to ES6のリファクタリングでコード自体は見やすくなったのではないかなーと思います。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。