当サイトを最適な状態で閲覧していただくにはブラウザのJavaScriptを有効にしてご利用下さい。
JavaScriptを無効のままご覧いただいた場合には一部機能がご利用頂けない場合や正しい情報を取得できない場合がございます。
承知しました
本サイトではWebサイトのエクスペリエンスを向上させるために、Cookieを使用しています。Cookieはブラウザの設定から無効にできます。本サイトで使用するCookieについては、プライバシーポリシーをご確認ください。

Blog

ブログ

開発者向け

HugoとHeadlessでチームを幸せにする方法

By Michael Berry  

Hugoの速度、セキュリティ、シンプルさが目を引きましたが、この静的サイトジェネレーターは、あなたとあなたの非技術チームの両方を満足させることができますか?

記事上で、 ヘッドレスCMSからHugoサイトのデータをフィードする方法を紹介します。これにより、開発者は静的サイトのメリットを享受しながら、コンテンツ作成者が好きなツールを使用できるようになります。

燃え尽き症候群に反応する」ことがどのように私をヒューゴに導いたか

静的サイトジェネレーター(SSG)は最近勢いを増しており、テクノロジーニュースフィードの概念に数週間衝撃を受けた後、傾向をよりよく理解する必要があると感じました。調査の結果、多くの著名なSSGがReactを使用していることがわかったので、JavaScriptのスキルを向上させ始めました。私はいくつかのきちんとしたReactプロトタイプを作成しましたが、エラーが発生したり、コードで迷子になったりしました。問題がJavaScript、React、JSXのいずれにあるのかを解明するのに苦労しました。それは、非常に苛立たしいことでした。たくさんのことを学びましたが、それは謙虚な経験でした。

私は燃え尽き症候群を避けるために他のオプションを検討し始めました。 State of Jamstack 2020 ReportでのHugoの人気が私の興味をそそったので、いくつかのチュートリアルを見ました。簡単そうだったので、「クイックスタート」チュートリアルを起動して実験しました。 2週間以内に、 Hugoの経験がゼロから、選択したヘッドレスCMSからコンテンツを取得する作業サイトに移行しました。 Reactとの最初の出会いと比べてなんと違います!

Hugoとは何ですか?

Hugoは、ファイルとテンプレートのソースディレクトリを取得し、これらを入力として使用して完全なWebサイトを作成します。GO上に構築され、独自のテンプレート言語を備えており、どこでもホストできます。 Hugoチームは(大胆に)それがウェブサイトを構築するための世界最速のフレームワークであり、最も人気のあるオープンソースの静的サイトジェネレーターの1つであり、スポーツであると主張しています 驚くべきスピードと柔軟性。

それはあなたにとってどういう意味ですか?

高度なReactの概念や複雑なJSを習得しなくても、静的に生成されたサイトのメリットを享受できます。 GOでプログラミングする方法を本当に知る必要はありません。いくつかの基本的なHugoテンプレートの概念、HTML / CSS、およびHugoのディレクトリ規則に関する知識を身に付ければ、サイトを構築するのに十分です。

私の経験では、高速でシンプルですが、2つの欠点が見つかりました。

    1. 箱から出して動的ページを真に作成する機能はありません。ルーティングの処理など、Hugoのすぐに使用できる機能を使用するには、コンテンツが「content」ディレクトリに物理的に存在する必要があります。つまり、デフォルトでは、外部システム(CMSなど)で作成されたページをプロジェクトに動的に追加することはできません。
    2. Hugoは、限られたコンテンツ作成ツールで物理的なマークダウンファイルを使用します。

これらの制限は、技術以外のチームにとってどのような意味がありますか?

誰もがMarkdownを好きというわけではありません。ほとんどのコンテンツクリエーターは、端末のようなエディターにまたは*記号を打ち込むよりもグラフィックなエクスペリエンスを望んでいると思います。また、ワークフローや共同編集などに慣れてきた貴重なCMS機能も見逃しています。何よりも悪いことに、Hugoでは、コードファイルと一緒に存在するマークダウンファイルに直接変更を加える必要があります(😱)。

