『React入門』を読んだ

React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで (NEXT ONE)

『React入門』は、JavaScriptの定番ライブラリ、React.jsの入門書です。

Reactの入門書は他にもありますが、本書が特に優れているのは、実務で使う上で必要なポイントが書かれている点です。

Reactはそれほど機能の多くないビューライブラリで、Reactと他のライブラリを適宜組み合わせることで、リッチなユーザインターフェースを実現します。

しかし、従来の入門書の多くは、React本体の入門で終わっています。ある程度の規模になると必要になる状態管理ライブラリや、リッチなインタフェースを実現するためのUIライブラリ等、Reactは本体以外にも学ぶべきことが色々あります。

本書では、他の入門書で扱っているようなReact本体の入門は前半3分の1くらいで、その後はReduxやUIライブラリ、ユニットテスト、作ったアプリケーションの公開方法(GitHub PagesとFirebase)からサーバサイドレンダリングまで、より実践的なトピックを手厚く紹介しています。

Vue.jsやAngular等、モダンなJavaScriptフレームワークの経験者であれば、本書でいきなりReactに入門できると思います。そうでない人は、もう1冊他の入門書を挟んでから本書を読んだ方が良いかもしれません。

Webフロントエンド技術を扱った本の宿命として、本書もそれほど賞味期限は長くないので、早めに読むのがオススメです。

Gutenberg コードリーディングメモ

Gutenberg本体のコードを読む上で、とっかかりになりそうな部分をメモ。

registerBlockType()

https://github.com/WordPress/gutenberg/blob/master/blocks/api/registration.js#L51

色々バリデーションが書いてあって、最終的には

でローカル変数 blocks に第1引数(name)をキー、第2引数(settings)を値として追加する。

setAttributes()

BlockListBlock というブロックで定義されている。

https://github.com/WordPress/gutenberg/blob/master/editor/components/block-list/block.js#L184-L203

ここではBlockListBlockがpropsに持っているonChange()メソッドが重要。

https://github.com/WordPress/gutenberg/blob/master/editor/components/block-list/block.js#L465

onChangeはStoreをdispatchする。属性の設定処理の本体はreducerにある。

https://github.com/WordPress/gutenberg/blob/master/editor/store/reducer.js#L129

Gutenbergのコードを読むなら、ある程度Flux(およびその実装であるRedux)については理解しておく必要がある。

Gutenberg Handbook 読書メモ (3) Reference

↓の続き。今回はリファレンスをざっくり。

Gutenberg Handbook 読書メモ (1)
Gutenberg Handbook 読書メモ (2)

Attributes

https://wordpress.org/gutenberg/handbook/reference/attributes/

ソース(source)

属性のsourceはブロックの属性の値の取得方法を定義する。

それぞれのsourceは、第1引数にセレクタを取る(オプショナル)。セレクタが指定されると、sourceは、ブロック内で対応する要素を取得する。

内部では、sourcehpqライブラリのスーパーセットとなっている。

attribute

attributeを使うと、マークアップから属性を取得できる。

以下の例では、imgタグからsrc属性を抜き出している。

text

textを使うと、マークアップの内側のテキストを取得できる。

html

htmlを使うとマークアップの内側のHTMLを取得できる。

children

childrenを使うとマッチした要素の子ノードを取得できる。Editableコンポーネントとの組み合わせでよく使われる。

query

queryを使うと、複雑なセレクタでマークアップから値を取得できる。

以下では、それぞれのimg要素からurlalt属性を抜き出している。

Meta

記事のメタデータ(post meta)から属性を取得することもできる。

このようにすると、ブロックからメタ属性に対して読み書きできるようになる。

検討事項

デフォルトでは、メタフィールドは記事のオブジェクトのメタデータからは除外されている。この制限は、フィールドを明示的に可視化することで回避可能である。

さらに、WordPressは以下のようなデフォルト設定になっている点に注意が必要。

  • メタデータをユニークなものとしては扱わず、値の配列を返す
  • データを文字列として扱う

どちらの振る舞いも望ましくないなら、register_meta関数の呼び出しを以下のようにすることで、補うことができる。

最後に、属性に値を設定する際はデータの型に注意が必要である。

Blocks support by themes

https://wordpress.org/gutenberg/handbook/reference/theme-support/

基本的に、ブロックのスタイルのカスタマイズはテーマ側のCSSで行うことができる。しかし、一部の機能はテーマ側での明示的な有効化(オプトイン)が必要になる。

Meta Boxes

https://wordpress.org/gutenberg/handbook/reference/meta-box/

※色々書いているけど一旦飛ばす

Glossary

https://wordpress.org/gutenberg/handbook/reference/glossary/

