AlgoliaによるNetlify Build Pluginの構築方法

この記事はAlgoliaのエンジニアである、Sylvain BelloneによるHow Algolia created its Netlify build pluginのブログの翻訳です。


私たちはAlgolia Netlify Pluginを先日リリースしました。このプラグインに関する詳細を読んだり、イントロをご覧いただくことで、すぐに始めていただくことができます。Algoliaはフレキシブルな検索とナビゲーションのプラットフォームで、カッティングエッジなWeb、スマートフォンなどのアプリケーション、そしてeコマースの体験を可能にします。こちらの記事では、どのようにAlgoliaがこのプラグインを開発したのかにdeep diveし、そして、Netlify build pluginsを構築しているクリエイターの方にもインサイトをご提供させていただけるものとなっております。

どのようにNetlify Build Pluginsを使うかに関しては use Netlify Build Plugins を、またどのようにNetlify Build Pluginsを作るのかに関しては create your own をご覧ください。

Algolia Netlify Pluginとは何か?

Algolia Netlify Pluginは、わずか数行のコードでAlgoliaの検索機能が簡単に導入できる、というものです。アドバンテージとしては、一度セットアップを行えば、コンテンツを更新するたびに検索インデックスに自動的に反映されるため、検索結果はウェブサイトのコンテンツに合わせて進化をしていきますし、検索インデックスを維持するような手間を省けます。新しいバージョンがpublishされるたびに、プラグインがクローラーをトリガーし、あなたのウェブサイトのコンテンツをブラウズおよび抽出し、Algoliaのインデックスにpushします。

Algolia Netlify pluginの処理フロー図

どのように構築したか

このプラグインのゴールは、Algoliaを活用して簡単に設定を行うことができるNetlify検索体験を提供することにあります。

  • Search API、そして実際の検索エンジン
  • CrawlerはWebサイトをクロールして、ページのコンテンツをstructured dataにしてAlgoliaにプッシュを行うAlgoliaのadd-on機能
  • Autocomplete.js UIライブラリ

私たちの目標はNetlifyプラグインを作成し、コンテンツのデプロイ後にクローラーがウェブサイトをブラウズし、Algolia Indexをready-to-userな形にビルドするというものです。これは簡単なように聞こえるかもしれませんが、Greatなユーザー体験を提供するためにはやらなければならないことが沢山あることが分かるでしょう。以下のセクションでは、既存コンポーネントと新しいコンポーネントにおいて必要であった作業について詳しく説明していきます。

Algolia account と authentication

Algoliaを使うには、まずAlgoliaのアカウントを持っている必要があります。そして、Algoliaのクローラーのインターフェースにアクセスするためには、それ専用のパーミッションが必要となります。今回はユーザーがTokenをcopy/pasteしたり、アクセスをリクエストしたり、といったことをしなくても済むように、新しいログインオプションを追加しました: NetlifyのOAuth2 APIと統合された”Login with Netlify”です。NetlifyアカウントでAlgoliaにログインすると、自動的にAlgoliaのアカウントが裏で作成され、Algolia Crawlerのインターフェースへのアクセスを許可するようになっていて、また、その際、後から使う用に、Netlifyのトークンも取得して保存しておきます。

Algoliaログインオプションのスクリーンショット(右下が今回新しく追加したNetlifyログインボタン)

クローラーUIのアップデート

クローラーが自身のWebサイト上でどのように動作していたかを明らかにするために、レポート用のインターフェースを提供する必要がありました。ということで、既存のAlgoliaのクローラーのインターフェースへのアクセスを提供するために、Netlifyユーザー向けにいくつかのTweakを行って、スムーズな体験を提供しました。

Netlifyユーザー向けに提供するツール類を管理するために、”Netlify”というロールを新たに作って、そのロールのユーザーは、通常のお客様に提供しているAdvancedな機能の一部やデバッグツールが活用できるようになっています。

このNetlifyロールは、NetlifyプラグインおよびNetlifyユーザーのためだけに開発されたもので、いくつかの特別なページにアクセスすることが許可されています。それによって、Netlifyサイトにおいてプラグインのインストールを管理することができるようになっています。これらのページにおいては、認証時に取得したOAuthトークンを使ってNetlify APIとやりとりを行い、ユーザーのサイトをリスト化し、プラグインがそのサイトにインストールされた際に必要なAPIのクレデンシャルをNetlifyにpushすることが可能になっています。

API update

