jQueryの先に行こう!
最先端のWeb開発トレンドを学ぶ
2016/09/24
株式会社オープンウェブ・テクノロジー
TechFeed統括
白石 俊平
自己紹介
• 白石俊平
– shumpei.shiraishi
• 株式会社オープンウェブ・
テクノロジーCEO
– TechFeedというサービスを
やっています
• HTML5 Experts.jp編集長
• html5jファウンダー
TechFeed
• http://techfeed.io
• ITエンジニア向けキュレー
ションサービス
– Web&モバイルアプリ
• エンジニアの興味・関心に
沿った情報を、世界中から
日々自動的に収集し、整理
して届ける。
• 2016/7/26正式リリース
HTML5 Experts.jp
• http://html5experts.jp
• 2012年、NTTコミュニ
ケーションズと創立
• 「コミュニティとメディ
アの融合」を旗印に、日
本のWebエキスパートが
一同に会した場を作った。
html5j
• http://html5j.org
• 2009年、Google社と共同創立
• 2014年7月まで白石がコミュニティリーダー
を務める
– 現リーダーは弊社取締役の吉川徹
• 多くのサブコミュニティ(部活)創立にも関
与
• ML登録者数7,000名弱(2016年9月時点)
• 主な実績
– HTML5とか勉強会(月例イベント)
– HTML5 Conference(1,000名超が集まる大規模カ
ンファレンス)
– HTML5 Japan Cup(プログラミングコンテスト)
アジェンダ
• なぜWeb開発の最新トレンドを学ぶ必要
があるのか?
• 最新Web開発トレンドを学ぶ
なぜWeb開発の最新トレンドを学
ぶ必要があるのか?
なぜWeb開発の最新トレンドを
学ぶ必要があるのか?
• 2つの疑問
– Webはいまだに重要なのか?
– jQueryでいいではないか?
疑問その1:
Webはいまだに重要なのか?
• 「Webは死んだ」?
• Webは遅い!
• スマートフォンの利用
時間は8割がアプリ(※)
※http://www.netratings.co.jp/news_release/2015/11/Newsrelease20151125.html
Webの利点
(と呼ばれているもの)
• Secure (安全)
• Linkable (リンク可能)
• Indexable (インデックス可能)
• Composable (再構成可能)
• Ephemeral (一時的な利用)
出典: https://html5experts.jp/agektmr/20527/
Webはアプリを補うもの、
でOK?
YES!
…NO!!
Web is Application Platform itself!
昔HTML5の仕様書には
こんなことが書いてあってな
APIはそれなりに揃ったものの、
あまり使われなかったりするが、、
まだまだイケるよ!
Webアプリ!
…って想いを体現したのが
プログレッシブ・ウェブアプリ(後述)
だと個人的には思っております。
疑問その2:
jQueryでいいではないか?
はいと言わざるをえない
TechFeed内部の変遷
2016/7/26 正式版
• モバイル/SPA
• バックエンド:
• Node.js 4 (ES6相当)
• フロントエンド:
• Angular2 + Ionic2
• TypeScript
2015/12/1 プレビュー版
• メール/Web
• バックエンド:
• Node.js 0.12 (ES5相当)
• フロントエンド:
• jQuery + Bootstrap
• ES5 (後半は6も)
まさに
「jQueryから、その先へ。」
この経験を踏まえますと
Webアプリ
(SPA: Single Page Application)を
jQueryで作るのは、
相当しんどうございます。
ただ、SPAを作るのでなければ、jQueryはいまだに
とっても素晴らしい。
SPAなんて、無理して
作る必要あるか?
ある…かも知れない。
お客さんや上司がそれを望んできたとしたら?(恐怖)
↑そうなるよう仕向けようとしてる奴らがいる。
Web開発の最新トレンドを学ぶ
なので、
2016年現在、Web開発の
最新トレンドを学ぶための3つの
キーワード
• プログレッシブ・ウェブアプリ
• コンポーネント指向フレームワーク
• ECMAScript.next
プログレッシブ・ウェブアプリ
なんだかんだ言って
今のところはWebも大事
• とはいえどっちも作ってメンテし続ける
のはしんどい
Web Mobile
想像してみよう
1. (モバイル)Webサイトにア
クセスする
2. 何度目かのアクセスで、
「ホームスクリーンに入れと
く?」と聞かれる
3. ホームスクリーンから起動す
ると、ネイティブアプリと同
様にアドレスバーなしで表示
される。
4. そのアプリ経由で、プッシュ
通知が届くようになる
5. そのアプリは高速で起動し、
オフラインでも動作する
このスライドの画像はこちらのページより引用:
https://googledevjp.blogspot.jp/2015/04/service-worker-google-developers-summit.html
想像してみよう
1. (モバイル)Webサイトにア
クセスする
2. 何度目かのアクセスで、
「ホームスクリーンに入れと
く?」と聞かれる
3. ホームスクリーンから起動す
ると、ネイティブアプリと同
様にアドレスバーなしで表示
される。
4. そのアプリ経由で、プッシュ
通知が届くようになる
5. そのアプリは高速で起動し、
オフラインでも動作する
このスライドの画像はこちらのページより引用:
https://googledevjp.blogspot.jp/2015/04/service-worker-google-developers-summit.html
これを実現するのが
プログレッシブ・ウェブアプリ
「プログレッシブ」=
「徐々に、だんだんと」
既存のWebサイトを「だんだんと」Webア
プリ化していくこともできる。
– PWA化は実は簡単
– HTTPSであることは前提
インストールバナーが出るように
するには
• manifest.jsonを書き、linkタグに指定する
• バナーの出現タイミングはブラウザが自動で決定する
{
"name": "Weather",
"short_name": "Weather",
"icons": [{
"src": "images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
}],
"start_url": "/index.html",
"display": "standalone"
}
<link rel="manifest" href="/manifest.json">
プッシュ通知が出るようにする
• ServiceWorkerを使用する
– ServiceWorkerはバックグラウンドで動作し続ける
JavaScriptコードを定義できる仕組み
• 既存のWebサイトにそれほど影響を与えずに組み
込める
self.addEventListener('push', function(event) {
const data = event.data.json();
const notification = {
body: data.message,
data: {url: data.url}
};
event.waitUntil(self.registration
.showNotification('TechFeed', notification));
});
高速起動&オフライン動作
• ServiceWorkerのCache APIや、Indexed
Database API(ブラウザ組み込みのデータ
ベースAPI)を使用する。
var filesToCache = [...];
self.addEventListener('install', function(e) {
e.waitUntil(
caches.open('TechFeed').then(function(cache) {
return cache.addAll(filesToCache);
})
);
});
想像してみよう
1. (モバイル)Webサイトにア
クセスする
2. 何度目かのアクセスで、
「ホームスクリーンに入れと
く?」と聞かれる
3. ホームスクリーンから起動す
ると、ネイティブアプリと同
様にアドレスバーなしで表示
される。
4. そのアプリ経由で、プッシュ
通知が届くようになる
5. そのアプリは高速で起動し、
オフラインでも動作する
このスライドの画像はこちらのページより引用:
https://googledevjp.blogspot.jp/2015/04/service-worker-google-developers-summit.html
これを実現するのが
プログレッシブ・ウェブアプリ
SPAとは
• 単一ページアプリケーション、つまり「HTMLが1
枚のアプリ」
• UI変更は、JavaScriptによるDOM操作によって実
現される
– ページ全体の書き換えが発生しないため、UXに優れ
る
SPAの開発は難しい
• 実現すべき要件が数多い
– 一貫したアーキテクチャ
– より良いパフォーマンス
– ブックマーク可能に(URLルーティング)
– SEO対策
• 開発の助けとなるフレームワーク・ライ
ブラリが必要となる
コンポーネント指向
フレームワーク
SPA開発
に必須!
JavaScriptアプリケーション
フレームワークは死屍累々
• React.js / Angular.js / Backbone.js / Vue.js
/ Mithril.js / Aurelia.js / Knockout.js /
Ember.js / Riot.js / Ractive.js / Spine.js /
Javascript MVC / Batman.js…
メジャーなJavaScript
フレームワークの変遷
• 2006年8月 jQuery 1.0 リリース
– DOM操作の容易化
– ブラウザ間の差異を吸収
• 2012年6月 AngularJS 1.0 リリース
– MVCフレームワークの決定版
– Single Page Applicationという概念が一般的に
• 2013年5月 React オープンソース化
– コンポーネント指向ライブラリ
– 良好なパフォーマンス(仮想DOM)
– サーバサイドレンダリング
• 2016年9月 Angular 2.0 リリース
– コンポーネント指向フレームワーク
– TypeScriptの採用
AngularJSとReactが二大巨頭
この両者の共通点がコンポーネント指向のフ
レームワークであること
コンポーネント指向とは
• アプリケーションをコンポーネント(部
品)という単位で分割して扱えること
コンポーネント指向がなぜ有用か
• 従来のWebページ(アプリ)は、全てがグローバルな単一空
間
– HTML (DOM)
– CSS
– JavaScript
• SPAでは、常に衝突や状態破壊の危険性がある
– CSSのIDやクラス名はその典型
– 外部ライブラリに勝手にDOMをいじられたり
– 非SPAでは、毎回ページがリフレッシュされるから問題は少な
い
コンポーネント指向がなぜ有用か
• アプリケーションをコンポーネントに分割し
て管理する
– 問題がコンポーネントに局所化される
– コンポーネント単位で再利用が可能になる
一覧の項目はいたる
ところで再利用する
なぜ今頃コンポーネント指向か?
• コンポーネント分割は、UIプログラミン
グの基本
• なぜ今頃、ようやく?
https://www.amazon.com/Adobe-Flash-Builder-4-Premium/dp/B003739DRS
http://win32easy.blogspot.jp/2011/03/dialog-controls-explained-part-1.html
なぜ今頃コンポーネント指向か?
• 基盤技術のアップデートが必要だった
– HTML/CSS…Shadow DOM(※)
– JavaScript…ECMA Script 6 Modules & Classes
• 厳密には、これらのアップデートはまだ道半
ばであり、ツールの手助けを必要とする
– Shadow DOM…Angular2は属性でエミュレート
する
– ESモジュール…モジュールバンドラーが、モ
ジュール間の関連性を考慮しつつまとめ上げる
Advanced: Shadow DOMとは?
• DOMの詳細を隠蔽し、カプセル化することのできる仕組み
• 例えば、video要素などは複数の要素から構築されているが、
詳細は隠蔽されている。
– 開発者ツールの設定で「Show user agent Shadow DOM」を有
効にすると詳細を見ることが出来る
• Chrome 53から、Shadow DOM v1が利用可能になった
ECMAScript.next
ECMAScriptとは?
• ECMAScript = JavaScriptの仕様
• この仕様に基づき、各ベンダー
がJavaScriptエンジンの開発を
行っている
• 仕様書はGitHub上でオープンに
開発されている
– https://github.com/tc39/ecma262
• 現在の正式な最新バージョンは
ES2016。
– バージョン番号はスナップ
ショット的な扱いであり、それ
ほど深い意味はない
– 本スライドでは、「次期ES」と
いう意味のES.nextと呼称する
ES.nextを書くには
• ブラウザごとの対応状況にばらつきがあ
ることから、トランスパイラ(ES.nextの
コードをES5に変換する)を使う必要があ
る
// ES6
const f = (a,b) => a+b;
// ES5
var f = function(a,b) {
return a+b;
}
ES.nextが変えたWeb開発
• ES.nextの変更点は多岐にわたるが、特に
以下の点でWeb開発を大きく変える
– モジュール&クラス
– 非同期処理に対する言語レベルでのサポート
• その他、「書いていて楽しい」機能も満
載
ES6を試してみる
• ECMAScript6以降で導入された言語仕様は多
岐に登るが、その中でも特に仕様頻度が高い
ものを紹介
– 変数
– 文字列
– 配列
– オブジェクトリテラル
– デストラクチャリング
– 関数
– クラス
ES6を試してみる:
変数
• letやconstが使えます。
– let: スコープが {...} に限定された変数の定義
• varは、関数スコープしか持たない
– const: 再代入不可のlet
• 正直、varの出番はもうありません
– ぼくらは、「基本const、たまにlet」というルールでやっ
てます
let a ='Hello';
const b = 'World';
b = 'Error'; // 再代入不可
ES6を試してみる:
文字列
• テンプレート文字列
– バッククォートで囲んだ文字列内では、"${ }"
を使って式を埋め込める
let a ='Hello';
const b = 'World';
const c = `${a}, ${b}`;
ES6を試してみる:
配列
• spread演算子
– 配列の中身をいい感じに展開
• for...of
– 配列(正確にはイテレータ)をループ処理
let a ='Hello';
const b = 'World';
const c = `${a}, ${b}`;
const d = [a, b];
const e = [1, 2, ...d]; // [1, 2, 'Hello', 'World']
e.push(...d); // [1,2,'Hello','World','Hello','World']
for (let f of e)
console.log(f); // 1, 2, Hello, World
ES6を試してみる:
オブジェクトリテラル
• Property Shorthand
– 変数名と同名のプロパティを簡単に定義
– {a: a} みたいなのを {a} で宣言できる
– 個人的には異様に便利
• Computed PropertyNames
– {[式]: 値} とすることで、プロパティ名に式を使用できる
• Method properties
– オブジェクトのメンバーに関数を指定するのが楽になった
let a ='Hello';
const b = 'World';
const c = {a, b}; // {a: Hello, b: World}
const d = {[a]: a}; // {Hello: Hello}
const f = {
method() {}
};
ES6を試してみる:
デストラクチャリング
• 配列やオブジェクトの中身を変数に展開
するのがとても楽に
• オブジェクトも配列も展開可能
const fullName =
{firstName: 'Shumpei', lastName: 'Shiraishi'};
// Destructuring
const {firstName, lastName} = fullName;
const array = [firstName, lastName];
// Destructuring
const [first, last] = array;
ES6を試してみる:
関数1
• アロー関数
– ( ) => { 関数本体 } という形式で関数定義可能
– 関数本体が単一の式な場合、中括弧を省略可能
• デフォルト引数
– 関数の仮引数に「= デフォルト値」と指定することで、
引数のデフォルト値を指定可能
const sum = (a = 0, b = 0) => { return a + b; };
// 上と同義
// const sum = (a = 0, b = 0) => a + b;
ES6を試してみる:
関数2
• Rest Parameter
– 関数の最後の仮引数を「...仮引数名」とすること
で、可変長引数を配列として扱うことが可能
• Spread Operator
– 「...配列」とすることで、配列を関数の引数に展
開できる
// 可変長引数を取る関数
const join = (s, ...rest) => [s, ...rest].join(' ');
let s = ['Wor', 'ld'];
// 配列を引数に展開
join('Hello,', ...s);
ES6を試してみる:
クラス
• クラス定義
• コンストラクタ
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
ES6を試してみる:
クラス
• 継承
– 親クラスのメンバーを引き継いだ新たなクラ
スを作れる
...(略)...
class MorningGreeter extends Greeter {
greet() {
return "Good morning, " + this.greeting;
}
}
モジュール
• 基本は1ファイル=1モジュール
• export…モジュール外にメンバーを公開
• import…他のモジュールを参照
export const GREETING = 'Hello';
export class Greeter {
}
import {GREETING, Greeter} from './greetings';
Advanced: モジュールバンドラー
• JavaScriptモジュールをまとめ上げ、1つ(以上)のファイル
を出力するツール
• モジュールバンドラーで、import/exportをJSコードに
変換
import {Component} from '@angular/core'
↓ (TypeScriptコンパイラ)
var Component = require('@angular/core').Component;
↓ (モジュールバンドラーがrequireをブラウザ上で使えるよう変換)
var component_1 = __webpack_require__(1);
ES6を試してみる:
Promise
• 非同期処理を、コールバックよりも記述しやすくする
– コードのネストが少なくなるため読みやすい
– エラー処理を行いやすい
// 指定したミリ秒待つ関数
function waitFor(millis): Promise<void> {
return new Promise((resolve, reject) => {
if (millis >= 0)
setTimeout(resolve, millis);
else
reject(new Error(`Invalid arg:${millis}`));
});
}
// 非同期関数
function hello(seconds) {
waitFor(seconds * 1000)
.then(() => alert('Hello'))
.catch (e) {}
}
hello(3); // 3秒後に「Hello」が表示される
ES6を試してみる:
async/await
• Promiseベースの非同期なコードを、あたかも同期的なコードであるかのように記述でき
るようになる
– 処理は依然として非同期なので、並列度が下がることもない
– 一度使うとやめられないくらい便利。
• asyncキーワードは関数に指定する。
– 指定した関数内ではawaitを使える
– async関数の戻り値はPromiseとなる
• awaitキーワードは、Promiseを返す関数呼び出しの前に付与する
– Promiseを返す関数の結果を戻り値として受け取れる。
– エラーをtry-catchできる。
…
// 非同期関数
async function hello(seconds) {
try {
// awaitで、Promiseの終了を待ち合わせ
await waitFor(seconds * 1000);
alert('Hello');
} catch (e) {}
}
hello(3); // 3秒後に「Hello」が表示される
Advanced: TypeScript
• Microsoftが開発したJavaScriptトランスパ
イラ。
• 大きな特徴は厳密な型付き言語であるこ
と。
– ざっくりいうと「ES.next + 型 + α」
• どうせビルドが必要な昨今、型チェック
もしてもらえるTypeScriptの人気は増して
いる
– Angular2は、TypeScriptで書くのがほぼ前提
型+αを試してみる
• 型定義、型推論、ダックタイピング
• ジェネリクス
• クラス
• 抽象クラス
• インターフェース
• Enum(列挙型)
• デコレータ
型+αを試してみる:
型定義、型推論、ダックタイピング
• 「変数名: 変数の型」という記述で変数の型
を明示的に指定可能
• 型を明示的に指定しない場合も、右辺から型
推論される。
• 型のORも可能(型Aもしくは型B)
let a: string ='Hello'; // 型を明示的に指定
const b = 'World'; // 型推論
b = 1; // 型が合わないためエラー
// 文字列もしくは数値型
let c: string | number = 'Hello';
c = 1; // 数値も代入可能
型+αを試してみる:
型定義、型推論、ダックタイピング
• 無名の型を簡単に宣言できる
• ダックタイピング
– 「もしもそれがアヒルのように歩き、アヒルのように鳴く
のなら、それはアヒルである」
– 宣言された型とは無関係のオブジェクトでも、インター
フェースが一致していれば同じ型だとみなされる
// 無名の型をアドホックに宣言
function hello(person: {name: string}): void {
alert(`Hello, ${person.name}`);
}
// 上の型と一致するオブジェクトを引数に指定
hello({name: 'shiraishi'});
型+αを試してみる:
ジェネリクス
• 型情報の一部をパラメータ化する機能
• 例えば、配列内容の具体的な型は、コー
ディング時に初めて決定する
// 文字列型の配列を宣言
let a: Array<string> = [];
// 配列については、以下のようにも指定可能
// let a: string[] = [];
a = 1; // 型が合わないためエラー
// 右辺の型から、型推論も行われる
let b = [1, 2, 3]; // numberの配列と推論される
b = 'a';
型+αを試してみる:
クラス
• アクセス修飾子
– private: そのクラス内でのみ利用可能
– protected: そのクラス、もしくは子クラスから利用可能
– public: あらゆる場所から利用可能
• コンストラクタでのプロパティ指定
– コンストラクタの仮引数に、アクセス修飾子をつけると、
クラスのプロパティ宣言を省略できる
class Greeter {
constructor(private greeting: string) {
}
greet() {
return "Hello, " + this.greeting;
}
}
型+αを試してみる:
抽象クラス
• abstractキーワードをクラスに指定すると抽象クラス
となる。
– 抽象クラスはnewできない
– 抽象クラスには抽象メソッド(中身なしのメソッド)を定
義できる
• 抽象クラスを継承するクラスは、抽象メソッドの実装
が求められる
abstract class Greeter {
constructor(private greeting: string) {
}
abstract greet();
}
// 抽象メソッドを実装していないのでエラー
class MorningGreeter extends Greeter {}
型+αを試してみる:
インターフェース
• interfaceキーワードを使用すると、インターフェース
を定義できる
• インターフェースは全てのメソッドが抽象メソッドと
なる
• implementsキーワードでインターフェースを実装する
クラスを作成可能
– 継承とは異なり、複数のインターフェースを実装可能
interface Greeter {
greet();
}
// 抽象メソッドを実装していないのでエラー
class MorningGreeter implements Greeter {}
型+αを試してみる:
Enum(列挙型)
• ひとまとまりの定数を型としてまとめら
れる機能
• Enumとは異なるが、代入可能な文字列を
型として定義する機能もある
// 0から始まる定数が割り振られる
enum RGB {RED, GREEN, YELLOW};
// 定数値を指定することも可能
// enum RGB {RED = 1, GREEN, YELLOW};
const color: RGB = RGB.RED;
// red/blue/yellowに限定した文字列型
let s: 'red' | 'blue' | 'yellow';
s = 'black';
型+αを試してみる:
デコレータ
• クラスやメンバー、メソッドの仮引数など、
あらゆる部分にメタデータを付与できる
– 実体は単純な関数
@Component({
providers: [MyService]
})
export class AppComponent {
@Input()
disabled: boolean;
constructor(
@Inject() myService: MyService) {
}
}
TechFeedの実コードで学ぶ
Web最新トレンド
TechFeedの実コードで学ぶ
Web最新トレンド
• これまで学んだことを、実際に動作する
コードを見ながら復習しましょう
– プログレッシブ・ウェブアプリ
– Angular2(コンポーネント指向フレームワー
ク)
– TypeScript + Webpack (ES.next)
TechFeedのアーキテクチャ
Ionic2
Angular2
Cordova
Webpack App
Node.js
サーバー
99% JavaScript
で出来てます
プログレッシブ・ウェブアプリ
• アプリケーションマニフェスト
– manifest.jsonを置き、linkタグに指定するだけ
プログレッシブ・ウェブアプリ
• ServiceWorker & プッシュ通知
– ServiceWorkerの登録
– プッシュ通知
navigator.serviceWorker.register('file')
self.addEventListener('push', function(event) {
const data = event.data.json();
const notification = {
body: data.message,
data: {url: data.url}
};
event.waitUntil(self.registration
.showNotification('TechFeed', notification));
});
Angular2
(コンポーネント指向フレームワーク)
• Angular2におけるコンポーネントは、@Component でデコレート
されたクラス
• HTMLでコンポーネントのテンプレートを、CSSでスタイルを定義
– これらもデコレータ内に指定する
– TechFeedでは、require() を使用して別ファイルに切り出し
• CSSはカプセル化されるので、クラス名の衝突は考えなくて良い
tf-entry-listitem
というタグで使え
るコンポーネント。
CSSとHTMLは
requireで別出し
※現在のTechFeedはAngular2 RC.4ベースのコードです
Angular2
(コンポーネント指向フレームワーク)
• コンポーネントのツリー構造でアプリケーションが構
築される
• コンポーネントに値を受け渡すには属性を、コンポー
ネントから値を受け取るにはイベントを用いる
※現在のTechFeedはAngular2 RC.4ベースのコードです
tf-entry-listitem
を使用
adプロパティに値
をセット
Digest
Realtime
EntryList EntryListItem
1 *
1
*
*
1
TypeScript + Webpack
(ES.next)
• import/export
• interface
• const
• デコレータ
• private
• ジェネリクス
• …
まとめ
最新のWeb開発トレンドは、
モバイルアプリを作るためにある。
ご清聴ありがとうございました。
http://techfeed.io
http://facebook.com/techfeedapp
http://twitter.com/techfeedapp
“エンジニアなら、使っとけ。”

jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