web.dev エンジニアリング ブログ #1: サイトの構築とウェブ コンポーネントの使い方

この投稿は、web.dev のエンジニアリング ブログの最初の投稿です。今後数か月にわたって、私たちの仕事から行動につながるインサイトを共有したいと考えています。エンジニアリング ブログのタグを付けて投稿をお待ちください。 ここでは、静的サイトのビルドプロセスと、ウェブ コンポーネントの背後にある JavaScript です。

web.dev では、最新のウェブ エクスペリエンスの構築に関するコンテンツが提供され、サイトのパフォーマンスを測定できます。経験豊富なユーザーは、[測定] ページが単なる Lighthouse のインターフェースであり、Chrome の DevTools でも利用できることをご存じかもしれません。 web.dev にログインすると、Lighthouse の監査を定期的に実施して、サイトのスコアの推移を確認できます。 [測定] ページはかなり特別なものなので、しばらくしてからもう一度アクセスします。🎊

はじめに

基本的に、web.dev は Markdown ファイルのコレクションから生成される静的サイトです。Eleventy を選択したのは、Markdown を簡単に HTML に変換できる洗練された拡張可能なツールです。

また、asyncawait など、type="module" をサポートするブラウザにのみ配信される最新の JavaScript バンドルも使用しています。Google では、最新ブラウザではサポートされているが、一部の古いバージョンではサポートされていない機能も使用しています。Google は静的サイトであるため、コンテンツの読み取りに JavaScript は不要です。

静的 HTML を生成し、JavaScript を Rollup とバンドルするビルドプロセスが完了したら、シンプルな静的サーバーで web.dev をホストしてテストできます。 このサイトはほぼ完全に静的ですが、カスタム Node.js サーバーを利用する特別なニーズがいくつかあります。これには、無効なドメインに対するリダイレクトや、今後予定されている国際化機能のためにユーザーの使用言語を解析するコードが含まれます。

静的生成

web.dev の各ページは Markdown で記述されます。すべてのページには、各投稿に関するメタデータを記述したフロント マターがあります。このメタデータは各ページのレイアウトに取り込まれ、見出しやタグなどが作成されます。次の例をご覧ください。

---
layout: post
title: What is network reliability and how do you measure it?
authors:
  - jeffposnick
date: 2018-11-05
description: |
  The modern web is enjoyed by a wide swath of people…
---

