massa142's blog

くり返す このポリリズム

「アイソモーフィックJavaScript」を読んだ

アイソモーフィックJavaScript

アイソモーフィックJavaScript

アイソモーフィック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という新しいアーキテクテャの背後にある概念をしっかり学ぶのにお薦め。

読書メモ

まえがき

MicrosoftXMLHttpRequestを考案
=> Ajaxの誕生・Webをアプリケーションプラットフォームへと進化
=> クライアント側にアーキテクチャがないためAjaxによる技術的負債が蓄積
=> DOMをラップするためのjQueryに代わるものとして、Jeremy AshkenasがBackboneを開発
=> ロジックとデータの取得が分離される
=> 初期ロードやSEOなどのSPAによる弊害が起こるように

1章 アイソモーフィックJavaScriptが求められる理由

  • メリット
    • SPAでやっている#!フラグメントを使わなくてもSEO対策が可能
    • History APIに対応していれば、クライアント側のみで描画可能
    • 最初の読み込みはサーバー側で描画することで初期ロードが高速化
    • 同じ処理のコードを2つの言語で書かなくてすむ・責務の境界が明確に

=> 「SEO対策」・「初期ページの読み込み最適化」・「ページ遷移の最適化」の3点を満たしている

=> SEO対策やパフォーマンスが重要ではない場合では、オススメしない

2章 アイソモーフィックJavaScriptのスペクトル

  • クライアントとサーバーがどのレイヤーまで共有するか問題

3章 アイソモーフィックJavaScriptのカテゴリー

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'));
});
  • HistoryAPI
    • サーバー側でいうルーティングの機能を持たせる

9章 よく使われる抽象化

  • 抽象化は用法用量を守って正しくお使いください
  • 具体例
    • cookieの読み書き
    • リクエストのリダイレクト

10章 シリアライズ、デシリアライズ、関連付け

=> 『リハイドレート』

11章 ここまでの振り返り

  • 基礎的な概念をネイティブなAPI中心に説明してきた
  • Webの変化は早いけど、Isomorphic JavaScriptの概念はそうそう変わらない

14章 Brisket

https://github.com/bloomberg/brisket

16章 アイソモーフィックJavaScriptとユニバーサルJavaScript

*1:最近ではより広義なUniversal JavaScriptという言葉のほうがよく使われてるように思えるが、このニュアンスの違いなども本書で説明されている