Service Workerとの戦い

実装編
ヤフー株式会社
マーケティングソリューションカンパニー

開発本部エクスペリエンスデザイン部テクニカルデザイン

柴田 和祈
photo by halfrain
2015.3.10 SCRIPTY#3 ∼フロントエンド紳士・淑女のための勉強会∼
柴田 和祈
@shibe97
Web Designer / Frontend Engineer
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Service Workerとは
‣ ブラウザのバックグラウンドで動作する
JavaScript環境
‣ フォアグラウンドとは別スレッド
‣ サーバへのリクエストをキャッチできる
‣ 動かせる環境は今のところ限られている

https://jakearchibald.github.io/isserviceworkerready/
‣ localhost、またはhttps環境でのみ動く
画面 サーバ画面 サーバ
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
画面 サーバ画面 サーバ
Service
Worker
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
画面 サーバ
Service
Worker
クライアントサイド サーバサイド
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
今日やりたいこと
‣ データのキャッシュ
‣ Ajax通信のモックテスト
‣ 値のバリデーションチェック
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
今日やりたいこと
‣ データのキャッシュ
‣ Ajax通信のモックテスト
‣ 値のバリデーションチェック
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Ajax通信のモックテストの流れ
1. Service Workerの登録
2. Ajax通信
3. Service Workerがリクエストをキャッチ
4. ダミーJsonを返す
5. 画面に表示
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Ajax通信のモックテスト
1. Service Workerの登録
navigator.serviceWorker.register(	
  
	
   "service-­‐worker.js",	
  
	
   {scope:	
  "./"}	
  
)	
  
.then(function(result){	
  
	
   //	
  登録成功	
  
})	
  
.catch(function(result){	
  
	
   //	
  登録失敗	
  
});
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
つまずきポイント#1
root
├── index.html
└── sw
└── test.json
test.jsonへのリクエストをキャッチしたいから

スコープを「/sw」にする
test.jsonへのリクエストをindex.htmlから行なうので

スコープを「/」にする
○
【スコープ】
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
つまずきポイント#1
‣ Service Workerはスコープ内からのリクエストを
キャッチする
‣ リクエスト先がスコープ内にあるかどうかは関係ない
‣ スコープを指定していない場合はルート以下

すべてがスコープとなる
【スコープ】
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Ajax通信のモックテスト
$.ajax({	
  
	
   url:	
  "/success",	
  
	
   dataType:	
  "json"	
  
})	
  
.done(function(result){	
  
	
   //	
  成功処理	
  
})	
  
.fail(function(result){	
  
	
   //	
  失敗処理	
  
});
2. Ajax通信
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Ajax通信のモックテスト
self.onfetch	
  =	
  function(event){	
  
	
   var	
  requestURL	
  =	
  new	
  URL(event.request.url);	
  
	
   if(requestURL.pathname.match("/success")){	
  
!
	
   	
   //	
  success以外のリクエストは素通りさせる	
  
!
	
   }	
  
};
3. Service Workerがリクエストをキャッチ
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
つまずきポイント#2
‣ リクエストのキャッチが可能な状態になるのは

ロードのタイミング
‣ ワーカーが登録されても、

リロードしなければリクエストはキャッチされない
‣ リロードすると、index.htmlのリクエストが

キャッチされ、本物のindex.htmlが取得できない
- URL判定でindex.htmlは素通りさせる必要がある
【リクエストのキャッチ】
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Ajax通信のモックテスト
var	
  result	
  =	
  [	
  
	
   {id:	
  1,	
  name:	
  "柴田",	
  mail:	
  "shibata@scripty.com"},	
  
	
   {id:	
  2,	
  name:	
  "小川",	
  mail:	
  "ogawa@scripty.com"},	
  
	
   {id:	
  3,	
  name:	
  "森本",	
  mail:	
  "morimoto@scripty.com"}	
  
];	
  
var	
  response	
  =	
  new	
  Response(JSON.stringify(result),	
  {	
  
	
   status:	
  200,	
  
	
   statusText:	
  "OK",	
  
	
   headers:	
  {	
  
	
   	
   "Content-­‐Type":	
  "application/json"	
  
	
   }	
  
});	
  