では、チームのコンテンツ作成のニーズとHugoを使用したいという願望の間のギャップをどのように埋めることができますか?

恐れることはありません、CMSはここにあります!

開発者とコンテンツ作成者の両方をHugoに満足させるための重要な要素は、ヘッドレスCMSを統合することです。 ヘッドレスCMSは、編集カレンダーなどのコンテンツ作成ツールを提供します。

編集カレンダー
編集カレンダー

同時編集などのコラボレーション機能:

Kentico Kontent

このような生活の質の高い機能は、コンテンツの作成者や編集者を満足させます。開発者としてのあなたはどうですか?さて、あなたはそれのクラウドベースとして、ホストにそれを持っていない、あなたは、単純なデータ収集のためのSDKを取得します。それは素晴らしいと思いませんか?

私のソリューションを5つのステップで要約します。

  1. Hugoのセットアップ
  2. HugoをヘッドレスCMSに接続する
  3. JSONをMarkdownに変換する
  4. ビルドスクリプトの使用
  5. サイトの展開

Hugoのセットアップ

まず、Hugoをインストールする必要がありました。 Hugoは複数のプラットフォームで実行できます。私はWindowsマシンを使用しているため、ドキュメントに従ってChocolateyを使用しました。

 choco install hugo -confirm

Hugoをインストールしたら、新しいサイトコマンドを実行しました。

 hugo new site kontent-hugo-articles

これにより、すぐに開始するために必要なすべての定型ディレクトリを備えた新しいHugoサイトが作成されました。次のコマンドを使用して、新しいマークダウンファイルを作成しました。

 cd quickstart

そして、新しく作成したファイルにマークダウンコンテンツを追加しました。

 --- title: 'How to Make the Team Happy with Hugo and Headless' draft: false The speed, security, and simplicity of Hugo caught your eye, but can this static site generator satisfy both you and your non-technical team? In this article, I'll show you how to feed a Hugo site data from a headless CMS, so developers can reap the benefits of a static site while allowing content creators to use the tools they love. --- title: 'How to Make the Team Happy with Hugo and Headless' draft: false The speed, security, and simplicity of Hugo caught your eye, but can this static site generator satisfy both you and your non-technical team? In this article, I'll show you how to feed a Hugo site data from a headless CMS, so developers can reap the benefits of a static site while allowing content creators to use the tools they love. --- title: 'How to Make the Team Happy with Hugo and Headless' draft: false The speed, security, and simplicity of Hugo caught your eye, but can this static site generator satisfy both you and your non-technical team? In this article, I'll show you how to feed a Hugo site data from a headless CMS, so developers can reap the benefits of a static site while allowing content creators to use the tools they love. --- title: 'How to Make the Team Happy with Hugo and Headless' draft: false The speed, security, and simplicity of Hugo caught your eye, but can this static site generator satisfy both you and your non-technical team? In this article, I'll show you how to feed a Hugo site data from a headless CMS, so developers can reap the benefits of a static site while allowing content creators to use the tools they love.

テストコンテンツが作成され、構造が確立されたら、レイアウトディレクトリに_defaultサブディレクトリを追加し、single.htmlおよびlist.htmlレイアウトを作成しました。

〜/ layout / _default / list.html:

 

〜/ layout / _default / single.html:

 {{ .Content }}

コマンドhugoserverを実行すると、サンプルコンテンツをテストするサーバーが起動しました。

Kentico Kontent

基本が稼働しているので、ヘッドレスCMSの統合を開始できました。

HugoをヘッドレスCMSに接続する

すばやく立ち上げて実行するために、 Kentico Kontentのサンプルプロジェクトを使用することを選択し、そこに含まれる既成の記事を取得することに重点を置きました。

Hugoはデフォルトでマークダウン形式を使用するため、コンテンツをフェッチしてマークダウンファイルに変換する必要がありました。これを実現するために、最初にNode.jsをインストールし、npmを使用してコンテンツを取得するためのKentico Kontent Delivery JavaScriptSDKをインストールしました。

