pjax1

18
Pja x Rubyist 九九 九九九 Rubyist 九九 2011 九 11 九九九 2011 九 11 九 26 九

Upload: shigeichiro-yamasaki

Post on 28-May-2015

1.060 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Pjax1

PjaxRubyist 九州山崎重一郎

Rubyist 九州 2011 年 11 月例会2011 年 11 月 26 日

Page 2: Pjax1

Web アプリっていちいちページ遷移して使いにくい反応が悪いそもそも、サーバ側でユーザの操作に対するアクションを処

理したり、ビューを生成したりする必要があるのか?

プラウザ

サーバ

アクション

ビュー生成データとビュー

HTML

Page 3: Pjax1

Web アプリってブラウザ側でやれることはブラウザ側でやれば?ひとつのアプリの中でページ遷移って必要?ブラウザ内で、 DOM 要素だけ処理すればいいんじゃない?必要なデータだけ JSON とかでサーバからもらえばいいじゃん。

プラウザ サーバ

アクション

ビュー生成

データのみJSON 等

Page 4: Pjax1

じゃあ Ajax なの?

リソースにちゃんとした URL がついてないとブックマークできない、検索エンジンにひっかからないというか、そもそもそのリソースを Web で共有できないじゃないか

REST の基本は重要!リソース状態の流通 (REpresentational State Transfer)

→ サーバをステートレスに保ちながら、リソースの状態は表現できる例:リソースへのアクセス権限状態( OAuth のアクセストークンなど)

ほら! やっぱり Ajax じゃだめじゃん

Page 5: Pjax1

ブラウザ側のリソースとサーバ側のリソース

Ajax 的なシステムでも同一の URL が指すのは同一のリソース直接サーバに URL でアクセスした場合 → サーバから GET

Ajax 的に同じ URL でアクセスした場合 → ブラウザ側で生成

プラウザ サーバ

アクション

ビュー生成

リソース

リソース

リソース

リソース

リソース

リソース

Page 6: Pjax1

ブラウザ側にリソース表現の実体が構成された場合

Ajax 的に DOM 要素の構成でできたリソースその場合も仮想的にサーバ側にもリソースが存在しているよう

にしたい →  バックボタン、ブックマーク、検索エンジン、 Web 共有

プラウザ サーバ

アクション

ビュー生成

リソース

リソース

リソース

リソース

リソース

リソース

Page 7: Pjax1

URL で直接的にリソースにアクセスした場合

もともとそのリソースはサーバに存在しているよ、という感じページの姿はブラウザ側で構成したものと全く同一にしたい

プラウザ サーバ

リソース

リソース

リソース

Page 8: Pjax1

Web ブラウザの基本構成(かなりいいかげんですが ... )<a href="">...</a> をクリックしたとき

Web ブラウザ

エンティティマネージャ

DOMレンダラ

クリック

表示

http GET など

history スタック

サーバLF ( ヘッダ ) CR LF ( ボディ ) CR

<h1>aaa</h1><p>...

Page 9: Pjax1

Pjax 魔法のしくみ 1jQuery で、ブラウザの機能を抑制/入替HTML5 の pushState で history スタックに履歴をプッシュ

Web ブラウザ

エンティティマネージャ

DOMレンダラ

クリック

表示

http GET などをしたつもり

history スタック

XjQuery

preventDefault()HTML5

pushState

Page 10: Pjax1

ブラウザの機能を抑制/入替えpreventDefault()

<!doctype html><html><head><meta charset="UTF-8"><title>preventDefalut() のテスト </title><script type="text/javascript" src='jquery-1.7.js'></script></head><body><h1>preventDefault() のテスト </h1><p><a id="enable"  href="http://www.cacanet.org">このリンク</a>は有効にされています。<a id="disable" href="http://www.cacanet.org">このリンク</a>は無効にされています。</p><p id="message"></p><script type="text/javascript"> $("#disable").click(function (e) {    e.preventDefault();    $("#message").html(" ほら、ページ遷移しないでしょ ?"); });</script></body></html>

