JavaScriptの歴史をまとめてみる

まだまだJavaScriptの基本やNode.jsについて抑えておこう!ということで、こちらの動画を見てJavaScriptの歴史を自分なりにまとめてみました。

【モダンJavaScript #2】歴史から学ぶJavaScript前編。ECMAScript、CommonJS、モジュール、名前空間を知ろう【フロントエンドエンジニア講座】 - YouTube

【モダンJavaScript #3】歴史から学ぶJavaScript後編① Node.jsとパッケージ管理システムnpm【フロントエンドエンジニア講座】 - YouTube

【モダンJavaScript #4】歴史から学ぶJavaScript後編② IIFE・AMDモジュールとブラウザ向けパッケージ管理システムBower 【フロントエンドエンジニア講座】 - YouTube

【モダンJavaScript #5】歴史から学ぶJavaScript完結編 バンドル・コンパイルを知る。Browserify, webpack, Babel【フロントエンドエンジニア講座】 - YouTube

素晴らしい動画をありがとうございます!!

☆私の解釈が間違っている可能性もあるので、正しく知るには動画を見ることをおすすめします!

また最近でこんな記事も見つけました。

プログラミング初心者のための JavaScript と Node.js の歴史、それを踏まえた勉強方法

用語など所々難しく感じましたが、JavaScriptは色々な人に使われていて、そのためちゃんと新しく正しい記事を探すべきであることが分かりました。

ざっくりしたJavaScriptの歴史の流れ

動画では4回に分けられていたので同じく分けました。

  1. JavaScriptの誕生
  2. Node.jsの誕生
  3. ブラウザ側でのモジュールの模索
  4. ブラウザJSの進化

サーバーとブラウザ、それぞれでJavaScriptが使われていくようになるのですが、ブラウザのJSは、しばらく使いづらい状況が続いていました。
そこでコードを事前に変換する という発想の転換によって、とても便利に使いやすくなりました。

さらに大事なこととして以下が挙げられていました。

・ JavaScriptの歴史のお話では「ブラウザとモジュール」というのが大きなテーマ
・ プログラミング用語はコンテキスト(背景)、言語、人、ツールによって違う意味で使われる。

用語の定義については、以前引っかかった「コンパイル」もこの類ですね。 今回は「モジュール」と「パッケージ」の違いでもやもやする予感です。

以下長くなりますが文字に起こしました。

1. JavaScriptの誕生

Natscapeのブラウザ(Netscape Navigator)で使われたのが始まり。 もともとは「LiveScript」。
当時注目されていたJavaにあやかって「JavaScript」に名称変更した。

IEでも搭載される

それぞれのブラウザに合わせたJavascriptを作らなくてはならず大変。
統一させたい、と考える。

ECMAScript(エクマスクリプト)の誕生

JavascriptECMA International(標準化団体)に登録された。仕様を一つに統合した。

☆ES(←きっと「ECMAScript」の略)は毎年リリースされる。現在はES[20xx]という表記。

ECMAScript
JavaScriptの中核となる言語仕様のこと。
いろいろな実行環境(サーバー:Node.js、ブラウザ間)でも共通の動作のみが定義されているJavaScript

☆といってもそのまま使えるわけではなく、環境によってはコンパイルしたりする必要がある(後述)。

不人気の後、大人気!

JS起因のクラッシュ、悪用ウィルス、不快なアニメーションなども多く、機能の使用をオフにする人もいた 。

  • GoogleMapsがAjaxを利用 :非同期通信で画面が一瞬白くなったりしない
  • jQueryの誕生:ブラウザ間の差異を吸収できて便利

これらの影響で人気になる。

Ajax(Asynchronous JavaScript + XML)について
初心者目線でAjaxの説明 - Qiita

サーバーサイドのJavascript

サーバーサイドでもJavascriptを作ろう、ということで「ServerJS」というプロジェクトが立ち上がる。

たくさんのAPIを作る必要がある

「CommonJS」へ名称変更(プロジェクト名の変更)
たくさんのAPI仕様が作られていく

API
Application Programming Interface
「アプリケーション、ソフトウェア」と「プラグラム」をつなぐもの

JavascriptAPIを作る」とはどういうことなのかなぁと引っかかりましたが、先のAjaxの参考ページにもあったように、Ajaxの機能を支えるXMLHttpRequestDOMAPIということなので、同じようなものを作ろうとしていたのだろうと考えました。
インターフェースなのでJSと外との窓口を増やす、といったイメージでしょうか。

モジュールAPI
CommonJSで作られたAPIのうちの1つ。モジュールを使う。

モジュール
ただのファイル。1つのスクリプトは1つのモジュール。
exportとimportを使用して機能をやり取り、あるモジュールの関数を別のモジュールから呼び出したりすることができる。
例)変数をexportして、別ファイルでimport(require)して使うことができる