npm i rxjs --save
npm i @kentico/kontent-delivery --save

ライブラリがインストールされたら、プロジェクトにcms-scriptsディレクトリを作成して、CMS実装の詳細をHugoのものから分離しました。

ここからは、 Kontent Delivery SDKのドキュメントに従って、Delivery Clientをセットアップし、APIを介してKontentプロジェクトの記事を取得する必要がありました。このロジックを2つのファイルに分けました。
cms-scripts / config.js:

 const KenticoContent = require ( '@kentico/kontent-delivery' ); const deliveryClient = new KenticoContent.DeliveryClient({    projectId : ' '
}); exports .deliveryClient = deliveryClient; const KenticoContent = require ( '@kentico/kontent-delivery' ); const deliveryClient = new KenticoContent.DeliveryClient({    projectId : ' '
}); exports .deliveryClient = deliveryClient;


cms-scripts / buildArticles.js:

 const { deliveryClient } = require ( './config' ) const subscription = deliveryClient.items() .type( 'article' ) .depthParameter( 2 ) .toObservable() .subscribe( response => {        console .log(response) }) 
Kentico Kontent

node cms-scripts/buildArticles.jsすると、KontentDeliveryエンドポイントからJSON応答が発生しました。さて、応答をHugoが期待する物理的なマークダウンファイルに変換する時が来ました。

JSONをMarkdownに変換する

KontentのJSONをHugoのデフォルトのマークダウンファイル形式に変換するには、次の3つのレイヤーがあります。

応答からのコンテンツの抽出:

cms-scripts / buildArticles.js:

 //code continued from cms-scripts/buildArticles.js
//...
const markdownConverter = require ( './markdownConverter' ); //...
 .subscribe( response => {        for ( var item of response.items){            //frontmatter:
            const title = item.title.value            const codename = item.system.codename             //correct mismatch between Kontent date format and Hugo's expected format
            let date = new Date ( Date .parse(item.post_date.value)) date = date.toISOString()            //article content
            const body_copy = item.body_copy.resolveHtml()            const teaser_image = item.teaser_image.value[ 0 ]            //convert JSON values to markdown
            const data = markdownConverter.convert(title, date, body_copy, teaser_image) } }); //code continued from cms-scripts/buildArticles.js
//...
const markdownConverter = require ( './markdownConverter' ); //...
 .subscribe( response => {        for ( var item of response.items){            //frontmatter:
            const title = item.title.value            const codename = item.system.codename             //correct mismatch between Kontent date format and Hugo's expected format
            let date = new Date ( Date .parse(item.post_date.value)) date = date.toISOString()            //article content
            const body_copy = item.body_copy.resolveHtml()            const teaser_image = item.teaser_image.value[ 0 ]            //convert JSON values to markdown
            const data = markdownConverter.convert(title, date, body_copy, teaser_image) } }); //code continued from cms-scripts/buildArticles.js
//...
const markdownConverter = require ( './markdownConverter' ); //...
 .subscribe( response => {        for ( var item of response.items){            //frontmatter:
            const title = item.title.value            const codename = item.system.codename             //correct mismatch between Kontent date format and Hugo's expected format
            let date = new Date ( Date .parse(item.post_date.value)) date = date.toISOString()            //article content
            const body_copy = item.body_copy.resolveHtml()            const teaser_image = item.teaser_image.value[ 0 ]            //convert JSON values to markdown
            const data = markdownConverter.convert(title, date, body_copy, teaser_image) } });

Turndown.jsnpm install turndown )を使用して抽出されたJSONコンテンツをマークダウンに変更するマークダウンコンバーターを作成します。

