JSについて最近知ったこと

歴史
太古の昔は、NetscapeとMicrosoftが勝手にJavaScriptを作っていたので、ブラウザ依存のJavaScriptコードを記述する必要があった。そんな中、ECMAScriptが策定されJavaScriptの仕様が統一された。
2015年にES6が制定されclassとかconstとかアロー関数などのモダンなJSになった。2015年からは毎年ECMAScriptが改定されている。議論はgithubで管理されている。

実装
chromeやnodejsが使っているJSの処理系はV8。
ブラウザの処理系はECMAScriptに加えてWeb APIs(DOMとか)が使える。
nodejsの処理系ではECMAScriptに加えてcommonjsが使える?(ESMも使える?)
ブラウザでもサーバサイドでもECMAScriptが使えるのは共通だが、付属物が違うので出来ることも違う。

var a = 0
とlet a = 0
の違い。
function a() {}
とa = function() {}
の違い。

CommonJSとES Modules
Node.jsが開発されたのはES6以前だったので、ES Modulesがそもそもなかった。
そのためNode.js用のモジュール管理の手法としてCommonJSが開発された。その経緯から現代でもNode.jsではCommonJSがメインで使われている。
CommonJSではrequire
/exports
でモジュールを読み込む。
一方でブラウザの処理系はES6策定後に変更を遂げて、ES Modulesを用いたモジュール管理が行われている。ES Modulesではexport
/import
でモジュールを読み込む。
最近、Node.jsでもES Modulesを用いたモジュール管理が実施出来るようになってきている。そのため、node.jsでモジュールを読み込む際にはES Modulesを読み込むのか、CommonJSを読み込むのか注意が必要。
(この説明あっているんだろうか。。。。)

JSの歴史振り返った記事。

個人的にJSのおもろいなぁと思ってる機能はこの辺かなぁ
- サーバーでもフロントでも同じコードが動く
- babelのトランスパイル
- 毎年追加される新たな言語機能
- TypeScript

サーバーでもフロントでも同じコードが動く
これはかなり悪用されていて、ここからServer Side Renderingとか、最近ではReact Server Componentsみたいなことができるようになった。他の言語だとこういう共通化はできない。

babelのトランスパイル
ES6の登場の時は新しい言語使用をそれ以前のブラウザに対応させるためのトランスパイラだったと思う。ただこれでみんながJSをトランスパイルして動かすものという認識になったおかげで、webpackとかが発展して新しい言語仕様とか、ReactのJSX的な拡張もできるようになったんだと思う。フロント書く時もnodeの処理系でデバッグできるとかもこれのおかげなのかなぁ
毎年追加される新たな言語機能
これもbabelがあるからこそ成しえるわざだと思う。Pythonとかそんなことできないし。

TypeScript
みんながbabelとかwebpackとかを設定したおかげでJSを書く必要さえ無くなって、AltJSが大量に発生した。そんなときにVSCodeと一緒に広まったのがTypeScriptなのかなぁ。最初は普通のJSのように使えて勉強してくうちに豊富な型機能のありがたみに気付かされる言語だと思う。

JSエコシステムを全く知らない人にJSの魅力を伝えるために、どうしてこんなに便利になっているのか言語化してみたけど、あってるかわからん。歴史を知らないんだよなぁ
「昔はブラウザ戦争のおかげで、同じJSのコードを複数の処理系で動かす必要があった。そのためにJSのトランスパイルが発展した。トランスパイルの流行によって言語が新機能を取り入れやすくなり、言語の拡張も発展した。またVScodeとTypeScriptが開発され、開発環境も快適になった。様々な処理系での動作が想定されており開発環境が快適であることから、バックエンドやデスクトップアプリでも使われるになった。現在はこれらの特徴を活かしCDNでの動作させたりクラウドの設定yamlの代替としても使われ始めている。」
こんな感じかなぁ

esbuild
以下の記事がよく纏まってる。
みんながJSでいろんな言語作るから、webpackでコンパイルすると遅すぎる。新たにGoで書き直したesbuildが登場。みんなwebpackを捨ててesbuildに乗り換えてる。

cdkのtypescriptはローカルにesbuildをインストールしておけばそれを使ってくれるらしい。(MacのDockerは遅いのでローカルにesbuild入れたほうが良さそう。)

手元のcdkのプロジェクトで軽く計測した。
ローカルのesbuildを使う場合。4.5秒
cdk synth 4.82s user 0.65s system 120% cpu 4.544 total
dockerのesbuildを使う場合。17.1秒
cdk synth 4.11s user 0.53s system 27% cpu 17.091 total
ローカルのesbuildの方が4倍高速。
esbuildはnpm i -D esbuild
一発でインストールできる。