Page 11: Pjax1

HTML5 の history.pushState

history.pushState(historyオブジェクト , タイトル , URL);ブラウザの閲覧履歴スタックに強引にタイトルや URL を強引にプッシュ→  とりあえずブックマークできる。

<html><head><meta charset="UTF-8"><title> 最初のページ </title><script> function ps() {history.pushState(null,null,"http://rubyist.org/");} </script> </head> <body><h1>pushSate のテスト </h1><form> <input type="button" value="URL に注目 " onclick="ps()" /></form></body></html>

Page 12: Pjax1

Pjax = jQuery の jquery.pjax.jsこれが Pjax のオリジナル

pushState + Ajax = Pjaxhttps://github.com/defunkt/jquery-pjax

デモページ: http://pjax.heroku.com/

直接 URL を入れても同じページが表示される

Page 13: Pjax1

jquery.pjax.jsリクエストヘッダに HTTP_X_PJAX  を含めるサーバ側は、 HTTP_X_PJAX のときは Ajax 的にデータだけ送る

そうでなければ、レイアウト付きの HTML を返す

Web ブラウザ

エンティティマネージャ

DOMレンダラ

クリック

表示

history スタック

XjQuery

jquery.pjax.js

HTML5pushState

サーバ

HTTP_X_PJAX

データだけ

Page 14: Pjax1

jquery.pjax.js の使用例sinatra の場合

# -*- coding: utf-8 -*- require 'sinatra'

get '/' do erb "<h1> トップページです </h1>", :layout => !env['HTTP_X_PJAX']end

get '/hello' do erb "<h1> こんにちは! <%=Time.now%></h1>", :layout => !env['HTTP_X_PJAX']end

__END__@@layout<!doctype html><html><head><title><%= @title %></title><script type="text/javascript" src="http://code.jquery.com/jquery-1.7.min.js"></script><script type="text/javascript" src="http://pjax.heroku.com/jquery.pjax.js"></script><script type="text/javascript">$("a.pjax").pjax("#main");</script></head><body><ul> <li><a href="/" class="pjax"> ホーム </a></li> <li><a href="/hello" class="pjax"> あいさつ </a></li></ul><div id="main"><%= yield %></div></body></html>

Page 15: Pjax1

サーバ側の魔法の種明かしリクエストヘッダの HTTP_X_PJAX の有無チェックとレイアウト

の抑制判定

Ajax 的に DOM 要素を更新する部分の指定( div で yield を囲む)

a タグ( pjax クラスの)に対する pjax の適用

get '/' do erb "<h1> トップページ </h1>", :layout => !env['HTTP_X_PJAX']end

<div id="main"><%= yield %></div>

<script type="text/javascript">$("a.pjax").pjax("#main");</script>

<li><a href="/" class="pjax"> ホーム </a></li> <li><a href="/hello" class="pjax"> あいさつ </a></li>

Page 16: Pjax1

Pjax は Rails3.2 から標準になる

利点は明らかだから当然今後の Web アプリケーションは基本的にページ遷移しなくな

るRails 流の MVC も見直しが必要

コントロールやビュー生成の大部分を coffeeScript でやるの?

Pjax を基本にした、すっきり新しい Web アプリフレームワークを新規設計した方がはやい

Page 17: Pjax1

でも、なぜこんなにうまくいくのか?

history に pushState を追加しただけなのに?なにか基本的な原理がありそう

Page 18: Pjax1

Rubyist の目線からの妄想history へのプッシュは、クロージャによるメモ化に似てい

る理論的なかっこいいアプローチもあるかもクロージャによるメモ化

関数の入力と出力の視点からの意味は変わらない既存の計算結果のキャッシュを使うか、関数の処理を実際に計算するか

Pjax同じ URL にアクセスしたときのページの姿は変わらないブラウザ側でページ要素のみを構成するか、サーバからページ全体を持ってくるか

Haskell の人は、「それは xx モナドだよ」とか言うかも ...