JavaScriptはなぜトレンドが毎年変わると思われていたのか
JavaScriptのエンジニャーは口を開くたびに出てくるツール名が違う、いつも環境設定をしている、みたいな話をよく聞きます。実際、それを揶揄するようなエントリーが人気だったりします。
とはいえ、JavaScriptを実際に使い込んでいる人は別にそんなに大きな変化だと思っていない節があって、台風は外周部ほど風速が速い、みたいな印象を感じます。
カンブリア紀のJavaScript
ウェブサイトをパカパカ動かすための言語でした。DHTMLです。FireBugが出る前のJavaScriptを開発していた人類は、念力デバッグを駆使していました。あるいはalert()。
三畳紀のJavaScript
prototype.js、jQuery、Closure Compiler、YUI、mochikit、Ext.jsなどの時代。JavaScriptはscriptタグで直接読み込む。モジュールとかは各ライブラリががんばっていたり、いなかったり。YAHOO.util.Animみたいなのだったり、goog.requireだっけ?でパッケージを読み込んだり。パッケージ機構は独自。JavaScriptはブラウザのためのものであって、ローカルで動かすことは基本的にない、という時代でした。
ライブラリ管理機構みたいなのはなくて、ウェブサイトから心を込めてひとつひとつスクリプトをダウンロードしたり、zipを落としてきて配置みたいな感じでした。jQueryなんかはウェブサイトに必要なライブラリをチェックボックスで選択して、必要な最低限の機能だけが入ったJSファイルを生成するウェブサービスを提供していました。jQueryプラグイン専用のリポジトリなど、コードの共有に中央集権なものはありませんでした。
JavaScriptのソースを加工するツールは多少はありました。まだ回線も細くて一番関心を持たれていたのが、難読化とminifyだったように思います。また、これらのツールは基本的に他の言語で書かれていた記憶があります。
FireBugsやらSafariやIE8以降などのブラウザの開発ツールなど、デバッグができるすげぇ!console.logで変数が表示できる!とか、ようやくプログラミング言語として使えるようになったぐらいで、jslintが超強力なツールとしてもてはやされたりしてる感じでした。まだ超大規模なJavaScript開発とかは登場する前で、1ファイルでなんとか、みたいな空気感だった記憶があります。テスティングフレームワークはQUnitとかTDD系でしたよね。
- フロントエンド: prototype.jsやjQueryやら各種UIライブラリ
- パッケージ管理: ライブラリごとになんとか手探り
- ファイルの結合: 基本ライブラリごと。アプリケーションコードは結合しない。
- ファイルに対するポストプロセス: 難読化。minify。
- タスク管理: 各自自由
- JSコードを処理する処理系: スクリプト言語やらJavaやら
ジュラ紀のJavaScript
共通のパッケージ機構を用意しよう、という流れ+node.jsの興隆がありました。パッケージ機構はrequire.jsのAMDとcommon.jsのBrowserifyが2強でした。node.jsのおかげで、ローカルでもJavaScriptを使おう、という流れになってきました。npmもあってライブラリの流通も活発化します。JavaScriptのJavaScriptによるJavaScriptのためのツール。JavaScriptルネッサンスです。
タスクランナーはjake、ユニットテストはJasmine、require.jsなどを使って管理。パッケージ管理はnpm、JSのバンドルはrequire.jsやBrowserify・・・みたいな空気感だったと思います。JSHint、JSDoc Toolkitなんかが出てきた記憶があります。JavaScriptによるJavaScriptパーサも作られて、次の時代の礎となる技術の基盤ができあがりました。
- フロントエンド: jQuery、Bootstrap
- パッケージ管理: npm, (一瞬Bower)
- ファイルの結合: require.jsやBrowserifyを使ったAMD/common.jsで結合(AMDは結合しない非同期読み込みもあり)
- ファイルに対するポストプロセス: 結合。難読化。minify。
- タスク管理: Jakefileとか
- JSコードを処理する処理系: node.js
白亜紀のJavaScript
JavaScriptらしさを求めてツールが大爆発しました。CoffeeScriptや6to5あらためBabelなどのトランスパイラが登場。より効率の良い開発手法や、型を使った実装・デバッグ支援などに注目が集まりました。
ウェブのフロントエンドも、JavaScriptもKnockout.jsやらbackbone.jsから初代vue.jsあたりから、React/Angular.jsなど一気にフレームワークが普及し、景色が一変しました。脱jQueryもさかんに言われました。
ジョブランナーも複雑化するプリプロセスに対応するためにプログラマブルにタスクが組み合わせられるGrunt/Gulpを中心にエコシステムが急拡大し、ファイルのモニタリングでビルド自動実行やらライブリロードやら、さまざまな機能を使うのがツウのような感じでした。SASSやらSCSSとWebPackと組み合わせた動的ローディングのシステムとか、いろいろなことが実現されるようになりました。
Grunt/Gulp/Babelで特徴的だったのはプラグインシステムです。コアは小さく、機能拡張はプラグインで行う仕組みが導入されました。これらのツールだけではなく、多くのツールがこの仕組を導入しています。
npmはCPANやPyPI、RubyGemsを抜いてパッケージ数一位となりました。
- フロントエンド: MVC, MVVM, 仮想DOM
- パッケージ管理: npm
- ファイルの結合: WebPackやBrowserifyを使ったAMD/common.jsで結合(AMDは結合しない非同期読み込みもあり)
- ファイルに対するポストプロセス: トランスパイル、難読化、minify。
- タスク管理: gulp/grunt
- JSコードを処理する処理系: node.js
新生代のJavaScript
前期の大爆発から少し後退し、安定化を模索しはじめているところです。最初に触れたように、JSのツールが変わりすぎる問題がクローズアップされたり、node_modules以下がやべぇぞ!npm 3でアルゴリズムが変わるよ!shrinkwrapうまく動かないんだけど!とか云々。leftpad問題もありましたね。CoffeeScriptの負の遺産が・・・みたいなことも言われるようになりました。
この直前の時代はさまざまなツールが登場し、改善や改良やら新ツール、車輪の再発明など、とにかくエネルギーにあふれた時代でした。とにかく重複を恐れず、開発リソースがガンガン突っ込まれていました。変化が大きく見えたのはこの時期です。フロントエンドのアーキテクチャの変更 x トランスパイラの登場 x ファイル結合のツール変更、タスク管理のツールの変更(grunt/gulp)などが波状攻撃をしかけてきました。組み合わせ数も多く、見るウェブサイトによって使うツールセットが違うなんてのもざら。
特に影響が大きかったのが、grunt/gulp周りだったように思います。gruntを使っていて、その後パフォーマンスが良いからgulp、みたいな感じで足元から大きくツールセットが変わるというのが頻繁に行われました。そんでもって、grunt/gulpのプラグインが同じ機能でも大量に作られ、「こっちはあまりメンテされてないから(現時点では)ダメ」「こっちはこのケースだと動かないから」のように、参考情報の形骸化の要因になったように思います。leftpadほどではないものの、小粒のプラグインが多く、メンテナンスされるかもわからん、みたいな感じです。
- フロントエンド: MVC, MVVM, 仮想DOM
- パッケージ管理: npm
- ファイルの結合: WebPackやBrowserifyを使ったAMD/common.jsで結合(AMDは結合しない非同期読み込みもあり)
- ファイルに対するポストプロセス: トランスパイル(Babel/TypeScript)、難読化、minify。
- タスク管理: npm scripts
- JSコードを処理する処理系: node.js
とはいえ、やろうとしていること(↑のリスト)はほぼ変わりません。ここ数年は「とにかく効率アップを」という掛け声のもとにガンガンツールは変わっていますが、開発の基本骨格は全然変わっていません。
grunt/gulpへの反動からか、最近ではトランスパイラの呼び出しやポストプロセスは、「どうせ最終的に絶対に使うことになる」BrowserifyやらWebPackから呼び出されることが多く観測されるようになってきました。TypeScriptもBabelも、すべてここから呼べます。そしてこれをnpm scriptsを使って呼び出す方向です。ツール周りはかなりシンプルになります。ちなみにBabelのBrowserify用のツールのBabelifyと、WebPack用のBabel-loaderはBabel公式ツールです。TypeScriptの場合は公式ではないですが、まあプラグインが乱立して説明や設定ファイルの形式がページによって違う、ということは減るんじゃないでしょうか。
$ browserify -p tsify
あとは、トランスパイラもTypeScriptやBabel以外は目にする機会も減りましたね。
まとめ
僕は完全に中にどっぷり使ってみていたわけではありませんし、ブラウザ以外のJavaScriptを使うことが多かったのですが、JavaScript周辺の変化はだいぶ落ち着いてきているように思います。yarnみたいなのは出てきているけどnpmを完全に置き換えるものではなくアクセラレータのようなものだし、まったく新しいパラダイムではないですよね。
当初はプログラミング言語を名乗るとバカにされるような感じでしたが、node.jsが出てきて、さまざまな周辺ツールが整備されるに従って、JS以外で書かれていたツールもどんどんJSで書き直されてエコシステムが整備されてきました。ある意味では独り立ちにあたって持たされた変化です。そして、他の言語のパラダイムからJS固有の文化が醸成されて、ツールもいろいろ試行錯誤されてきました。成長痛のようなもんです。これらを経て、変化の要因はだいぶ減ってきています。ReactのFlux周りとかまだ変わりそうなところもありますが、設定ファイル全書き換えとか、そういうのはなくなってくるはず。
使われるMVCやUIライブラリの種類もかなり厳選されてきて、トランスパイラなど使われるツールの種類も絞られてきました。まあまだLTSが短くて、バージョンアップでコードの中身の修正が必要になることはありますが、周辺ツール含めて開発手法が大きく変わる、というのはなくなっていくでしょう。
次に変化が来るとしたらWebComponentsですが、開発を大きく変えるものではないと思います。よくできた独立性の高いコンポーネントであれば、HTMLタグがちょっと増えるようなものでしかないし、仮想DOMで管理されるDOMツリーの要素がちょっと増えたぐらいといった感覚で使えるはず。もしくはWebComponentsの開発自身の中に、Shadow DOMの内側で仮想DOMを使うといったこともできるでしょう。これまでのフロントエンドとWebComponentsは直交しているので「引っ越し」は不要だと思います。まあ想像でしかないので、これは今後検証してみたいところです。