クローラーをプログラムで管理するためのAPIは既存のものがあるわけですが、私たちが必要としていたのは、Netlifyのウェブサイトにデプロイがされたシチュエーションに特化したアディショナルなエンドポイントでした:

  • クローラーが存在しない場合に、クローラーを作成(ブランチごとに1つのクローラー)
  • netlify.tomlの値によって設定を上書き
  • 実際のクロールの実行

このエンドポイントはNetlify上でビルドがトリガーされた際にコールされるものになります。

OAuthのおかげで、プラグインとしては、クローラーのインターフェースからインストールする際に、Netlifyサイトの環境変数として自動的に追加されるクレデンシャルによってエンドポイントが保護されるような仕組みになっています。

Data 抽出

Algoliaのクローラーは、データの抽出を完全にカスタマイズすることが可能であることから、”Algolia Custom Crawler”という名前が付けられました。実際に、私たちのクローラーはお金を支払ってご利用いただいているお客様にご自身で実装していただく`recordExtractor`というJavaScriptの関数を使って、抽出されたデータを完全にコントロールすることが出来ます。これはCheerioのインスタンスを使って各ページのDOMにアクセスできるようになっているため、そのデータをカスタマイズして、構造化されたレコードとしてリターンするといったものです(以下はパンくずからURLと階層およびコンテンツを抽出し構造化されたデータとしてリターンする例):

recordExtractor: ({ $, url }) => {
  const hierarchy = $('.breadcrumb > ul > li > a')
    .map((i, el) => $(el).text())
    .get()
  const content = $('#main-content .section-main p')
    .map(function() { return $(this).text() })
    .get()
    .join(' ');
  return [{
    url,
    hierarchy,
    content,
  }];
}

このプレミアム機能は、お客様ご自身が自分のサイトに合わせた機能を生成して、欲しいデータが正確に抽出できる優れたものとなっています。

私たちはNetlifyプラグインにおいては、このようなコードやアドバンストな設定を必要としない、ほとんどのウェブサイトに対応するような汎用的なソリューションを提供したいと考えていました。チャレンジとしては、実際のところ全てのWebサイトの構造は大きく異なっていて、HTMLはページのコンテンツを構造化するために数多くのタグを用いているわけですが、ほとんどのウェブサイトは未だ古き良き divタグに依存しています。これによって実際のコンテンツを抽出した後にその他の(メニューやフッター等)の残りの部分を取り除くことが難しくなってしまっています。

これに対応する魔法のような方法は存在しないわけで、解決策としては、各ページの複数の場所からコンテンツを抽出するといった単純なものからはじめて、実際のウェブページでテストを行うということから模索していきました。そこから、共通のパターンを特定してイテレーションを回していく、と。コンテンツデータを抽出するプロセスの各変更が有用であるかどうかを確認するために、私たちは時間をかけて様々なウェブサイト(もちろんNetlifyにホストされているもの)のスナップショットを作成して、それらのウェブページで抽出の機能を実行し、そのスナップショットを作成しました。このようにして、抽出のアルゴリズムを改良していく中で、何が壊れてしまったか、何を改善できるかといったことを確認していきました:

Front-endのバンドル

検索結果を表示するフロントエンドは、Greatな検索体験という観点で非常に重要であり、ウェブサイトをメンテナンスする人は常にbuild と integrateを行う必要があります。Algoliaでは、このプロセスの手助けをする多くのライブラリを備えていますが、Netlifyプラグインにおいては、このステップを更に簡単にしたいと考えていました。抽出されたレコードの構造は分かっているわけなんどえ、Autocomplete.jsをベースとしてpre-packagedなUIを構築することにしました。Autocomplete.jsはとても軽量なオートコンプリート用のライブラリで、Algoliaで開発を行っており、長年にわたってDocSearchのUIの構築に使われてきました。

その結果、あなたのウェブサイトのコードにおいては、数行だけcopy/pasteするだけで、、、

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@algolia/algoliasearch-netlify-frontend@1/dist/algoliasearchNetlify.js"></script>
<script type="text/javascript">
  algoliasearchNetlify({
    appId: '<YOUR_ALGOLIA_APP_ID',
    apiKey: '',
    siteId: '',
    branch: 'master',
    selector: 'div#search',
  });
</script>

、、、以下のようなUIが出来上がります。

もちろん、あなたのウェブサイトにパーフェクトにマッチするようなデザインにするためには、あながご自身で構築なさることをオススメしますが、このpre-packagedなUIは、ほんの数分ではじめることができる素晴らしい方法だと考えております。もちろん、配色等を微調整できるようにテーマのプロパティを公開しています。

フロントエンドバンドルのスクリーンショット

実際のプラグイン

最後のAlgolia Netlifyプラグインのピースは、、もちろん実際のプラグインそのものです!