用語集

  • 属性ソース(Attribute sources): ブロックの属性の形を記述するオブジェクト
  • 属性(Attributes): ブロックの現在の状態を表現するオブジェクト
  • ブロック(Block): マークアップの単位を表す抽象的な用語。ブロックは組み合わせて使用され、Webページのコンテンツやレイアウトを構成する。
  • ブロックの名前(Block name): ブロック型のユニークな識別子
  • ブロック型(Block type): ブロックの振る舞いの定義
  • 動的ブロック(Dynamic block): 保存時にコンテンツが確定せず、記事が表示されるタイミングで描画されるブロック
  • Editable: リッチエディタ機能を提供するコンポーネント
  • Inspector: ブロック設定用のUIコンポーネント
  • 記事の設定(Post settings): 記事編集画面のサイドバーのこと
  • シリアライゼーション(Serialization): 記事の保存時にブロックの属性オブジェクトをHTMLマークアップに変換するプロセス
  • 静的ブロック(Static Block): 記事の保存時に内容が確定するブロック
  • TinyMCE: リッチエディタ(WYSIWYGエディタ)
  • ツールバー(Toolbar): ブロックの上に表示される一連のボタンのこと

Design Priciples

https://wordpress.org/gutenberg/handbook/reference/design-principles/

抽象的な話なので割愛

History

https://wordpress.org/gutenberg/handbook/reference/history/

内容がないので割愛

Coding Guidelines

https://wordpress.org/gutenberg/handbook/reference/coding-guidelines/

Gutenbergのコードに関することなので割愛。

Testing Overview

https://wordpress.org/gutenberg/handbook/reference/testing-overview/

JSはnpm testでテストが実行できる。

Jestのスナップショットテストを使っていて、スナップショットテストを使う際のベストプラクティス等について言及してある。

FAQ

https://wordpress.org/gutenberg/handbook/reference/faq/

いずれ公式で訳されるはず。

Gutenberg Handbook 読書メモ (2) Block Tutorial

Gutenberg Handbook 読書メモ (1) の続き。

Block

https://wordpress.org/gutenberg/handbook/blocks/

新しいブロック型を作るためのチュートリアル。

このチュートリアルのコードは下記GitHubリポジトリから入手できる。
https://github.com/WordPress/gutenberg-examples

なお、本記事のサンプルコードはESNextとJSXを使用しているが、Gutenbergのブロック機能はES5でも利用できる。

Writing Your First Block Type

https://wordpress.org/gutenberg/handbook/blocks/writing-your-first-block-type/

はじめに、固定されたメッセージを表示するブロック型を作成する。静的なコンテンツを含むブロックはJavaScriptでregisterBlockType関数を使うだけで実装できる。この関数はブロックの青写真となり、エディタ上での表示、編集・保存時の動作等を定義する。

ブロックのスクリプトを追加(enque)する

ブロック型はJavaScriptで実装されるが、WordPressのenqueue_block_editor_assetsアクションを使ってスクリプトがエディタに読み込まれるようにする必要がある。このアクションはwp_enqueue_scriptsと似ているが、エディタのスクリプトとスタイルに限定される点に違いがある。

特に注意が必要なのは以下のように設定していること。

  • wp-blocks は、ブロック型の登録と関連する関数の読み込みを行う
  • wp-element はWordPressのElement抽象化機能を使用する

ブロックの登録

スクリプトが登録されたので、次にブロックを実装する。

ブロックを登録すると、エディタのinserterのダイアログで利用できるようになる。inserterではtitle, icon, categoryが利用される。アイコンは組み込みのアイコンから選ぶか、独自のsvg要素を指定する。

ブロック名は nemaspace/block-name という構造である必要がある。

editsave関数は、エディタ画面でのレンダリングと保存後のレンダリングを定義する。

Applying Styles From a Stylesheet

https://wordpress.org/gutenberg/handbook/blocks/applying-styles-with-stylesheets/

↑のサンプルではインラインでスタイルを定義しているが、外部のスタイルシートにスタイルを定義して、これを読み込む方法もある。

エディタは、それぞれのブロック型に対して、独自のクラス名を自動的に生成する。このクラス名には、editsave関数のオブジェクト引数からアクセスできる。

クラス名は、ブロック名を元に生成される。

エディタでのみ使用するブロックのアセットを登録(enque)する

enqueue_block_editor_assetsアクションを使うことでエディタでのみ使用するスタイルを登録できる。

エディタとフロントエンドで使用するアセットを登録(enque)する

ブロックのスクリプトはエディタでのみ必要なものだが、スタイルはサイトの表側とエディタの両方で読み込みたいこともある。

enqueue_block_editor_assetsアクションはエディタの読み込み時にしかトリガーされない。サイトの表側でも読み込まれるようにするには、enqueue_block_assetsアクションを使うのが良い。