event.respondWith(response);
4. ダミーJSONを返す
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
つまずきポイント#3
‣ JSON形式で引数に渡してしまうと上手くいかない
ので、文字列に変換する
‣ ヘッダー情報を与える必要がある
‣ レスポンス処理が行なわれない場合は、予定通りの

fetchが行なわれる
【レスポンスの生成】
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Ajax通信のモックテスト
5. 画面に表示
$.ajax({	
  
	
   url:	
  "/success",	
  
	
   dataType:	
  "json"	
  
})	
  
.done(function(result){	
  
	
   //	
  成功処理	
  
})	
  
.fail(function(result){	
  
	
   //	
  失敗処理	
  
});
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
今日やりたいこと
‣ データのキャッシュ
‣ Ajax通信のモックテスト
‣ 値のバリデーションチェック
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
値のバリデーションチェックの流れ
1. Service Workerの登録
2. Ajax通信
3. Service Workerがリクエストをキャッチ
4. リクエストのパラメータをチェック
5. チェック結果を返す
6. 画面に表示
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
値のバリデーションチェック
1. Service Workerの登録
navigator.serviceWorker.register("service-­‐worker.js")	
  
.then(function(result){	
  
	
   //	
  登録成功	
  
})	
  
.catch(function(result){	
  
	
   //	
  登録失敗	
  
});
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
値のバリデーションチェック
$.ajax({	
  
	
   type:	
  "POST",	
  
	
   url:	
  "/success",	
  
	
   dataType:	
  "json",	
  
	
   data:	
  {	
  
	
   	
   name:	
  $("#input_name").val(),	
  
	
   	
   tel:	
  $("#input_tel").val()	
  
	
   }	
  
})	
  
.done(function(result){	
  
	
   //	
  成功処理	
  
})	
  
.fail(function(result){	
  
	
   //	
  失敗処理	
  
});
2. Ajax通信
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
値のバリデーションチェック
3. Service Workerがリクエストをキャッチ
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
self.onfetch	
  =	
  function(event){	
  
	
   var	
  requestURL	
  =	
  new	
  URL(event.request.url);	
  
	
   if(requestURL.pathname.match("/success")){	
  
!
	
   	
   //	
  処理	
  
!
	
   }	
  
};
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
値のバリデーションチェック
event.request.text().then(function(data){	
  
	
   var	
  jsonData	
  =	
  getConverted(data);	
  //	
  JSON形式に変換	
  
	
   var	
  errors	
  =	
  validate(jsonData);	
  //	
  バリデーション	
  
});	
  
!
var	
  validate	
  =	
  function(data){	
  
	
   var	
  errors	
  =	
  [];	
  
	
   if(data.name	
  ===	
  ""){	
  
	
   	
   errors.push("name:empty");	
  
	
   }	
  
	
   if(data.tel.match(/[^0-­‐9]+/)){	
  
	
   	
   errors.push("tel:notNumber");	
  
	
   }	
  
	
   //	
  等々	
  
	
  	
  	
  return	
  errors;	
  
};
4. リクエストのパラメータをチェック
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
つまずきポイント#4
‣ リクエストパラメータは event.request.text()
で取得する
‣ console.log で event の中身を見ても

パラメータが入っていない
【パラメータのチェック】
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
値のバリデーションチェック
5. チェック結果を返す
event.respondWith(	
  
	
   event.request.text().then(function(data){	
  
	
   	
   var	
  jsonData	
  =	
  getConverted(data);	
  
	
   	
   var	
  errors	
  =	
  validate(jsonData);	
  
	
   	
   return	
  new	
  Response(JSON.stringify(errors),	
  {	
  
	
   	
   	
   status:	
  200,	
  
	
   	
   	
   statusText:	
  "OK",	
  
	
   	
   	
   headers:	
  {	
  
	
   	
   	
   	
   "Content-­‐Type":	
  "application/json"	
  
	
   	
   	
   }	
  
	
   	
   });	
  
	
   })	
  
)	
  
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
つまずきポイント#5
‣ Promise後に respondWith() すると動かない
‣ respondWith() してからPromise処理
‣ respondWith() はonfetch内で1度しか使えない
【Promise処理とレスポンス作成】
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
まとめ
‣ スコープの指定には注意が必要

