EWD 3トレーニング・コース #30
ewd-xpress アプリケーションを
モジュラー化するM/Gateway Developments Ltd.
Rob Tweed訳 : 日本ダイナシステム株式会社 嶋 芳成
GT.M 版編集 : 澤田 潔
※ 本稿オリジナルは Cache’ 向けとして編纂
2
バックエンド・モジュール
• 今まで、モジュール・ファイルは、• ~/ewd3/node_modules
に保存してきました• アプリケーション名 = モジュール・ファイル名
2016/9/8 EWD 3 トレーニング・コース #30
3
完全な Node.js モジュールにできる
• すなわち、次のようなファイルを入れて完全なモジュール・パッケージ・ディレクトリを作ります• index.js• Package.json• README.md• その他
• NPM 上に発行することもできます• NPM からインストールすることもできます
2016/9/8 EWD 3 トレーニング・コース #30
4
例えば
• demo1 アプリケーションのバックエンド・モジュール• ~/ewd3/node_modules/demo1.js を入れて
おくだけではなく• ~/ewd3/node_modules/demo1 というディ
レクトリを作り、そこに次のファイルを入れます• package.json• index.js• /lib フォルダ• オプションとして仕様書ファイルの
READme.md2016/9/8 EWD 3 トレーニング・コース #30
5
package.json• 最小限 :
{ “name”: “demo1”, “version”: “1.0.0”, “main”: “index.js”,}
2016/9/8 EWD 3 トレーニング・コース #30
6
package.json• 典型的にはもう少し :
{ “name”: “demo1”, “version”: “1.0.0”, “ description”: “demo アプリのバックエンド・メッセージ・ハンドラ” , “main”: “index.js”, “author”: “Rob Tweed”, “license”: “Apache-2.0”, “repository”: { “type”: “git”, “url”: “git+https://github.com/robtweed/demo1.git” }}
2016/9/8 EWD 3 トレーニング・コース #30
7
package.json• 典型的にはもう少し :
{ “name”: “demo1”, “version”: “1.0.0”, “ description”: “demo アプリのバックエンド・メッセージ・ハンドラ” , “main”: “index.js”, “author”: “Rob Tweed”, “license”: “Apache-2.0”, “repository”: { “type”: “git”, “url”: “git+https://github.com/robtweed/demo1.git” }}
2016/9/8 EWD 3 トレーニング・コース #30
Node.js に、メインのコード/スクリプト・ファイルがあるかを教えます
8
index.js• メインのスクリプト・ファイル• コードを入れることができます• 通常は、コードへのポインターのみ• コードは通常別のフォルダに入れます• 例えば /lib
2016/9/8 EWD 3 トレーニング・コース #30
9
index.js‘use strict’;module.export = require(‘./lib/demo1’);
• メインのコードは実際には /lib/demo1.js にあります
2016/9/8 EWD 3 トレーニング・コース #30
10
/lib/demo1.js module.exports = { init: funciton() { serviceAllowed: { testService: true }, handlers: { login: function(messageObj,session,send,finished) { // その他 }, // その他 }, } };
標準的な ewd-xpress のバックエンド・モジュール2016/9/8 EWD 3 トレーニング・コース #30
11
これで完全な Node.js / NPM モジュール
• demo1 モジュールはこれで NPM に対して発行することができます ( それが適切であればですが )
• 他の人は、次のコードでそれをインストールして使うことができるようになります• npm install demo1
2016/9/8 EWD 3 トレーニング・コース #30
12
ewd-xpress サービス
• ewd-xpress サービス・モジュールは、 NPM 上に発行することのできるモジュールとしてパッケージ化する良い候補です• それを他の人が、自分のアプリケーションで再利
用することができます
2016/9/8 EWD 3 トレーニング・コース #30
13
フロントエンドのコードをモジュラー化する
• “ フラグメント” を用いる• Browserify や WebPack のような “バンド
ラー” を用いる
2016/9/8 EWD 3 トレーニング・コース #30
14
フラグメント
• 少し旧式のアプローチになっています• React.js や Angular のような、最新のフレーム
ワークには適切ではありません
• より慣習的な開発については、アプリケーションをモジュラー化する効率的な方法になり得ます• サービスの一部にすることができます
2016/9/8 EWD 3 トレーニング・コース #30
15
フラグメント
• 概念:• まず最初の HTML ファイル ( 例えば
index.html) を読み込みます• そこには通常少しのマークアップしかありません• しかし、アプリケーションにより、必要なすべて
の JavaScript や CSS を読み込みます
• 続いて、 HTML のフラグメントが、動的に <div> やその他のタグの中に、ブラウザで生じたイベントの結果として読み込まれます• Ajax や WebSocket 経由
2016/9/8 EWD 3 トレーニング・コース #30
16
フラグメント
• フラグメントは、サービス・モジュールの一部として組み込むことができます• バックエンドのメッセージ・ハンドラーのロジッ
ク• マークアップに関係するフラグメント• NPM 上に発行可能
• 従って、ひとつのアプリケーションが、複数のサービスから、フラグメントやバックエンド・ロジックを用いることができます• 即ち、再利用可能なロジック、マークアップ/ UI
の部品
2016/9/8 EWD 3 トレーニング・コース #30
17
EWD.getFragment()• フラグメントを取り込むには、ブラウザ側の
ロジックに、次のコードを入れます EWD.getFragment(argObj, callback);
2016/9/8 EWD 3 トレーニング・コース #30
18
EWD.getFragment()• フラグメントを取り込むには、ブラウザ側の
ロジックに、次のコードを入れます• EWD.getFragment(artObj, callback);
• argObj: オブジェクトで、その内容は• name: ( 例えば : loginForm.html )
デフォルトで、同じディレクトリから index.html ファイルとして取り込む
• targetId:そのマークアップが挿入されるべきタグの id例えば <div id=“myTargetDiv”></div>
2016/9/8 EWD 3 トレーニング・コース #30
19
EWD.getFragment()• フラグメントを取り込むには、ブラウザ側の
ロジックに、次のコードを入れます• EWD.getFragment(artObj, callback);
• callback: フラグメントがブラウザに読み込まれたときに呼び出されます• オプションの引数は1つだけ : name
読み込まれたフラグメントのファイル名• フラグメントのマークアップが必要とするハンド
ラーを読み込むためにこのコールバックを利用します
例えば、ボタンをクリックしたときのハンドラ
2016/9/8 EWD 3 トレーニング・コース #30
20
例 : index.html<html> <head> <title>Fragment Demo</title> <link href=“//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css” rel=“stylesheet” /> </head> <body> <script src=“//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js”></script> <script src=“//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js”></script> <script src=“/socket.io/socket.io.js”></script> <script src=“/ewd-client.js”></script> <script src=“app2.js”></script>
<div id=“loginFormDiv”></div>
</body></html>
2016/9/8 EWD 3 トレーニング・コース #30
21
例 : app2.js$(document).ready(function() { EWD.log = true;
EWD.on(‘ewd-registered’, function() {
EWD.on(‘error’, function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on(‘socketDisconnected’, function() { toastr.info(‘You have been logged out’); setTimeout(function() { location.reload(); },1000); });
var params = { name: ‘loginForm.html’, targetId: ‘loginFormDiv’ }; EWD.getFragment(params, function(name) { toastr.info(‘flagment loaded: ‘ + JSON.stringify(name)); }); }); EWD.start(‘demo1’, $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
22
例 : index.html<html> <head> <title>Fragment Demo</title> <link href=“//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css” rel=“stylesheet” /> </head> <body> <script src=“//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js”></script> <script src=“//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js”></script> <script src=“/socket.io/socket.io.js”></script> <script src=“/ewd-client.js”></script> <script src=“app2.js”></script>
<div id=“loginFormDiv”></div>
</body></html>
2016/9/8 EWD 3 トレーニング・コース #30
var params = { name: ‘loginForm.html’, targetId: ‘loginFormDiv’};EWD.getFragment(params, function(name) { toastr.info(‘flagment loaded: ‘ + JSON.stringify(name));});
23
例 : loginForm.html<table id=“loginForm”> <tr> <td>Username: </td> <td><input type=“text” id=“username” /></td> </tr> <tr> <td>Password: </td> <td><input type=“password” id=“password” /></td> </tr> <tr> <td colspan=“2”> <button id=“loginBtn”>Login</button> </td> </tr></table>
2016/9/8 EWD 3 トレーニング・コース #30
ログイン・フォームのためのマークアップのみ
24
実行してみよう
2016/9/8 EWD 3 トレーニング・コース #30
25
フォームは何もしません
2016/9/8 EWD 3 トレーニング・コース #30
例えば、このボタンをクリックしても何もおこりません
26
編集 : app2.js var params = { name: ‘loginForm.html’, targetId: ‘loginFormDiv’ }; EWD.getFragment(params, function(name) { $(’#loginBtn’).on(’click’,function(e) { var username = $(’#username’.val(); if (username === ’’) { toastr.error(’You must enter a username’); return; } var password = $(’#password’).val(); if (password === ’’) { toastr.error(’You must enter a password’); return; } var message = { type: ’login’, params: { username: username, password: password } EWD.send(message(function(responseObj) { if (!responseObj.message.error){ $(’#loginForm’).hide(); } }); }); });
2016/9/8 EWD 3 トレーニング・コース #30
27
編集 : app2.js var params = { name: ‘loginForm.html’, targetId: ‘loginFormDiv’ }; EWD.getFragment(params, function(name) { $(’#loginBtn’).on(’click’,function(e) { var username = $(’#username’.val(); if (username === ’’) { toastr.error(’You must enter a username’); return; } var password = $(’#password’).val(); if (password === ’’) { toastr.error(’You must enter a password’); return; } var message = { type: ’login’, params: { username: username, password: password } EWD.send(message(function(responseObj) { if (!responseObj.message.error){ $(’#loginForm’).hide(); } }); }); });
2016/9/8 EWD 3 トレーニング・コース #30
Login ボタン用のクリック・ハンドラを追加しています
28
編集 : app2.js var params = { name: ‘loginForm.html’, targetId: ‘loginFormDiv’ }; EWD.getFragment(params, function(name) { $(’#loginBtn’).on(’click’,function(e) { var username = $(’#username’.val(); if (username === ’’) { toastr.error(’You must enter a username’); return; } var password = $(’#password’).val(); if (password === ’’) { toastr.error(’You must enter a password’); return; } var message = { type: ’login’, params: { username: username, password: password } EWD.send(message(function(responseObj) { if (!responseObj.message.error){ $(’#loginForm’).hide(); } }); }); });
2016/9/8 EWD 3 トレーニング・コース #30
Login ボタン用のクリック・ハンドラを追加していますクリックされると ‘ login’ という type とともに、 username と password がメッセージとして ewd-xpress のバックグラウンドに送信されます
29
これで作動します
2016/9/8 EWD 3 トレーニング・コース #30
30
これで作動します
• しかし、アプリケーションのメインの app.js ロジックの中に、フラグメントを読み込むロジックを定義しなくてはなりませんでした• loginForm フラグメントに付随するロジック
を別の場所に置くことができれば、よりモジュラー化できたことになります• 別々に維持管理できる• 再利用可能となる
2016/9/8 EWD 3 トレーニング・コース #30
31
loginForm.js を作る
• app.js と同じディレクトリ内に• または、 /www の下の独自のサブディレクトリ内
に
2016/9/8 EWD 3 トレーニング・コース #30
32
loginForm.jsvar loginForm = { loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: 'login', params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
33
例 : index.html<html> <head> <title>Fragment Demo</title> <link href=“//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css” rel=“stylesheet” /> </head> <body> <script src=“//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js”></script> <script src=“//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js”></script> <script src=“/socket.io/socket.io.js”></script> <script src=“/ewd-client.js”></script> <script src=“app2.js”></script> <script src=“loginForm.js”></script>
<div id=“loginFormDiv”></div>
</body></html>
2016/9/8 EWD 3 トレーニング・コース #30
34
例 : app2.js$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
var params = { name: 'loginForm.html', targetId: 'loginFormDiv' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
35
例 : app2.js$(document).ready(function() { EWD.log = true;
EWD.on(‘ewd-registered’, function() {
EWD.on(‘error’, function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on(‘socketDisconnected’, function() { toastr.info(‘You have been logged out’); setTimeout(function() { location.reload(); },1000); });
var params = { name: ‘loginForm.html’, targetId: ‘loginFormDiv’ }; EWD.getFragment(params, loginForm.loader); });
EWD.start(‘demo1’, $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
loginForm.jsvar loginForm = { loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: 'login', params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
36
バックエンドのコードについてはどうでしょう?
2016/9/8 EWD 3 トレーニング・コース #30
37
バックエンドのコードについてはどうでしょう?
var loginForm = { loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: 'login', params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
ログインメッセージはバックエンドに送られます。現時点では ewd-xpress は、それのハンドラーが、メインのアプリケーション・モジュール (demo1.js) 内に存在すると期待しています
そうではなくて、これをモジュラー化します ...
38
ログイン・サービスを生成するfunction checkLogin(username,password) { // 現時点ではハードコード版 if (username !== 'rob') return {error: 'Invalid username'}; if (password !== 'secret') return {error: 'Invalid password'}; return {ok: tur};}module.exports = { handlers: { login: function(messageObj,session,send,finished) { if (session.authenticated) { finished({error: 'You are already logged in!'}); return; } var username = messageObj.params.username; if (username === '') { finished({error: 'You must enter a username'}); return; } var password = messageObj.params.password; if (password === '') { finished({error: 'You must enter a password'}); return; } var status = checkLogin(username,password); if (status.ok) { session.authenticated = true; session.timeout = 3600; session.updateExpiry(); finished({ok: true}); } else { finished({error: status.error}); } } }};
2016/9/8 EWD 3 トレーニング・コース #30
node_modules/Login.js に保存します
ここには、バックエンドで、ログイン認証を処理するロジックが書かれています
39
loginForm.js を編集するvar loginForm = { loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
ログイン・メッセージには “ Login” サービスを用います。
40
demo1.js を編集する
module.exports = { servicesAllowed { Login: true }};
demo1 アプリケーションが Login サービスを用いることができるようにするための、これが最小限のモジュールである必要があります
2016/9/8 EWD 3 トレーニング・コース #30
実行してみる
• 新しいバックエンド・モジュールが確実に読み込まれるように、 ewd-xpress をリスタートしてください• 同じように稼働するはずですが、今回は
Login サービスを利用しています
2016/9/8 EWD 3 トレーニング・コース #30 41
42
さらなるモジュラー化
• loginForm.html というフラグメントは、現在 www/demo1 のディレクトリにあります• これは Login サービスのフラグメント側の
部分にするにはどうしますか?
2016/9/8 EWD 3 トレーニング・コース #30
43
Login モジュールを生成する
• 新しいフォルダを作ります
• ~/ewd3/node_modules/Login
2016/9/8 EWD 3 トレーニング・コース #30
44
Login モジュールを生成する
• ~/ewd3/node_modules/Login
2016/9/8 EWD 3 トレーニング・コース #30
package.json{ “name”: “Login”, “version”: “1.0.0”, “description”: “Modular login system”, “main”: “index.js”}
index.js‘use strict’;module.exports = require(‘.lib/Login’);
⁻ index.js⁻ package.json
45
Login モジュールを生成する
• ~/ewd3/node_modules/Login.js を、
~/ewd3/node_modules/Login/lib/login.js に移動する
2016/9/8 EWD 3 トレーニング・コース #30
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
46
Login モジュールを生成する
• ~/ewd3/www/demo1/loginForm.html を、
~/ewd3/node_modules/Login/fragments/loginForm.html に移動する
2016/9/8 EWD 3 トレーニング・コース #30
⁻ fragments⁻ loginForm.html
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
47
例 : app2.js$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
loginForm.html を Login サービス・モジュールから読み込みます
ewd-xpress は、そのフラグメントを探すとき、 Login/fragments フォルダの中を見ることになります
48
例 : app2.js$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
loginForm.html を Login サービス・モジュールから読み込みます
ewd-xpress は、そのフラグメントを探すとき、 Login/fragments フォルダの中を見ることになります
⁻ fragments⁻ loginForm.html
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
49
クライアント側の loginForm.jsvar loginForm = { loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
ログイン・メッセージには “ Login” サービスを用います。
50
loginForm.js はサービスに含めるか?
• loginForm.js は、 loginForm.html フラグメントに対応するハンドラを定義しているので、これも Login サービスの一部とするのは賢明です• しかし、ブラウザは JavaScript を Node.js
モジュールから読み込むことはできません• 直接的にはできません
•2つのアプローチがあります ...
2016/9/8 EWD 3 トレーニング・コース #30
51
Login モジュールに追加する
• ~/ewd3/www/demo1/loginForm.js を、• ~/ewd3/node_modules/Login/client/loginForm.js にコピーする
2016/9/8 EWD 3 トレーニング・コース #30
⁻ client⁻ loginForm.js
⁻ fragments⁻ loginForm.html
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
52
オプション 1• 発行し、他の人もインストール/利用できる
が、しかし• ~/ewd3/node_modules/Login/client/loginForm.js を、
• ~/ewd3/www/{ アプリケーション名 }/loginForm.js にコピーする
2016/9/8 EWD 3 トレーニング・コース #30
⁻ client⁻ loginForm.js
⁻ fragments⁻ loginForm.html
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
53
オプション 2: よりモダンなアプローチ
• 発行し、他の人もインストール/利用できる• バンドラ ( 例 Browserify または WebPack) を使う
• フロントエンドの JavaScript を Node.js を使っているかのように定義する• 即ち var loginForm = require(‘Login/client/loginForm’); とできます
• ブラウザが <script> タグを用いてロードできる単一の JavaScript に変換するためにパンドラを用いる
• しかし、 loginForm.js はモジュールとして書き換えなくてなりません• 後述 ...
2016/9/8 EWD 3 トレーニング・コース #30
⁻ client⁻ loginForm.js
⁻ fragments⁻ loginForm.html
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
54
フロントエンドのモジュラー開発
• Browserify をインストールします• cd /ewd3• npm install babelify• npm install –g browserify
2016/9/8 EWD 3 トレーニング・コース #30
55
クライアント側 JavaScript の NPM バージョン
• <script> タグを用いて読み込まれるライブラリはすべて、 Node.js モジュールとしてアクセスできる必要があります• 最近はほとんどはこのフォーマットで入手可
能です
• cd /ewd3• npm install toastr jquery socket.io-client• ewd-client はすでにモジュールとしてインス
トールされています
2016/9/8 EWD 3 トレーニング・コース #30
56
loginForm.js を編集する
• Login モジュール内の、クライアント側のスクリプト・ファイル loginForm.js は、変更する必要があります• Node.js のモジュールである必要があります
• とても単純な変更です ...
2016/9/8 EWD 3 トレーニング・コース #30
⁻ client⁻ loginForm.js
⁻ fragments⁻ loginForm.html
⁻ lib⁻ Login.js
⁻ index.js⁻ package.json
57
loginForm.js を編集するvar toastr = require(‘toastr’);var EWD;
module.exports = { init: function(ewd) { EWD = ewd; }, loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
58
loginForm.js を編集するvar toastr = require(‘toastr’);var EWD;
module.exports = { init: function(ewd) { EWD = ewd; }, loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
Node.js モジュールは、完全に自給自足していなくてはなりません
toastr と EWD はどこかから来なくてはなりません
59
loginForm.js を編集するvar toastr = require(‘toastr’);var EWD;
module.exports = { init: function(ewd) { EWD = ewd; }, loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
toastr の場合は、それを require() で呼び出すことができます
60
loginForm.js を編集するvar toastr = require(‘toastr’);var EWD;
module.exports = { init: function(ewd) { EWD = ewd; }, loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
EWD についてはもう少し複雑です
loginForm.loader は、 send() API とセッション・トークンにアクセスする必要があるので、 EWD の登録後のバージョンを利用する必要があります
従って require(‘ewd-client’) という形では、これは登録前のものなので使うことができません
61
loginForm.js を編集するvar toastr = require(‘toastr’);var EWD;
module.exports = { init: function(ewd) { EWD = ewd; }, loader: function(name) { $('#loginBtn').on('click', function(e) { var username = $('#username').val(); if (username === '') { toastr.error('You must enter a username'); return; } var password = $('#password').val(); if (password === '') { toastr.error('You must enter a password'); return; } var message = { type: ‘login’, service: ‘Login’, params: { username: username, password: password } }; EWD.send(message,function(responseObj) { if (!responseObj.message.error) { $('#loginForm').hide(); } }): }); }};
2016/9/8 EWD 3 トレーニング・コース #30
ひとつのアプローチは、 init() 関数を用いて EWD の登録後のバージョンをこのモジュールに渡せるようにすることです
これをどのように使うか、 app.js を見てください
62
app.js を編集するvar io = require('socket.io-client');var jQuery =require('jquery');window.$ = window.jQuery = jQuery;var toastr = require('toastr');var EWD =require('ewd-client').EWD;var Login = require('Login/client/loginForm');
$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
Login.init(EWD); var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
この場合 app.js は require() を用いてすべてをロードする必要があります
63
app.js を編集するvar io = require('socket.io-client');var jQuery =require('jquery');window.$ = window.jQuery = jQuery;var toastr = require('toastr');var EWD =require('ewd-client').EWD;var Login = require('Login/client/loginForm');
$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
Login.init(EWD); var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
jQuery の $ オブジェクトは、window のひとつのプロパティとしてインスタンス化される必要があります
これにより $ にはグローバルのスコープが設定されるので、他のモジュールは $ を require() で再び参照する必要はなくなります。
例えば loginForm.js の中でも $ が使われています
64
app.js を編集するvar io = require('socket.io-client');var jQuery =require('jquery');window.$ = window.jQuery = jQuery;var toastr = require('toastr');var EWD =require('ewd-client').EWD;var Login = require('Login/client/loginForm');
$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
Login.init(EWD); var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
EWD オブジェクトは、 ewd-client モジュールから読み込まれます
65
app.js を編集するvar io = require('socket.io-client');var jQuery =require('jquery');window.$ = window.jQuery = jQuery;var toastr = require('toastr');var EWD =require('ewd-client').EWD;var Login = require('Login/client/loginForm');
$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
Login.init(EWD); var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
そして、 Login サービス・モジュールから loginForm のコードを読み込みます
66
app.js を編集するvar io = require('socket.io-client');var jQuery =require('jquery');window.$ = window.jQuery = jQuery;var toastr = require('toastr');var EWD =require('ewd-client').EWD;var Login = require('Login/client/loginForm');
$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
Login.init(EWD); var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
そして、 Login サービス・モジュールから loginForm のコードを読み込みます
そして登録後の EWD オブジェクトを loginForm に渡します
67
app.js を編集するvar io = require('socket.io-client');var jQuery =require('jquery');window.$ = window.jQuery = jQuery;var toastr = require('toastr');var EWD =require('ewd-client').EWD;var Login = require('Login/client/loginForm');
$(document).ready(function() { EWD.log = true;
EWD.on('ewd-registered', function() {
EWD.on('error', function(responseObj) { toastr.error(responseObj.message.error); });
EWD.on('socketDisconnected', function() { toastr.info('You have been logged out'); setTimeout(function() { location.reload(); },1000); });
Login.init(EWD); var params = { name: 'loginForm.html', targetId: 'loginFormDiv' service: 'Login' }; EWD.getFragment(params, loginForm.loader); });
EWD.start('demo1', $, io);});
2016/9/8 EWD 3 トレーニング・コース #30
そして、 Login サービス・モジュールから loginForm のコードを読み込みます
そして登録後の EWD オブジェクトを loginForm に渡します
これで loader 関数が getFragment のコールバックとして利用できるようになり、 EWD はメッセージを送信し、応答を処理することができるようになりました
68
index.html を編集する
• CSS を読み込むための <link> タグはそのままにします• <script> タグはすべて取り除きますが、以下
は必要です• bundle.js• Browserify を用いてモジュラー化された
JavaScript を生成します
2016/9/8 EWD 3 トレーニング・コース #30
69
index.html を編集する<html> <head> <title>Demo modularised ewd-xpress application</title> <link href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" rel="stylesheet" /> </head> <body>
<script src="bundle.js"></script>
<div id="loginFormDiv"></div> </body></html>
2016/9/8 EWD 3 トレーニング・コース #30
70
では bundle ファイルを作ります
• cd /ewd3/www/demo1• browserify –t [ babelify ] app.js –o bundle.js
• エラーの報告がなければ、 demo1 のディレクトリに、 bundle.js ファイルができているはずです
2016/9/8 EWD 3 トレーニング・コース #30
71
実行してみよう
• アプリケーションは前と同じように稼働するはずです• JavaScript コンソールを見て、 bundle.js
ファイルが使われていることを確かめてください
• これでアプリケーションを完全にモジュラー化できました• ログインに関係するものはすべて、独自の Login
サービスモジュールの中に定義することができました• これで、あなたのアプリケーションの中で再利用
が可能になりました2016/9/8 EWD 3 トレーニング・コース #30
72
バンドリング : 注意点
• フロントエンドの JavaScript を何か変更した場合には、そのアプリケーションのコードや、そのモジュールを使うすべてのアプリケーションで Browserfy を再実行する必要があります• Browserify の代替として WebPack もあり
ます• こちらの方が良いという人もいるかもしれません
• bundle.js ファイルを最小化したいかもしれません• 例えば minify があります
2016/9/8 EWD 3 トレーニング・コース #30
73
自動化
• このトレーニング・コースの範囲外になりますが、今のトレンドは、このアプリケーション構築の自動化です• あるファイルが変更されると、それが引き金とな
り再構築をします• ファイルを bundle し、• 最小化し、• ユニット・テストし、• Git のリポジトリを更新する
• 例えば、 Gulp のよようなツールを用います
2016/9/8 EWD 3 トレーニング・コース #30