JavaScriptをサイトの表側に限定したいなら、enqueue_block_assetsアクションを使った上で、! is_admin()の場合のみ読み込むようにすれば良い。

Introducing Attributes and Editable Fields

https://wordpress.org/gutenberg/handbook/blocks/introducing-attributes-and-editable-fields/

属性(attributes)

ブロックの出力は属性(attributes)の値によって決まる。

新しいブロック型を登録する際は、attributesプロパティによってeditsave関数で受け取りたいオブジェクトの形を指定できる。それぞれの値はsource function(???)であり、ブロックをマークアップするための値を取得する。

上記サンプルコードでは、contentの値を子供のp要素から取得している。

コンポーネントとEditableコンポーネント

ここまで、createElement関数(またはJSX)を使ってDOMノードを作成してきた。これらの振る舞いは、「コンポーネント」に閉じ込めることもできる。このような抽象化を行うことで、処理の共通化や複雑さの隠蔽といった恩恵を得ることができる。ブロックを作成する際に利用できるコンポーネントがいくつも用意されている。サンプルコードではEditableコンポーネントを使用している。

Editableコンポーネントはtextarea要素の機能強化版である。太字、イタリック体、ハイパーリンク等の機能を持っている(Editableコンポーネントは、現行のビジュアルエディタと同様、TinyMCEを使って実装されている)。

Block Controls: Toolbars and Inspector

https://wordpress.org/gutenberg/handbook/blocks/block-controls-toolbars-and-inspector/

ブロックのカスタマイズをシンプルにして、ユーザに一貫した体験を提供するため、エディタのプレビュー機能の提供を助ける組み込みのUIパターンが用意されている。wp.blocksグローバル変数は、エディタのインタフェースとして利用できる、いくつかの共通コンポーネントを含んでいる。

ツールバー

ユーザがブロックを選ぶと、その上にツールバーが現れ、その上にいくつものボタンが表示される。これらのブロック用コントロールは、選択された要素がEditableコンポーネントである場合などに自動的に表示される。

ツールバーをカスタマイズして、特定のブロック専用のコントロールを読み込むこともできる。ブロック型のedit関数の戻り値がBlockControls要素を含んでいれば、これらのコントロールがブロックのツールバーに表示される。

ブロックが選択されている場合のみBlockControlsを読み込むよう注意が必要である。↑ではfocus変数の値を見ることで、BlockControlsの条件レンダリングを実現している。

Inspector

フォームのフィールドのためにより広い編集エリアがほしい場合、inspectorを使うことができる。InspectorControlsを読み込んで、edit関数で表示すればよい。

Gutenberg Handbook 読書メモ (1)

WordPressのエディタ画面のカスタマイズのため、新エディタ「Gutenberg」のドキュメントを読んでます。覚え書きを書き残しておきます。

Introduction

https://wordpress.org/gutenberg/handbook/

  • “Gutenberg”とは、新しいWordPressエディタのコードネーム
  • リッチなレイアウトを誰でも簡単に作れるようにするのが目的
  • “Block” という概念を導入することで、ショートコードやカスタムHTMLを不要にする

The Language of Gutenberg

The Language of Gutenberg

  • Gutenbergの中心にあるのは「ブロック」の概念である
  • Gutenbergでは、記事(post)はブロックの集合からなる
  • ブロックは活版印刷における活字のようなもので、記事の編集時には必要だが、最終的に出力される記事には含まれない

ブロックはHTMLよりも高い次元にある

  • ブロックはHTMLを出力するための機能だが、ユーザが編集を助けるための機能も伴っている
  • ブロックは最終的なHTMLを出力するために必要な情報を全て保持している

2つのpost

  • Gutenbergの記事(post)はブロックのことを知っている(block-aware)
  • Gutenbergのpostは、post_contentそのものではない

ブロックのツリー

  • 実行時に、ブロックはメモリ上に保持される
  • GutenbergのpostはHTMLではなく、オブジェクトのツリーである
  • ルートノードは必要とせず、ノードのコレクションである

シリアライゼーションとHTMLコメントの目的

  • Gutenbergのデータモデルは、記事の編集中のメモリに保持されるが、レンダリング結果からは痕跡が消える
  • Gutenbergはデータモデルをpost_contentに保存できるようシリアライズする
  • シリアライズの過程では、ツリーをHTMLに変換する。その際、HTMLコメントをブロックの境界として用いる
  • 編集時には、HTMLコメントからツリーを再構築する
  • 仮に、Gutenbergに対応していないテーマを使用したとしても、最低限のコンテンツは描画されるようになっている(動的な要素は描画されない)