cms-scripts / markdownConverter.js:

 const TurndownService = require ( 'turndown' ); const convert = ( title, date, body_copy, teaser_image ) => {    //markdown conversion
    const turndownService = new TurndownService()    const markdown = turndownService.turndown(body_copy)    const header_image = turndownService.turndown( `${teaser_image.url} ' alt=' ${teaser_image.description} '/>` )    const data = `--- title: ' ${title} ' date: ${date}
 draft: false ---    ${header_image}
    ${markdown}
 `    
    return data    exports .convert = convert; const TurndownService = require ( 'turndown' ); const convert = ( title, date, body_copy, teaser_image ) => {    //markdown conversion
    const turndownService = new TurndownService()    const markdown = turndownService.turndown(body_copy)    const header_image = turndownService.turndown( `${teaser_image.url} ' alt=' ${teaser_image.description} '/>` )    const data = `--- title: ' ${title} ' date: ${date}
 draft: false ---    ${header_image}
    ${markdown}
 `    
    return data    exports .convert = convert;

Nodeの組み込みfsライブラリを使用して、Hugoコンテンツディレクトリまたはサブフォルダに物理ファイルを作成します。

cms-scripts / buildArticles.js(完全なコード):

 const { deliveryClient } = require ( './config' ) const markdownConverter = require ( './markdownConverter' ); const fs = require ( 'fs' ); const subscription = deliveryClient.items() .type( 'article' ) .depthParameter( 2 ) .toObservable() .subscribe( response => {        for ( var item of response.items){            //frontmatter:
            const title = item.title.value            const codename = item.system.codename             //correct mismatch between Kontent date format and Hugo's expected format
            let date = new Date ( Date .parse(item.post_date.value)) date = date.toISOString()            //article content
            const body_copy = item.body_copy.resolveHtml()            const teaser_image = item.teaser_image.value[ 0 ]            //convert JSON values to markdown
            const data = markdownConverter.convert(title, date, body_copy, teaser_image) fs.writeFileSync( `content/articles/ ${codename} .md` , data) } }); const { deliveryClient } = require ( './config' ) const markdownConverter = require ( './markdownConverter' ); const fs = require ( 'fs' ); const subscription = deliveryClient.items() .type( 'article' ) .depthParameter( 2 ) .toObservable() .subscribe( response => {        for ( var item of response.items){            //frontmatter:
            const title = item.title.value            const codename = item.system.codename             //correct mismatch between Kontent date format and Hugo's expected format
            let date = new Date ( Date .parse(item.post_date.value)) date = date.toISOString()            //article content
            const body_copy = item.body_copy.resolveHtml()            const teaser_image = item.teaser_image.value[ 0 ]            //convert JSON values to markdown
            const data = markdownConverter.convert(title, date, body_copy, teaser_image) fs.writeFileSync( `content/articles/ ${codename} .md` , data) } }); const { deliveryClient } = require ( './config' ) const markdownConverter = require ( './markdownConverter' ); const fs = require ( 'fs' ); const subscription = deliveryClient.items() .type( 'article' ) .depthParameter( 2 ) .toObservable() .subscribe( response => {        for ( var item of response.items){            //frontmatter:
            const title = item.title.value            const codename = item.system.codename             //correct mismatch between Kontent date format and Hugo's expected format
            let date = new Date ( Date .parse(item.post_date.value)) date = date.toISOString()            //article content
            const body_copy = item.body_copy.resolveHtml()            const teaser_image = item.teaser_image.value[ 0 ]            //convert JSON values to markdown
            const data = markdownConverter.convert(title, date, body_copy, teaser_image) fs.writeFileSync( `content/articles/ ${codename} .md` , data) } });

上記のスクリプトが配置されたら( このGitHubリポジトリで確認できます)、ターミナルでnode cms-scripts/buildArticles.jsを再度実行することで、Hugoプロジェクトにコンテンツを追加し始めることができました。

Kentico Kontent
Kentico Kontent

/ content / articlesディレクトリにあるマークダウンファイルを使用しhugo server実行してサイトをオンラインにすることができます。

Kentico Kontent

私はショックを受けました!ヘッドレスCMSをわずか3つの小さなJavaScriptファイルでHugoに接続すると、間違いなく私の顔に笑顔がもたらされました。

ビルドスクリプトの使用

この時点で、ヘッドレスCMSコンテンツを使用するローカルで実行されているHugoサイトがありました。すごい! node cms-scripts/buildArticles.jsを手動で実行してプロジェクトにデータを入力し、続いて別のコマンドを実行してHugoサーバーを実行することは理想的ではありませんでした。このプロセスを合理化するために、 npm-run-allを使用しました。これにより、 package.json local:startコマンドを使用して、Windowsマシンでスクリプトを一緒に実行できました。
〜/ package.json:

 'scripts': { 'cms:prepare': 'node cms-scripts/buildArticles.js', 'local:start': 'npm-run-all -p cms:prepare local:serve', 'scripts': { 'cms:prepare': 'node cms-scripts/buildArticles.js', 'local:start': 'npm-run-all -p cms:prepare local:serve',

これにより、ローカルビルドが簡素化されるだけでなく、ホスト環境でビルドを自動化するための基礎が整います。

サイトの展開

私のHugoプロジェクトに完全に満足する前の最後の障害は次のとおりです。

  • 全世界が見ることができるようにサイトを展開する
  • ビルドプロセスの自動化

幸いなことに、どちらもNetlifyのようなホスティングサービスで可能になります。 NetlifyへのデプロイはGitHubリポジトリに接続するのと同じくらい簡単であるだけでなく、GitをプッシュするたびにWebサイトの自動ビルドを実行することもできます。

Netlifyをホスティングと自動ビルドに活用するために、 package.jsonを変更してNetlifyビルドスクリプトを含めました。

〜/ package.json:

 'scripts': { 'cms:prepare': 'node cms-scripts/buildArticles.js', 'local:start': 'npm-run-all -p cms:prepare local:serve', 'netlify:serve': 'hugo -b $DEPLOY_PRIME_URL', }, 'scripts': { 'cms:prepare': 'node cms-scripts/buildArticles.js', 'local:start': 'npm-run-all -p cms:prepare local:serve', 'netlify:serve': 'hugo -b $DEPLOY_PRIME_URL', }, 'scripts': { 'cms:prepare': 'node cms-scripts/buildArticles.js', 'local:start': 'npm-run-all -p cms:prepare local:serve', 'netlify:serve': 'hugo -b $DEPLOY_PRIME_URL', }, 'scripts': { 'cms:prepare': 'node cms-scripts/buildArticles.js', 'local:start': 'npm-run-all -p cms:prepare local:serve', 'netlify:serve': 'hugo -b $DEPLOY_PRIME_URL', },

これにより、Netlifyで「ビルドとデプロイビルドコマンド」を設定できるようになりました。 Gitから新しいサイトを作成し、buildコマンドをnpm run netlify:build publish 、PublishをPublishディレクトリとしてターゲットに設定しました。これらはすべてNetlifyインターフェイス内から行われます。これで、このプロジェクトのGitHubリポジトリでコードを変更すると、サイトが自動的に再構築されました。

Kentico Kontent

この自動化をCMSのコンテンツ更新に拡張するために、Kontentのドキュメントに従ってKenticoKontentのWebhookとペアになっているNetlifyのビルドフックを使用しました。この追加により、コンテンツがKentico Kontentプロジェクトで公開または非公開になるたびに、Netlifyはサイトを再構築して、コンテンツが常に最新の状態になるようにします。

概要

この記事では、Hugoを紹介し、HugoをヘッドレスCMSに接続する方法と、それが開発者とコンテンツ作成者の両方にどのように役立つかについて説明しました。あなたとあなたの非技術的なチームメイトの両方が将来のプロジェクトでHugoと一緒に働くことを楽しむことができることをあなたに示したことを願っています!

この記事でHugoとKenticoKontentの可能性に興奮した場合は、より堅牢なHugo + Kontentサンプルサイトをここで確認できます。

Headless CMSの導入をお考えでしょうか?

クラウドとマルチデバイスに最適化されたKentico Kontentをお試しください