Gutenberg
解体新書(初稿)
Ryo Utsunomiya(@ryo511)
WordCamp Tokyo 2018
2018-09-15
自己紹介
- 宇都宮 諒(うつのみや りょう)
 - 株式会社 一休 宿泊事業本部
 - 職種は「フロントエンドエンジニア」
 - 主なお仕事
 - 
WordPress歴
	
- ユーザとして4年くらい
 - 開発者として1年くらい
 
 - Twitter: @ryo511
 - 個人ブログ( https://ryo511.info/ )
 

Agenda
- 
	
Gutenbergはどういう技術で成り立っているのか
 - Gutenbergを拡張する(プラグインを作る)ためにはどういう技術が必要か
 
第1部
Gutenbergの
技術的な成り立ち
Gutenbergの成分表示
- 
	
GutenbergはWordPressプラグイン
 - 
	
主要成分はJavaScript
 - PHPもそれなりに
 

JavaScript
- 
	
Webブラウザ上で動作するプログラミング言語
 - JavaScriptの仕様はECMA Internationalという団体で策定されている
 - この仕様をECMAScriptと呼ぶ
 - 従来はES 3、ES 5のようなバージョン番号が使われていた
 - 2015年のES 6以降は毎年新バージョンが出るようになったため、発表年で呼ばれるように
 - 最新の仕様はES2018
 
ECMAScriptのブラウザ対応
- 
	
ECMAScriptの仕様化には、ブラウザでの実装状況も考慮される
 - ES2018の主要機能は、現在の主要なブラウザの最新版では動作する
 - ただし、IE11はES 5で更新が止まっている
 
JavaScriptライブラリとnpm
- 
	
Gutenbergでは、JavaScriptのライブラリ管理にはnpm(Node Package Manager)を使用している
 - npmはJavaScriptライブラリ管理のデファクトスタンダード
 - npmでは、依存しているライブラリをpackage.jsonというファイルに列挙する
 - package.jsonを見ることで、Gutenbergがどのようなライブラリを使っているかわかる
 
Gutenbergのpackage.json
- 
	
dependencies(動作に必要なライブラリ)と、devDependencies(開発に必要なライブラリ)に分かれる
 - dependencies
	
- React.js
 - jQuery
 - その他、@wordpress 系のライブラリ群も
 
 - devDependencies
	
- Babel
 - webpack
 - その他沢山
 
 
React.js
- 
	
Gutenbergの中心を成すライブラリ
 - Facebookが開発した、リッチなUIを開発するためのJavaScriptライブラリ
 - 現在最も人気のあるJavaScriptライブラリの1つ
	
- npmでは2017年に5900万回ダウンロードされた
 - 参考値:jQuery 4600万、Angular 1100万、Vue.js 800万
 
 
React.jsはコンポーネント指向
- 
	
React.jsは、リッチな=複雑なUIを、効率よく開発するためのライブラリ
 - Reactでは、コードを「コンポーネント」という単位で管理する
 - コンポーネントは、振る舞いと見た目を併せ持つ
 - Gutenbergでは、それぞれの「ブロック」が、Reactコンポーネントとして実装されている
 
React.jsのサンプルコード
// ES2015のclass構文
class HelloMessage extends React.Component {
  render() {
    return (
      // JavaScriptの中にHTMLを書く(JSX)
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}
// #app というidを持つ要素にReactアプリケーションを描画
ReactDOM.render(
  <HelloMessage name="Taylor" />,
  document.getElementById("app")
);最大の特徴は、JavaScriptの中にHTMLを書くこと
JSX
// JavaScript関数の戻り値にHTMLを書く
function Hello() {
  return <div>Hello World</div>
}
// HTMLの中にJavaScriptの変数を埋め込むことができる
function Hello(name) {
  return <div>Hello {name}</div>
}
// 関数呼び出しも可能
function Hello(name) {
  return <div>{greeting(name)}</div>
}
- 
	
React.jsは、JSXによって、高い表現力を実現している
 - しかし、JSXはブラウザでそのまま実行できるコードではない…
 
Babel
- 
	
JavaScriptトランスパイラ
 - JSX => JavaScriptの変換のほか、新しいバージョンのJavaScript(ES2018等)を、古いバージョンのJavaScript(ES5)に変換することもできる
 - React.jsを使った開発では、ほぼ必須のソフトウェア
 - もちろん、Gutenbergでも使っている
 
JSXトランスパイル
// ESNext + JSX
const hw = <h1>Hello World</h1>;
// ES5(React)
var hw = React.createElement("h1", null, "Hello World");
// ES5(Gutenberg)
var hw = wp.element.createElement("h1", null, "Hello World");- BabelはJSXをES5に変換する
 - JSXのHTMLタグは、React.createElement() の呼び出しと同じ
 - GutenbergはReact.createElement() をラップした独自メソッドを用意している
 
createElementを手書きする
// JSX
<div className="container">
    <h1>Header1</h1>
    <p>Paragraph</p>
</div>
// ES5
var el = wp.element.createElement;
el(
    'div',
    { className: 'container' },
    [
        el( 'h1', null, 'Header1' ),
        el( 'p', null, 'Paragraph' ),
    ],
);- JSXなしのReact開発も可能
 - ただし、記法が煩雑なので非推奨
 
Babelとセットで使う、
webpackというものがあると
聞いたんだけど… 🤔
webpack
- 
	
webpackは、ES2015のモジュールシステムを、レガシーブラウザ(IE11等)でも動くようにするためのツール
 - Babelのようなトランスパイラとセットで使うことが多い
 - Gutenbergでもwebpackを使っている
 
モジュールシステム
- 
	
jsファイルの外側から、ライブラリ等を読み込んで使用できるようにするための構文
 - import/exportというキーワードを使う
 - PHPのrequire/includeとだいたい同じ
 - モダンブラウザ(Chrome, Safari, Firefox, Edge等)では動く
 - IE11では動かないので、webpackを使って動作する形に変換する必要がある
 
ここまでのおさらい
- 
	
GutenbergはWordPressプラグインとして実装され、
 - npmを使ってライブラリを管理している
 - React.jsを使ってリッチなUIを実現している
 - Babelを使ってReactのJSXをブラウザで動くコードに変換している
 - webpackを使ってモジュールシステムがIE11でも動くようにしている
 
ところで、
Babelとかwebpackとか、
絶対に覚えないとダメ? 😨
最低限必要なのはReactだけ
- 
	
webpack + Babelのビルドの仕組み作りはそれなりに複雑で、学習コストがかかる
 - しかし、開発効率のためにはJSXを使えた方がよい…
 - create-guten-block等、Gutenbergの開発環境をセットアップしてくれるツールが出てきている。初めはツールの助けを借りて、徐々に自分でも設定できるようにしておけばOK
 
第2部
Gutenbergのプラグイン開発
Gutenbergの基本はブロック
- 
	
記事の編集に使用する、再利用可能な部品
 

GutenbergのブロックAPI
- 
	
自分で定義したブロックを登録し、Gutenberg で利用可能にできる
 - 段落(paragraph)や画像(image)のようなコアブロックも、ブロックAPIを利用している
 - コアブロックは packages/block-library の下にあるので、一度は覗いてみるのをおすすめ
 
ブロックの登録
import HelloBlock from './HelloBlock';
wp.blocks.registerBlockType( 'my-block/hello', {
	title: 'Greeting',
	icon: 'cart',
	category: 'common',
        // ブロックがもつメタデータを定義
	attributes: {
		// 省略
	},
        // ブロックの初回表示・編集時の動作を定義
	edit( { attributes, setAttributes } ) {
		return (
			<HelloBlock
				attributes={ attributes }
				setAttributes={ setAttributes }
			/>
		);
	},
        // ブロックを保存する際の動作を定義
	save( { attributes } ) {
		// 省略
	},
} );
ブロックはReactで作る
/* global React */
export default class HelloBlock extends React.Component {
	render() {
		const { name } = this.props.attributes;
		return <div>{ name }</div>;
	}
}
- 
	
たとえば、コアの段落ブロックはParagraphBlockというReactコンポーネントとして実装されている
 
記事データの保存形式(1)
- 
	
WordPressの記事データはwp_postsテーブルのpost_contentというカラムに保存される
 - クラシックエディタでは、保存されるのはHTML文字列
 - Gutenbergでも、保存先や保存形式は同じ
 - ただし、Gutenbergの場合、メタデータをコメントに埋め込む
 
記事データの保存形式(2)
<!-- wp:core/heading -->
<h2>What is Gutenberg?</h2>
<!-- /wp:core/heading -->
<!-- wp:core/cover-image {"url":"http://localhost:8888/wp-content/uploads/2017/12/Screen-Shot-2017-12-06-at-23.34.27.png","id":45} -->
<section class="wp-block-cover-image has-background-dim" style="background-image:url(http://localhost:8888/wp-content/uploads/2017/12/Screen-Shot-2017-12-06-at-23.34.27.png)">
</section>
<!-- /wp:core/cover-image -->
<!-- wp:core/paragraph -->
<p>Gutenberg is a new UX of WordPress editor.</p>
<!-- /wp:core/paragraph -->Gutenbergブロックのメタデータは
HTMLコメントの中にJSON形式で埋め込まれる
記事データの保存形式(3)
<h2>What is Gutenberg?</h2>
<section class="wp-block-cover-image has-background-dim" style="background-image:url(http://localhost:8888/wp-content/uploads/2017/12/Screen-Shot-2017-12-06-at-23.34.27.png)">
</section>
<p>Gutenberg is a new UX of WordPress editor.</p>- 記事データとして(the_post()などで)出力されるHTMLからは、メタデータ(コメント)は取り除かれる
 - 記事のレンダリングはサーバサイド(PHP)で行われる。Reactは記事のレンダリングには使わない。
 
ブロックのライフサイクル
- 
	
edit() で初期状態を出力(保存されたコンテンツを編集する際は、以前の状態の復元)
 - ユーザがコンテンツを編集する
 - save() の結果をpost_contentに保存
 
Attributes API
- Gutenbergのブロックのメタデータのことをattributesと呼ぶ
	
- 例:段落ブロックの文字サイズ等
 
 - ユーザがブロックに行った設定を反映するには、edit()の中でsetAttributes()メソッドを使用する
 - save() の中でattributesを参照して、最終的に保存するコンテンツを決定する
 - どのようなattributesを定義して、保存するか、がGutenbergのブロック開発のキモ
 
Gutenbergプラグインの構造
- 
	
通常のWordPressプラグインと変わらない
 - enque_block_editor_assets アクションでブロックのJSを読み込む
 
<?php
// index.php
/**
 * Register Block JavaScript file.
 */
add_action( 'enqueue_block_editor_assets', function () {
	wp_enqueue_script(
		'my-block',
		plugins_url( 'build/index.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element' )
	);
} );
まとめ
- 
	
Gutenbergは様々なJavaScriptライブラリによって成り立っている
 - React.jsを作った、モダンなJavaScriptアプリケーションとして実装されている
 - モダンなWebフロントエンドの技術を身につけることが、Gutenberg対応プラグイン開発の基盤になる
 
参考文献
- 
	
Gutenberg Handbook
 - React.js公式ドキュメント
 - Babel公式ドキュメント
 - webpack公式ドキュメント
 
【初稿】Gutenberg解体新書
By Ryo Utsunomiya
【初稿】Gutenberg解体新書
WordCamp Tokyo 2018セッションスライド初稿
- 2,540