The modern web is enjoyed by a wide swath of [people](https://www.youtube.com/watch?v=dQw4w9WgXcQ), using a range of different devices and types of network connections.

Your creations can reach users all across the world...

このフロント マターによって、作成者、公開日、タグなどの任意のプロパティを定義できます。Eleventy は、ほぼすべてのプラグインやテンプレートなど、インテリジェントな処理を行う必要のあるコンテキストにおいて、最前線のデータをデータとして簡単に公開します。 このデータ オブジェクトには、Eleventy がデータ カスケードと呼ぶものも含まれています。これは、各個々のページ、ページで使用されるレイアウト、階層フォルダ構造内のデータから pull されるさまざまなデータです。

固有のレイアウトはそれぞれ、異なるタイプのコンテンツを記述し、他のレイアウトから継承できます。 web.dev では、この機能を使用すると、1 つのトップレベル HTML レイアウトを共有しながら、さまざまなタイプのコンテンツ(投稿や Codelab など)を正しくフレーム化できます。

コレクション

Eleventy では、コンテンツの任意のコレクションをプログラマティックに構築できます。これにより、ページネーションのサポートを構築し、投稿者向けの仮想ページ(一致する Markdown ファイルがディスク上にないページ)を生成できるようになりました。たとえば、作成者のページは、パーマリンクの式(すべての作成者に対してテンプレートが再レンダリングされるように)を含むテンプレートと、裏付けとなるコレクションを使用して構築しています。

これにより、たとえば、Addy のすべての投稿を含むシンプルなページができあがります。

制限事項

現時点では、Eleventy のビルドプロセスには簡単に組み込むことができません。これは、命令型ではなく宣言型であるため、記述方法ではなく、宣言型です。Eleventy はコマンドライン インターフェースからしか呼び出せないため、大規模なビルドツールの一部として実行することは困難です。

テンプレート

web.dev では、Mozilla が開発した Nunjucks テンプレート システムが使用されています。Nunjucks にはループや条件などの一般的なテンプレート機能がありますが、さらに HTML を生成したり、他のロジックを呼び出すショートコードを定義したりすることもできます。

静的コンテンツ サイトを構築しているほとんどのチームと同様に、Google も小規模から始めて、時間をかけてショートコードを追加してきました(現在までに約 20 のショートコードを追加)。そのほとんどは、(Google のカスタム ウェブ コンポーネントを含む)さらに HTML を生成するだけです。次の例をご覧ください。

{% Aside %}
See how Asides work in the web.dev codebase
{% endAside %}

結果は次のようになります。

しかし、実際には次のような HTML が作成されます。

<div class="aside color-state-info-text">
<p>See how Asides work in the web.dev codebase</p>
</div>

この記事の対象外ですが、web.dev でもメタプログラミング言語の一種としてショートコードが使用されています。ショートコードは引数を受け取り、そのうちの 1 つは含まれているコンテンツです。ショートコードが何かを返す必要はないので、ショートコードを使用して状態を構築したり、他の動作をトリガーしたりできます。🤔💭

スクリプト作成

前述のように、web.dev は静的サイトであるため、JavaScript なしで提供され、type="module" などの最新のコードをサポートしていない古いブラウザでも使用できます。これは、web.dev を誰でも利用できるようにするための Google の取り組みの非常に重要な部分です。

ただし、最新のブラウザのコードは主に次の 2 つの部分で構成されています。

  1. グローバル状態、アナリティクス、SPA ルーティングのコードを含むブートストラップ コード
  2. サイトを段階的に強化する Web Components 用のコードと CSS

ブートストラップ コードは非常にシンプルです。web.dev は新しいページをシングルページ アプリケーション(SPA)として読み込むことができるため、ローカルの <a href="..."> 要素のクリックをリッスンするグローバル リスナーをインストールします。SPA モデルでは、ユーザーの現在のセッションに関するグローバルな状態を維持できます。そうしないと、新しいページが読み込まれるたびに、ユーザーのログイン状態にアクセスするための Firebase への呼び出しがトリガーされます。

また、ヒットした URL に基づいてサイトへの異なるエントリポイントを指定し、動的な import() を使用して正しいエントリポイントを読み込みます。 これにより、サイトにコードを実装する前にユーザーが必要とするバイト数を減らすことができます。

ウェブ コンポーネント

ウェブ コンポーネントは、JavaScript で提供されるランタイム機能をカプセル化したカスタム要素で、<web-codelab> などのカスタム名で識別されます。このデザインは、web.dev のような大部分が静的なサイトに適しています。つまり、サイトの HTML が更新されるとブラウザが要素のライフサイクルを管理し、ページに要素を追加または削除する際に正しく通知します。 旧式のブラウザは Web Components を完全に無視して、DOM に残っているものをレンダリングするだけです。

各ウェブ コンポーネントは、connectedCallback()disconnectedCallback()attributeChangedCallback() などのメソッドを持つクラスです。web.dev のカスタム要素のほとんどは、複雑なコンポーネントのシンプルなベースを提供する LitElement を継承しています。

web.dev は多くのページで Web Components を使用していますが、これほど必要なのは [測定] ページだけです。このページで説明するほとんどの機能は、次の 2 つの要素で構成されています。

<web-url-chooser-container></web-url-chooser-container>
<web-lighthouse-scores-container></web-lighthouse-scores-container>

これらの要素により、より多くの機能を提供する追加要素が作成されます。重要なのは、これらの要素は Google の通常の Markdown ソースコードの一部にすぎないということです。コンテンツ チームは、測定ノードだけでなくあらゆるページに拡張機能を追加できます。

Google の Web Components は、React で広く採用されている Container Component モデルが最も一般的に利用されています。ただし、このモデルはやや古くなっています。各 -container 要素は、グローバルな状態(unistore 提供)に接続して視覚要素をレンダリングします。さらに、スタイル設定やその他の組み込み機能を備えた実際の DOM ノードをレンダリングします。

グローバルな状態と、それを使用する HTML 要素の関係を示す図。
グローバルな状態とウェブ コンポーネント

Google の最も複雑なウェブ コンポーネントは、グローバルなアクションと状態を可視化するために存在します。たとえば web.dev では、お気に入りのサイトを監査してから、Measure ページから離れることができます。 戻ると、タスクがまだ進行中であることが表示されます。

Google のシンプルなコンポーネントは、静的コンテンツを純粋に強調したり、優れた可視化機能を作成したりします(たとえば、各折れ線グラフは独自の <web-sparkline-chart> です)。これはグローバルな状態とは関係ありません。

お問い合わせ

web.dev のエンジニアリング チーム(RobEwaMichaelSam)が、近日中に技術的な詳細を追ってご連絡いたします。

Google の取り組みが皆様のプロジェクトの参考になれば幸いです。このブログに関する質問やトピックのリクエストがある場合は、Twitter でお問い合わせください。