Javascriptの課題

名前空間が一つしかない

変数や関数の命名が被ると上書きしてしまう。バグが発生しやすい。
例)あるjsファイルを3つに分けてhtmlファイルでa、b、cと順に読む

//a.js
var foo = 123;

//b.js
var foo = "foo";

//c.js
foo * 10; // NaN  ←変数fooの値は"foo"に上書きされている

let を使っても上書きされます。
const を使って同じ変数名にすると、この場合エラーになります。

サーバーではモジュールを使って解決。ブラウザでも使えるようにしたい。

Javascriptのモジュールは1ファイル単位でスコープ(“よそはよそ、うちはうち”)がかかっている。ファイル内の変数や関数は外部に影響しない 。

依存関係がある

読み込みの順番がある。
例)jQuery→jQueryUIの順で読み込まないとバグが発生する

2. Node.jsの誕生

モジュールの仕組みを持っている。
最初はCommonJSのモジュールAPIに準拠している(requireとexportをつかったもの。言い方:「CommonJS形式のモジュール」)

CommonJS(プロジェクト)は機能しなくなり、 Node.jsが独自の進化を遂げる。現在はモジュールの仕組みもCommonJSとは違うものがある。

Javascriptは複数の形式(仕様)のモジュールがある。

npmの誕生

モジュールのおかげで名前空間の問題が解決し、機能を細分化することができた。
すると、機能を他のプロジェクトでも使い回すようなる(共有)。
(他のサーバーサイド言語ではすでに実現されている)

npm誕生

npm(Node Package Manager)
Node.jsのパッケージ管理システム

パッケージ
package.jsonで記述されたファイルやディレクトリのこと。
共有したい機能をまとめた1つの単位。1ファイルの場合もあれば、ディレクトリの場合もある。

パッケージ管理システム
パッケージのバージョンを管理したり、共有するためのシステム。

はたらき

  1. リポジトリの購読
    ローカル環境にインストールしたパッケージを更新できる。パッケージを検索できる
  2. パッケージのインストール、削除
    パッケージを指定してローカルにインストールできる。削除もできる
  3. 依存関係の解決
    パッケージに必要な別なパッケージを自動的にインストールや更新することでがきる
  4. 設定管理
    設定を書くことで、1.2.3を自動で行える。毎回手動でパッケージを入れたりする必要がなくなり、チームでの環境を簡単に揃えたりすることができる

☆パッケージの依存関係を視覚化されているサイト
http://npm.anvaka.com/#/

☆npmのサイトの、パッケージのメニュー「Dependencies」では依存関係にあるパッケージが載っている。(Dev Dependenciesはまた別)

☆なるべく依存関係の少ないパッケージを選ぶと良い。

サーバーサイドJSの準備が整う

名前空間 → モジュールで解決
依存関係の問題 → npmで解決
有名企業も採用するように(UberNetflixなども!)

3. ブラウザ側でのモジュールの模索

モジュールっぽい仕組みはサーバーサイドJavascriptよりも前にあった。4パターン。

IIFE(即時実行関数式)形式

(function() {
  var foo = "foo";
})();
foo; // foo is not defined  即時関数の外ではfooは未定義

関数を使って、擬似的にプライベートな空間を作り上げている。

それだけでは不十分 。 言語仕様としてのモジュールではないので、名前空間の問題も完全に解決されていない。

AMD & Require JS誕生

AMD:モジュールの仕様(形式)
ブラウザ環境での実行を考慮し、依存関係の解決及び遅延ロードに対応した仕様

Require JS:AMDを実装しているもの

ブラウザでもモジュールが実現。依存関係も解決することができる。

AMD形式

define(["moduleA", "moduleB"], function(fnA, fnB) {
  // returnしたものがpublic(外部に出す)
  // returnしなければprivate
  return function() {};
});

☆moduleAとmoduleBにjQuery、jQueryUIを入れて開発、モジュールを作る、ということもできる。

次に欲しいのはブラウザ向けパッケージ管理システム

Bower誕生

Bower(バウアー)
クライアントサイド(ブラウザ)開発向けのパッケージ管理システム。
npmと似たようなことができる 。 ほとんどのBowerのパッケージはIIFEモジュールか、AMDモジュールを利用している。

ブラウザJavascripの落とし穴

AMD形式のモジュールは、サーバー側との互換性がない。構文がCommonJS形式と比較して冗長。メンテナンスも大変。

Bowerは、パッケージの依存関係の定義をユーザーが手動で定義する必要がある。 同一ページ内にある同じパッケージの異なるバージョンをサポートしていない 。 例)jQueryの1系と2系を同一ページで一緒に使えない