スコープ内では特定のリクエストのみキャッチさせる
‣ リクエストのキャッチが可能な状態になるのは

ロードのタイミング
‣ リクエストパラメータは event.request.text() 

で取得する
‣ Promise処理は respondWith() の後で行なう
Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
参考資料
‣ Google Chromeサンプル

https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker
‣ Service Workerの紹介

http://www.html5rocks.com/ja/tutorials/service-worker/introduction/
‣ Service Workerを使ったXHRのモックテスト

http://jxck.hatenablog.com/entry/response-injection
‣ スペシャルアドバイザー @nhiroki_氏
!

Service Workerとの戦い ~ 実装編 ~ #scripty03

  • 1.
  • 2.
    柴田 和祈 @shibe97 Web Designer/ Frontend Engineer Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 3.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Service Workerとは ‣ ブラウザのバックグラウンドで動作する JavaScript環境 ‣ フォアグラウンドとは別スレッド ‣ サーバへのリクエストをキャッチできる ‣ 動かせる環境は今のところ限られている
 https://jakearchibald.github.io/isserviceworkerready/ ‣ localhost、またはhttps環境でのみ動く
  • 4.
    画面 サーバ画面 サーバ Copyright(C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 5.
    画面 サーバ画面 サーバ Service Worker Copyright(C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 6.
    画面 サーバ Service Worker クライアントサイド サーバサイド Copyright(C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 7.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 今日やりたいこと ‣ データのキャッシュ ‣ Ajax通信のモックテスト ‣ 値のバリデーションチェック
  • 8.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 今日やりたいこと ‣ データのキャッシュ ‣ Ajax通信のモックテスト ‣ 値のバリデーションチェック
  • 9.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Ajax通信のモックテストの流れ 1. Service Workerの登録 2. Ajax通信 3. Service Workerがリクエストをキャッチ 4. ダミーJsonを返す 5. 画面に表示
  • 10.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Ajax通信のモックテスト 1. Service Workerの登録 navigator.serviceWorker.register(     "service-­‐worker.js",     {scope:  "./"}   )   .then(function(result){     //  登録成功   })   .catch(function(result){     //  登録失敗   }); Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 11.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 つまずきポイント#1 root ├── index.html └── sw └── test.json test.jsonへのリクエストをキャッチしたいから
 スコープを「/sw」にする test.jsonへのリクエストをindex.htmlから行なうので
 スコープを「/」にする ○ 【スコープ】
  • 12.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 つまずきポイント#1 ‣ Service Workerはスコープ内からのリクエストを キャッチする ‣ リクエスト先がスコープ内にあるかどうかは関係ない ‣ スコープを指定していない場合はルート以下
 すべてがスコープとなる 【スコープ】
  • 13.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Ajax通信のモックテスト $.ajax({     url:  "/success",     dataType:  "json"   })   .done(function(result){     //  成功処理   })   .fail(function(result){     //  失敗処理   }); 2. Ajax通信 Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 14.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Ajax通信のモックテスト self.onfetch  =  function(event){     var  requestURL  =  new  URL(event.request.url);     if(requestURL.pathname.match("/success")){   !     //  success以外のリクエストは素通りさせる   !   }   }; 3. Service Workerがリクエストをキャッチ Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 15.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 つまずきポイント#2 ‣ リクエストのキャッチが可能な状態になるのは
 ロードのタイミング ‣ ワーカーが登録されても、
 リロードしなければリクエストはキャッチされない ‣ リロードすると、index.htmlのリクエストが
 キャッチされ、本物のindex.htmlが取得できない - URL判定でindex.htmlは素通りさせる必要がある 【リクエストのキャッチ】
  • 16.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Ajax通信のモックテスト var  result  =  [     {id:  1,  name:  "柴田",  mail:  "[email protected]"},     {id:  2,  name:  "小川",  mail:  "[email protected]"},     {id:  3,  name:  "森本",  mail:  "[email protected]"}   ];   var  response  =  new  Response(JSON.stringify(result),  {     status:  200,     statusText:  "OK",     headers:  {       "Content-­‐Type":  "application/json"     }   });   event.respondWith(response); 4. ダミーJSONを返す Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 17.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 つまずきポイント#3 ‣ JSON形式で引数に渡してしまうと上手くいかない ので、文字列に変換する ‣ ヘッダー情報を与える必要がある ‣ レスポンス処理が行なわれない場合は、予定通りの
 fetchが行なわれる 【レスポンスの生成】
  • 18.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 Ajax通信のモックテスト 5. 画面に表示 $.ajax({     url:  "/success",     dataType:  "json"   })   .done(function(result){     //  成功処理   })   .fail(function(result){     //  失敗処理   }); Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 19.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 今日やりたいこと ‣ データのキャッシュ ‣ Ajax通信のモックテスト ‣ 値のバリデーションチェック
  • 20.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 値のバリデーションチェックの流れ 1. Service Workerの登録 2. Ajax通信 3. Service Workerがリクエストをキャッチ 4. リクエストのパラメータをチェック 5. チェック結果を返す 6. 画面に表示
  • 21.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 値のバリデーションチェック 1. Service Workerの登録 navigator.serviceWorker.register("service-­‐worker.js")   .then(function(result){     //  登録成功   })   .catch(function(result){     //  登録失敗   }); Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 22.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 値のバリデーションチェック $.ajax({     type:  "POST",     url:  "/success",     dataType:  "json",     data:  {       name:  $("#input_name").val(),       tel:  $("#input_tel").val()     }   })   .done(function(result){     //  成功処理   })   .fail(function(result){     //  失敗処理   }); 2. Ajax通信 Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 23.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 値のバリデーションチェック 3. Service Workerがリクエストをキャッチ Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 self.onfetch  =  function(event){     var  requestURL  =  new  URL(event.request.url);     if(requestURL.pathname.match("/success")){   !     //  処理   !   }   };
  • 24.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 値のバリデーションチェック event.request.text().then(function(data){     var  jsonData  =  getConverted(data);  //  JSON形式に変換     var  errors  =  validate(jsonData);  //  バリデーション   });   ! var  validate  =  function(data){     var  errors  =  [];     if(data.name  ===  ""){       errors.push("name:empty");     }     if(data.tel.match(/[^0-­‐9]+/)){       errors.push("tel:notNumber");     }     //  等々        return  errors;   }; 4. リクエストのパラメータをチェック Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 25.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 つまずきポイント#4 ‣ リクエストパラメータは event.request.text() で取得する ‣ console.log で event の中身を見ても
 パラメータが入っていない 【パラメータのチェック】
  • 26.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 値のバリデーションチェック 5. チェック結果を返す event.respondWith(     event.request.text().then(function(data){       var  jsonData  =  getConverted(data);       var  errors  =  validate(jsonData);       return  new  Response(JSON.stringify(errors),  {         status:  200,         statusText:  "OK",         headers:  {           "Content-­‐Type":  "application/json"         }       });     })   )   Copyright (C) 2015 Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止
  • 27.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 つまずきポイント#5 ‣ Promise後に respondWith() すると動かない ‣ respondWith() してからPromise処理 ‣ respondWith() はonfetch内で1度しか使えない 【Promise処理とレスポンス作成】
  • 28.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 まとめ ‣ スコープの指定には注意が必要
 スコープ内では特定のリクエストのみキャッチさせる ‣ リクエストのキャッチが可能な状態になるのは
 ロードのタイミング ‣ リクエストパラメータは event.request.text() 
 で取得する ‣ Promise処理は respondWith() の後で行なう
  • 29.
    Copyright (C) 2015Yahoo Japan Corporation. All Rights Reserved. 無断引用・転載禁止 参考資料 ‣ Google Chromeサンプル
 https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker ‣ Service Workerの紹介
 http://www.html5rocks.com/ja/tutorials/service-worker/introduction/ ‣ Service Workerを使ったXHRのモックテスト
 http://jxck.hatenablog.com/entry/response-injection ‣ スペシャルアドバイザー @nhiroki_氏 !