Netlifyプラグインを作ることは非常にスムーズな体験でした。NetlifyのAPIとその周辺ツールは完璧で且つ扱いやすく、AlgoliaのようなAPIサービスを組み合わせて使う用途にデザインされているものであると確信しています。このプラグインのコアな部分は以下のAPIコールにサマライズできます:

function onSuccess(params) {
  require('https').request('https://crawler.algolia.com/api/1/netlify/crawl', { method: 'POST' }).end();
}

イニシャルバージョンの実装においては、onSuccessビルドイベントが利用できませんでした。ビルドによってトリガーされるイベントは onPostBuild で、これはビルドの後に、サイトが公開される前にトリガーされてしまいます。私たちのプラグインにおいては、実際のウェブサイトをクロールすることを目的としているので、サイトが公開された後のイベントが必要でした。そこで私たちはNetlifyのチームにコンタクトをとりましたが、非常にレスポンスが早く、すぐにonSuccessイベントをプラグインで利用できるようにしてくれました。この段階で、プラグインはクロールをトリガーするように、クローラーのAPIを呼び出します。

※注: この onSuccess イベントはNetlifyチームによって現在開発中の機能であり、将来的に実装が変更される可能性があります。このトピックに関するアップデートをチェックしましょう!

クロールが完全に処理を終えるには時間がかかる(各ウェブサイトのページ数による)ので、プラグインはビルドプロセスをブロックさせずにバックグラウンドで稼働させ続けます。

Development and release

私たちはプラグインのコードとUIのコードを同じリポジトリに置くことにしました。そして、staticなテスト用のウェブサイトが入っているディレクトリも追加しています。

コードレポジトリの構造のスクリーンショット。3つのディレクトリはそれぞれフロントエンド、プラグイン、そして、パブリック

これによって、開発とリリースのためのスクリプトを一元管理できるようになりました。Netlify CLIはローカルでNetlify buildをシミュレートすることを許可しているので、yarn devコマンドをセットアップすることができました。

  • フロントエンドで開発バージョンを実行
  • フロントエンドを開発する際に使うテストウェブサイトを提供
  • プラグインのローカル版を実行するNetlifyビルダーをトリガーして、ローカルのクローラーをコール

これはリリースする際と同様です: NetlifyプラグインはnpmのPublic Registryで配布されます。フロントエンドはjsDeliverで配布されており、こちらもnpmのPublic Registryに依存しています。テストサイトに関しては当然Netlifyでホストされています。その意味するところは、というと、最新の変更をGitHubにpushするたびにテストサイトも更新されるということです。このリリースプロセスは以下の3つのステップにサマライズすることができます

最近の変更点とエンハンスメント

もし、10月の段階で最初のベータ版を試されているのであれば、それ以降、私たちは数多くの改善とプロダクトに磨きをかけてきました。ということでv1に含まれている全ての変更のサマリをこちらに掲載させていただきます。是非お試しください!

  • ページのJavaScriptを実行するための新しいオプションの追加
  • 📑  抽出テンプレート。ページごとに複数のレコードを抽出できる。DocSearchのUIとの互換性
  • ✨ pre-built UIはAlgoliaのオートコンプリートライブラリを書き換えたAutocomplete.js v1を使用
  • ⚙️ ブランチをまたいだAlgoliaインデックスのカスタマイズのサポート: メインのインデックスに設定された変更は全ての新しいブランチに反映
  • 💻  カスタムドメインの設定が可能に

まとめ

Algoliaにとって、Netlifyチームの手助けを受けてプラグイン構築を行ったことは、やりがいのある体験でした; 他のSaaS企業にもオススメしたいと思います。また、多くの様々なコンポーネントを活用しましたが、Netlifyのツールは快適に使うことができ、そして、彼らの応答の良さにはとても助かりました。これらの作業は大変興味深いものだったと言えるでしょう。

一歩引いた観点では、Netlify Build PluginはAlgoliaのようなサービスを統合するのに最適なものであると本当に思います。

最後に皆さんにとってのベネフィットとしては:

  • Netlifyはユーザーが無料で簡単に設定できる検索機能をオファーしています
  • Algoliaは百万人のNetlifyディベロッパーにプロダクトを披露することができました
  • NetlifyユーザーはJamstackサイトを構築するための様々なプラグインを利用することができます

これらの理由から、SaaS企業におかれましては、ご自身のNetlifyプラグインを構築することをオススメいたします!

もし、Netlifyのウェブサイトをお持ちでしたら、是非お試しください

コメント

タイトルとURLをコピーしました