モジュールまとめ

  • IIFE形式(欠点あり)
  • AMD形式(欠点あり)
  • CommonJS形式 (Node.jsで成功)

UMD形式もある(パッケージを外部に公開するときの設定の話)

ブラウザJS、考え方を変える

CommonJS形式で書かれたものを事前にブラウザ形式に変換する
書いたコード(開発時のコード)と(ブラウザで)動くコードが違う。

事前にブラウザ向けに変換する方法

Bundle
Bundleを使うと...

  1. 開発時はCommonJSモジュールで開発
  2. モジュールの依存関係を解決して1ファイルに変換(バンドル) → jsファイルになる
  3. 2でできたファイルをscriptタグで読み込む

☆CJS(CommonJS)モジュールだけではなく、CSSや画像やいろいろなものをBundleすることができる。

☆設定によって複数ファイルにバンドルすることができる。

Browserify(ブラウザリファイ)
CommonJS形式に書かれたものをブラウザ向けにバンドルするツール。 CJS形式モジュールをバンドルする。

Browserifyを使うと、ブラウザでもNode.js同様requireを使うコードが使用できる
CommonJS形式のモジュールが使えるようになる。

npmのパッケージがブラウザ向けに移植される

ブラウザでもnpmが主流に!

もともとnpmはCommonJS形式で書かれたパッケージが多く、ブラウザでは使えなかったが、Browserifyでブラウザ向けに変換できることで、ブラウザでもnpmが使われるようになった。

webpack
新たなバンドルツール(「モジュールバンドラー」と呼ばれる)。
Browserifyよりも高機能(chunk(チャンク)という単位で区切ることで最初のロード時間を短縮できる)。
主にJavascript向けだが、対応するローダーがあればHMTML、CSS、画像などのフロントエンドのアセット("もの")もバンドルすることができる。

☆バンドル前のファイルはブラウザで読み込めない拡張子のものがある(.sass、.cjs、.hbs)

☆バンドル前のファイルは依存関係にあるが、バンドル後のファイルは依存関係がない

ES Modules(ESM)の誕生

言語仕様としてのモジュールが欲しい。
今まで出てきたモジュールは、自分たちでどうにかして作ったモジュールっぽい仕組み(独自仕様)だった。

CJSではrequireを使っていたところ、ES Modulesではimport構文を使う(ES2015)

webpackがES Modulesに対応(ネイティブサポート)

ES Modulesはまだほとんどのブラウザでサポートされていなかった。モジュールバンドラーはまだ必要。
でもES Modulesで書きたい。

☆「ネイティブサポート」とは、webpackはローダーがなくてもES Modulesを読み込めるようになった、ということ

☆後に「Parcel(パーセル)」というモジュールバンドラーも出てくるが"webpack1強"に変わりはない

☆現在のES Modulesサポート状況
webpackを通さなくても、IE以外のモダンブラウザとNode.jsのVersion12系以上では標準で使用可能

Compile
Compileを使うと...

  1. 開発時はブラウザでは動かないけど、開発に便利な機能を使ってコードが書ける
  2. 書いたコードをブラウザで動くように変換する(コンパイル
  3. 変換したコードをscriptタグで読み込む

バンドルは依存関係の解決に焦点を当てていたが、コンパイルは純粋に便利な機能をJSに変換する。

ES2015のたくさんの仕様

モジュール、let、const、class、Promise、アロー関数、分割代入、スプレット構文、テンプレート文字列などなど。
IEではすぐには使えないが、コンパイルで解決!

Babel(6to5 ←最初の名称)誕生

Babel
ES2015などで書かれたコードを従来の環境でも動くように古いJavascriptに変換するコンパイラ

☆似た言葉で「トランスパイラ」があるが、Babelのサイトには「コンパイラ」とある。

便利なパッケージが流行る

パッケージ

  • React(.jsx)
  • Vue(.vue)
  • TypeScript(.ts)

これらはコンパイルしてjsファイルにして使う。

パラダイムシフトが起こった

事前に変換というパラダイムシフト(考え方が大きく変わること)が起こり、現在は段々とjQueryが使われなくなっってきている。

最後に

後半駆け足になってしまいましたが、字が多すぎ。図を入れたかった...。

ここまでまとめると、モジュールの進化がすごいことが分かりました。

モジュールとパッケージの関係も、モジュール(機能)がセットになったものがパッケージかな、と少し分かりました。

といっても、未だ「ブラウザでパッケージを使う」機会に遭遇していないので、ピンときていません。
Node.js同様、コマンドを叩いたりするのでしょうか。

早くReactが分かるようになりたい...とじりじりしていますが、 少しずつ前へ進みたいと思います!