デリミタと式文法の構文解析

  • HTMLコメントでは、二重のハイフン(–)を除いて、文法上の制約は無い
  • ブロックの属性はJSONリテラルとしてコメントに埋め込まれる

シリアライズされたブロックの中身

ブロックがwp_contentに保存されると、その属性はコメント内に保存される

サーバサイドでレンダリングされる動的なブロックは以下のようになる:

Gutenbergのライフサイクル

要約すると、Gutenbergの記事を編集する手順は、文書を保存してツリーを生成するところから始まる。最終的に、ブロックはpost_contentに保存される。編集中、全ての操作はブロックのツリーに変更を加える。

Extensibility

Extensibility

ブロックの作成

ブロックAPIを使うことで、静的なブロック、サーバサイドでレンダリングされる動的ブロック、post_metaにデータを保存するブロックなどを作成できる。

※メモ:クライアントサイドでの動的なレンダリングはできない???

静的ブロックは以下のように作成できる。

ブロックの削除

ブラックリストの使用

以下のようなJavaScriptコードを書き、

エディタ内で読み込むようにすればよい。

ホワイトリストの使用

特定のブロック以外を無効化したい場合、以下のように書く。

inserterからブロックを隠す

inserterに表示するブロックはサーバサイドでフィルタリングできる。

ブロックの編集(実験的)

既存のブロックの挙動を変更するため、Gutenbergはフィルターを提供している:

  • registerBlockType: ブロック設定のフィルタリング
  • getSaveContent.extraProps: save関数でWP elementを返す全てのブロックに適用されるフィルタ。ブロックにpropsを追加する場合に使用する
  • BlockEdit: ブロックのedit関数で受け取ったWP elementを編集するのに使う

全てのブロックにデフォルトで背景を設定している。

エディターUIの拡張(SlotとFill)

Coming soon. とのこと(2017/12/04現在)

Block API

Block API

プラグインやテーマは、エディタに対する独自の機能や追加の機能をブロックとして登録できる

ブロック型の登録

全てのブロックは、ブロック型定義の登録を行う必要がある。これには、registerBlockType関数を使用する。

ブロック名

新しいブロック型の登録にはregisterBlockType関数を使用する。この関数は、ブロック名と設定オブジェクトを引数に取る。

ブロック名は namespace/block-name という構造になっていなければならない。namespaceはプラグインやテーマの名前である。

注意:ブロック名には小文字のアルファベットと数字、ダッシュ(-)記号のみを含み、最初の1文字目はアルファベットでなければならない

ブロック設定オブジェクトの代表的な設定は下記の通り

  • title(必須): ブロックのinserter上に表示する名前
  • category(必須): inserter上の分類。common formatting layout widgets embedのいずれか
  • icon: ブロックのアイコン WordPressのDashiconsの名前を指定するか、独自のsvg要素を指定する
  • keywords: 検索時のキーワード
  • attributes: ブロックが使用する構造化されたデータ
  • transforms: 説明なし。WIPらしい
  • useOnce: 記事ごとに1個だけしか使えない場合はtrueにする
  • supports: サポート機能を拡張する設定
    • anchor(default: false): ページ内リンクできるようにする
    • customClassName(default: true): ブロックのラッパー要素にブロック独自のクラス名をつける
    • className(default: true): .wp-block-bour-block-name という形式のクラスをつけるか
  • supportHTML(default: true): HTMLモードで編集可能か

Edit and Save

Edit and Save

editsave関数によって、ブロックがどのようにレンダリングされるか定義できる。
※以下のサンプルコードではESNextとJSXを使用している。

Edit

edit 関数はエディタを使用している際のブロックの構造を定義する。

この関数は、引数のオブジェクトから以下のプロパティを受け取ることができる。

attributes

利用可能な属性と、それに対応した値。以下のサンプルでは、contentという属性を定義して、ブロックのコンテンツとして使用している。

className

ラッパー要素のクラス名。これらはsave関数によって自動的に追加されるが、editの段階では自動的には追加されない。クラス名を明示的に受け取るにはclassNameプロパティを使用する。

focus

ブロックがフォーカスされている状態か否かを判定する。

setAttributes

ユーザの操作に応じて属性の値を更新できる。

setFocus

ToDoらしい

Save

save関数は、最終的なマークアップを決定する。これはGutenbergによってシリアライズされて、post_contentに保存される。

save関数はnullを返すこともできる。この場合、属性のみがシリアライズされ、サーバサイドでHTMLの描画処理が行われる(これを動的(dynamic)ブロックと呼ぶらしい)。

save関数もプロパティを受け取ることができる。

attributes

editと同様の使い方。保存時にコンテンツが確定し、サーバサイドでの描画が必要ない静的ブロックでは、attributesの値をsave関数でマークアップに埋め込めば良い。