アイソモーフィックJavaScript(Isomorphic JavaScript)とは、クライアントとサーバで同じJSコードを共有して実行できるようにしようという概念。*1
この本ではリクエスト/レスポンスの古典的なWebアプリケーションから始まって、AJAX・SPAそしてIsomorphicとWebアプリケーションアーキテクチャの歴史を追って説明してくれている。それも単に歴史を辿るのではなく、当時なにが問題とされて、それをどう解決しようとしたかという背景がわかりやすく解説されているのが特に良かった。
ただ最後の方でReactやAngularJS、Angular2を用いた事例が紹介されているが、今となっては少し古い話になっていたり、コードも断片的にしか載っていないためすぐ業務に役立つというものではないという印象。ここも実際に企業であった問題をどうやって解決していったかというアプローチの部分に焦点が当たっている。
その他の雑感はこんな感じ。
- JeremyやDouglas、Brendan EichといったJS界の重要人物を紹介してくれている
- 薄い本でサクッと読める
- 説明のしやすさからbrowserfiy + gulpを扱っている
- webpack + npm-scriptsのほうが最近では主流だと思われる
- Angular Universal開発の裏側がちょっと書かれていておもしろい
アイソモーフィックJavaScriptという新しいアーキテクテャの背後にある概念をしっかり学ぶのにお薦め。
読書メモ
まえがき
MicrosoftがXMLHttpRequestを考案
=> Ajaxの誕生・Webをアプリケーションプラットフォームへと進化
=> クライアント側にアーキテクチャがないためAjaxによる技術的負債が蓄積
=> DOMをラップするためのjQueryに代わるものとして、Jeremy AshkenasがBackboneを開発
=> ロジックとデータの取得が分離される
=> 初期ロードやSEOなどのSPAによる弊害が起こるように
- メリット
- SPAでやっている
#!
フラグメントを使わなくてもSEO対策が可能
- History APIに対応していれば、クライアント側のみで描画可能
- 最初の読み込みはサーバー側で描画することで初期ロードが高速化
- 同じ処理のコードを2つの言語で書かなくてすむ・責務の境界が明確に
=> 「SEO対策」・「初期ページの読み込み最適化」・「ページ遷移の最適化」の3点を満たしている
=> SEO対策やパフォーマンスが重要ではない場合では、オススメしない
- クライアントとサーバーがどのレイヤーまで共有するか問題
- アイソモーフィックJS: サーバーとクライアントの双方
- ユニバーサルJS: ネイティブや埋め込みなどでも
- Node.jsのrequire()はブラウザでは使えない
- ブラウザ向けにコンパイルするビルドツールが必要
- Browserify / Webpack
- 環境に固有の処理にはシムを用意
- あわせて読んだ
4章 サーバー側での描画を超えて
- リアルタイムでアイソモーフィックなフレームワーク
- Meteor.js
- 6月のOkachi.jsでMeteor教えてもらった
- Asana’s Luna framework
5章 アプリケーションの基盤
hapiっていうフレームワーク知らなかった
If you would like to create microservices nodes and getting tired of using express, you need to know more about hapi
.
npm install hapi --save
- npm v5からはsaveオプションはデフォルトに
- constは変化しない値という意味ではない
- gulpとかのタスクランナーを導入するよりもnpm-scriptsでやるほうが好き
- 5章のgulpfileをnpm-scriptsに書き直すとこうかな
var gulp = require('gulp');
var babel = require('gulp-babel');
var nodemon = require('gulp-nodemon');
var sequence = require('run-sequence');
gulp.task('compile', function () {
return gulp.src('src/**/*.js')
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('dist'))
});
gulp.task('watch', function () {
gulp.watch('src/**/*.js', ['compile']);
});
gulp.task('start', function () {
nodemon({
watch: 'dist',
script: 'dist/index.js',
ext: 'js',
env: { 'NODE_ENV': 'development' }
});
});
gulp.task('default', function (callback) {
sequence(['compile', 'watch'], 'start', callback);
});
"scripts": {
"compile": "babel src -d dist --presets es2015",
"serve": "nodemon --watch dist dist/index.js",
"start": "npm run watch & npm run serve",
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "watch 'npm run compile' src"
},
=> 「SEO対策」・「初期ページの読み込み最適化」・「ページ遷移の最適化」の3点を満たしている
=> SEO対策やパフォーマンスが重要ではない場合では、オススメしない
6章 HTMLドキュメントを公開する
- Nunjucksは聞いたことあったけど初めて使った
gulp.dest()
コマンドはcpx
で代用するとこうかな
"scripts": {
"compile": "babel src -d dist --presets es2015 & cpx src/**/*.html dist",
"serve": "nodemon --watch dist dist/index.js",
"start": "npm run watch & npm run serve",
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "watch 'npm run compile' src"
},
7章 アプリケーションの設計
- 度を越す抽象化は禁物
- 再利用可能なApplicationクラスの作成
- hapiのままだとクライアントでは使えない
- hapiへの依存が強い
- BaseとなるContolloerを定義
- 各routingに対応するContollerはBaseを継承して定義
8章 アプリケーションをクライアント側に転送する
- クライアント向けにバンドル化
- Browserifyかー懐かしい
- Browserifyをgulpで通すためにvinyl-source-stream
- vinyl: npm全般で使用しているオブジェクト
gulp.task('bundle', function () {
const b = browserify({
entities: 'src/index.js',
debug: true
}).transform('babelify', {presets: ['es2015']});
return b.bundle()
.pipe(source('build/application.js'))
.pipe(gulp.dest('dist'));
});
9章 よく使われる抽象化
- 抽象化は用法用量を守って正しくお使いください
- 具体例
- サーバー側での処理の続きをクライアント側でシームレスに行う機能
- サーバー側でデータをシリアライズ
- クライアント側でルーティングハンドラのコントローラーをインスタンス化
- クライアント側で1.のデータをデシリアライズ化
- クライアント側でDOMのイベントハンドラと関連付け
=> 『リハイドレート』
11章 ここまでの振り返り
- 基礎的な概念をネイティブなAPI中心に説明してきた
- Webの変化は早いけど、Isomorphic JavaScriptの概念はそうそう変わらない
14章 Brisket
https://github.com/bloomberg/brisket
16章 アイソモーフィックJavaScriptとユニバーサルJavaScript