StrapiでHeadless CMS+高速サイト制作を始めよう(インストール・使い方など導入解説)
Strapiは話題のHeadless CMS
Headless CMSとは?
Headless CMSは、コンテンツ管理などのバックエンド機能のみを提供するCMSです。
ユーザーに直接提示されるビュー=フロントエンドを管理せず、APIを通してコンテンツを受け渡します。そのことで、フロントエンドの自由度が上がり、開発効率の向上も期待できます。
最新技術を用いたウェブサイトはもちろん、スマホアプリ、デジタルサイネージなど、様々なプラットフォームと連携させることが可能です。
Headless CMSについてはこちらの記事で詳しく説明しています。
Strapiのメリット
Headless CMSの中で、近年注目を集めているのがStrapiです。
コーディングなしでも簡単&高速にAPI開発が可能な、Node.jsベースのCMSです。2015年から開発され、現在は3.0.0-beta版が公開されています。まずはStrapiの魅力をご紹介していきます。
完全無料
Strapiは完全無料のオープンソースソフトウェアです。有料のクラウド型HeadlessCMSも多数ありますが、Strapiは自分でサーバーに載せて動かすタイプのもの。サクサク動くので、公開用だけでなく、社内ネットワークなどでも活用可能です。
基本設定が手軽
Strapi自体の導入は、コマンドたった1行で完結。のちほどデモでご紹介しますが、コンテンツタイプの作成や、カテゴリー同士の結びつきの設定、投稿作成画面のレイアウトなど、ほとんどの設定を管理画面のみで行えます。
SQLiteを推奨
SQLiteはファイル形式でデータベースを管理するRDBMS。データベース用のサーバーを別で立てる必要がなく、初期設定の手間を節約してくれます。
カスタムも自在
プラグインやフック、ミドルウェアなどを柔軟に追加できる設計のため、カスタムの幅は絶大。コアライブラリを最小限のサイズに抑え、ユーザーの管理やメールの送信といった基本機能も公式プラグインとして組み込まれています。
Strapiのデメリット
Strapi3系は現在まだベータ版のため、すぐに導入するには注意点もあります。
日本語のドキュメントがない
公式ドキュメントや、フロントエンドフレームワークとの連携例など、英語での情報は既に様々なものがありますが、日本語の情報はまだまだ少ない状態です。Strapi本体の管理画面では部分的に日本語がサポートされています。
下書き保存ができない
ブログやメディアで頻繁に利用する下書き機能。開発予定にはありますが、提供はまだ先のようです。どうしてもすぐに必要なら自力で実装することも可能……です。
バグやアップデートに要注意
まだベータ版ですので、特にSQLite以外のPostgres、MySQL、MongoDBなどのデータベースを使用する場合、細かなバグが見つかるようです。今後の大きなリリースの際には移行の手間もかかるかもしれません。
カスタムには知識が必要
StrapiはNode.jsベースのCMSですので、きめ細かなカスタムには、Node.jsそのものや、Koa、Bookshelf、MongooseといったStrapiが利用するNodeベースのパッケージの理解も必要です。これらには新しいものも多く、日本語の情報がほぼないものも含まれます。
さっそく始めてみよう
というわけで、発展途上ではあるものの、とにかく試してみる価値のあるStrapi。今回は10ステップで、フロントエンドの構築までを行ってみたいと思います。フロントエンドにはGatsbyを使いますので、のちほどご紹介しますね。
事前準備
Strapiの使用にはNode.jsが必要となります。この機会にインストール・アップデートしてみてくださいね。
- Node.js 10.x以上
- npm 6.x以上
ステップ1:QuickStartで一発導入
好きな作業用ディレクトリに移動して、ターミナルやコマンドプロンプトで下のコマンドを叩くだけ!
npx create-strapi-app backend --quickstart
ここで「backend」としたアプリ名はお好きなものでOKです。データベースの設定なども不要で、インストールが終わり次第、自動でブラウザが開き、localhostの1337番ポートが使用されて、Strapiのセットアップ画面が表示されているはずです。
ちなみに、Strapiサーバーの稼働を止めたい時はコマンド上でControl+C、再開したいときはこのディレクトリで「npm run develop」とコマンド入力すればOKですよ。では、ルートユーザーを作成し、管理画面に入ってみましょう。
ステップ2:コンテンツタイプを作成
左のメニューから「コンテンツタイプ作成」を選ぶと、すでに「Permission」「Role」「User」という、Strapi本体で使うユーザーや権限のコンテンツタイプが登録されているのがわかります。
Strapiでは、投稿内容や各種データなどを全て「コンテンツ」として扱えるため、何をどう格納するのか、どこまでオープンにするのか、などを決めることができます。また画像などのファイルをアップロードする機能もありますよ。
今回のデモでは、複数店舗を持つお店のウェブサイトを作ります。各店舗の住所や営業時間が載った「店舗情報」ページ、随時更新されるブログ形式の「新着情報」ページを用意する想定で進めていきます。まずコンテンツタイプの名前を、英単語の単数形で書きます。
「Shop」「Article」と名前が決まったら、フィールドを追加していきます。文字列(String)や数値(Number)、真偽値(Boolean)などの型や、他のコンテンツタイプとのリレーションなど、13種類のフィールドタイプが選択できます。
これらを組み合わせて、店ら「店舗名」「住所」「電話番号」「営業時間」のような項目を追加していきます。
ステップ3:コンテンツを追加
ここまできたら、左のメニューバーに各コンテンツタイプの名前が表示されているはずです。中に入って、エントリーを追加していきましょう!
Shopsに4つ、Articlesに3つエントリーを作ってみました。なお、このエントリーリストに表示される項目や、ソートに使うフィールド、エントリーの編集画面のレイアウトも柔軟に編集することが可能です。
ステップ4:権限を解放
さっそく実際の返却データを確認してみたいのですが、そのまえにもう1つだけ準備があります。メニューから「ロールと権限」を選択します。ここでは自由にロールを追加し、権限を設定して、ユーザーを紐づけることができます。
今回はコンテンツの表示が外からできればよいので、デフォルトで用意されている「Public」ロールの設定を変更します。
いま作成した「Shop」と「Article」が表示されていますので、「count」「find」「findone」にチェックをしてみます。チェックすると右下にはAPIのエンドポイントが表示されます。
ステップ5: 完了!
無事にJSON形式のデータが表示されました!
こちらはShopsのうちIDが2の投稿を表示しています。見づらいですが、「西店」の名前や住所などが入っています。後半からはこの「西店」の投稿に紐づけている「articles」の内容が出力されています。このデータが読める場所・プログラムなら、どこでもStrapi内のデータを活用可能というわけです!
また、Strapiにはパラメータも用意されていますので、IDが2より大きいshopsを表示「/shops?id_gt=2」、アップデート日時が新しい順にarticlesから3記事表示「/articles?_limit=3&_sort=updated_at:desc」、といったことも設定いらずで可能です。
なおupdated_at、created_atは全てのコンテンツタイプにデフォルトで挿入されるフィールドとなっています。ソートやフィルタに役立ちますよ。以上でStrapiの導入編は終了です!
フロントエンドから呼び出してみる
ステップ6:GraphQLを導入してみる
ここからはフロントエンドを実装していきたいのですが、Strapiにもうひと工夫してみます。メニューの「マーケットプレイス」から、公式プラグイン「GraphQL」をインストールしてみます。
GraphQLとは
GraphQLは、Facebookが開発したWebAPIの規格です。リクエストを受ける側のスキーマ、送信側のクエリの2種類があり、どちらも実際のレスポンスデータと似た形をしています。先ほどのように、隠せ須崎のURIで内容が決まるのではなく、1つのアドレスに様々なクエリを送信し、内容を指定します。
(ちなみに、先ほどのコンテンツタイプごとに異なるURLをもつものはRESTful APIと呼ばれます)
プラグインを導入したら、localhost:1337/graphqlでエディタを開くことができます。クエリの編集はもちろん、右端の「DOCS」「SCHEMA」タブで、どんなデータがリクエスト可能か随時確認もすることもできます。
ここで、「全てのarticleのtitleとid」「idが2のshopのaddress」「全てのarticleのtitleと全てのshopのname」といったクエリが実行できます。
ステップ7:Gatsbyを導入してみる
さて、今回はGatsbyを利用してフロントエンドを開発してみたいと思います。さきほど「backend」ディレクトリを作った階層から初めて、順にコマンドを打ちます。
npm install -g gatsby-cli gatsby new frontend cd frontend npm install --save gatsby-source-strapi gatsby develop
Gatsbyとは
インストールの間に少しご紹介を。Gatsbyは静的サイトジェネレータとして知られています。静的サイトジェネレータは、さまざまなデータやファイルからHTML/CSS/Javascriptのサイトを生成するツールです。
あらかじめサイトを生成しておくため、表示が高速で、データベースのセキュリティも高いことが特徴です。逆に、たとえばWordPressは、アクセスごとにデータベースに問い合わせを行ない、結果をもとにその場でページを作って表示させています。
GatsbyはReact+GraphQL製の強力な静的サイトジェネレータで、
- 生成されたサイトの動作が非常に速い
- SEOの面でも高品質
- PWA、AMPなどの技術にも対応できる
- Reactを駆使した動的なUIを生成できる
などのメリットがあります。特に最後の点について、Gatsbyは単なる静的サイトジェネレータの枠におさまらない、Reactフレームワークとしての実力も持っていると言えます。
本記事はReactの知識がなくてもお読みいただけますが、Reactが気になった方はぜひこちらの記事をご覧ください!
デフォルト表示
さて、最後のコマンドの実行が完了したところで、localhost:8000にアクセスすると、Gatsbyのデフォルトページが表示されるはずです。今回は省略しますが、最初はデフォルトページのソースコードを読み解いてみることをおすすめします!
こちらをもとに制作を進めていきます。用意するのは「トップページ」「各店舗のページ」「各記事のページ」の3種類です。ここからはコーディング多めになりますが、だいたい何をやっているかが伝われば幸いです!
ステップ8:GatsbyでStrapiのデータを取得
まずはStrapiで作成したコンテンツを持ってきましょう。さきほどのコマンドで「gatsby-source-strapi」プラグインをインストール済みですので、Gatsbyの設定ファイルにStrapiのアドレスなどを追記しておきます。ついでにサイトのメタデータも編集しておきます。
module.exports = { siteMetadata: { title: `Sample Cafe`, description: `Demo site for Webkiaku blog post which instructs fast API development with Strapi and Gatsby`, author: `@webkikaku`, }, plugins: [ /* 中略 */ { resolve: 'gatsby-source-strapi', options: { apiURL: 'http://localhost:1337', contentTypes: [ 'article', 'shop' ], queryLimit: 100, }, }, /* 中略 */ ], }
いちどGatsbyサーバーを停止し、「gatsby develop」コマンドを叩いて再起動します。Strapiのデータが読めるか確かめるため、今度はGatsby側のGraphQLエディタにアクセスしてみましょう。アドレスはlocalhost:8000/___graphqlになります。
Gatsbyでは、Reactコンポーネント以外の全ての要素を「データ」と定義しています。言い換えると、「gatsby-config.js」内に先ほど記述したサイトのタイトルや、このサイトが動いているホスト名(いまはlocalhost)をはじめとする様々な情報を、データとしてGraphQLで呼び出すことができます。
Strapiとの連携がうまくいっていれば、「allStrapiArticle」「allStrapiShop」「strapiArticle」「strapiShop」もデータとして登録されているはずです。
ステップ9:個別ページを作成
ここまできたら、データを使ってサイトを作成していきましょう!コーディング多めになってしまいますが、ざっくりとツールの便利さがお伝えできれば幸いです。
まず記事、店舗の個別ページを作ります。運営するうちに数が増えるものですので、それぞれ、テンプレートにデータを流し込む形式にします。
URLは、「/article/:id」「/shop/:id」とすることにしました。(こうしたルーティングも自由に設定できちゃいます!)
作業ディレクトリの直下にgatsby-node.jsというファイルが用意されており、デフォルトでは空ですが、ここでページの自動生成を設定できます。
下記のサンプルコードでは、GraphQLで店舗・記事の一覧をいったん取得し、それぞれをGatsbyの「createPage」関数に渡して、URLやテンプレートファイル、テンプレートに渡すコンテキストデータを指定しています。
/gatsby-node.js const path = require(`path`) exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions const result = await graphql(` query MyQuery { allStrapiShop { edges { node { strapiId name } } } allStrapiArticle { edges { node { strapiId title } } } } `) result.data.allStrapiShop.edges.forEach( ({node}) => { createPage({ path: `/shop/${node.strapiId}`, component: path.resolve(`src/templates/shop.js`), context: { id: node.strapiId, title: node.name, }, }) }) result.data.allStrapiArticle.edges.forEach( ({node}) => { createPage({ path: `/article/${node.strapiId}`, component: path.resolve(`src/templates/article.js`), context: { id: node.strapiId, title: node.title, }, }) }) }
次に、テンプレートファイルを作っていきます。/src/templates/ ディレクトリを作成し、以下の2ファイルを格納しました。こちらもGraphQLでデータを取得し、Reactコンポーネントに渡してブラウザに表示させる内容です。
長いコードに見えてしまっていますが、こちらはゼロから書く必要はなく、Gatsby導入時に生成されるサンプルコードをもとに作っています。
/src/templates/article.js import React from 'react' import { Link, graphql } from 'gatsby' import SEO from "../components/seo" import Layout from '../components/layout' const ArticleTemplate = ({ data, pageContext }) => { return ( <Layout> <SEO title={pageContext.title} /> <h1>{data.strapiShop.name}</h1> <dl> <dt>住所</dt> <dd>{data.strapiShop.address}</dd> <dt>営業時間</dt> <dd>{data.strapiShop.open}〜{data.strapiShop.close}</dd> <dt>電話番号</dt> <dd>{data.strapiShop.phone}</dd> <dt>メールアドレス</dt> <dd>{data.strapiShop.email}</dd> </dl> <div> {data.strapiShop.description} </div> <dl> {Object.entries(data.strapiShop.menu).map( ([food, price]) => { if(price !== null) {return (<dl><dt>{food}</dt><dd>{price}</dd></dl>)}} )} </dl> <ul> {data.strapiShop.articles.map( a => { return( <li key={a.id}><Link to={"/article/"+a.id}>{a.title}{a.created_at}</Link></li> ) })} </ul> </Layout> ) } export default ArticleTemplate export const query = graphql` query ShopTemplate($id: Int!) { strapiShop(strapiId: {eq: $id}) { strapiId name address email open(formatString: "kk:mm") close(formatString: "kk:mm") description phone menu { coffee cafe_au_lait tea cheese_cake morning_set boiled_egg } articles { id title created_at(formatString: "YYYY/MM/DD") } } } `
これで個別ページができるはずです!
「localhost:8000/article/3」
同様に、shopについても作っています。
ステップ10:トップページを作ってみる
トップページには記事一覧と店舗一覧を表示させ、各ページへのリンクを貼りたいと思います。今後コンテンツが増えた場合に、別で一覧ページを設けるなど色々と使い回す可能性があるので、トップページに直接書かずにコンポーネントを作ってみます。
/src/components/ディレクトリ以下で、「Articlelist」「Shoplist」コンポーネントを作成します。こちらの内容も、GraphQLで取ったデータをReactで処理する、といったものになります。
src/components/articlelist.js import { Link } from "gatsby" import React from "react" import { useStaticQuery, graphql } from "gatsby" const Articlelist = () => { const data = useStaticQuery(graphql` query articlelistQuery { allStrapiArticle(sort: {fields: created_at, order: DESC}) { totalCount nodes { strapiId title created_at(formatString: "YYYY/MM/DD") } } } `) return ( <ul> {data.allStrapiArticle.nodes.map( e => { return ( <li key={e.strapiId}> <Link to={"article/" + e.strapiId}> <span>{e.title}</span><span>{e.created_at}</span> </Link> </li> )})} </ul> ) } export default Articlelist
ShopListもほぼ同じです。トップページで読み込んで表示させてみます。
src/pages/index.js import React from "react" import Layout from "../components/layout" import SEO from "../components/seo" import Shoplist from "../components/shoplist" import Articlelist from "../components/articlelist" const IndexPage = () => ( <Layout> <SEO title="Home" /> <h1>Hi people</h1> <Shoplist></Shoplist> <Articlelist></Articlelist> </Layout> ) export default IndexPage
表示はこんな感じになりました! もちろんリンクも踏めますよ!
スタイルについて、今回はデフォルトで用意されている共通レイアウト「/components/layout.css」にほとんどそのまま通していますが、こちらもCSS+Reactの技術で自由にデザインを実装することが可能です。
開発が終わったら
gatsby run build
コマンドで本番用のファイルを生成しましょう。/public/ディレクトリに、表記を圧縮した本番用のファイルができます。まるごとお好きなサーバーにアップすれば公開完了です!
またFirebaseやNetlifyなどの「静的サイトホスティングサービス」と連携し、「CMSのコンテンツを更新すると、自動で本番サイトが更新される」というような仕組みを作ることもできます。
今回はここまで触れられませんが、機会があれば詳しくご紹介したいと思います!
まとめ: Strapi今後の展望
いかがでしたでしょうか。環境構築の手間を抑え、様々な規模や局面に対応できるHeadless CMSとして、Strapiをご紹介してきました。
今回はモダンなReactフレームワークであるGatsbyと組み合わせることで、コンテンツを使ったウェブサイトの制作もおこないました。
Strapiは現在も開発が進んでおり、APIアクセストークン、高機能なHTMLエディタ、コンテンツの多言語化機能、下書き機能など、さまざまな機能が追加される予定です。また、Headless CMSのなかでも随一の柔軟なカスタム性を持っているところも、世界のエンジニアから熱い注目を浴びているポイントです。
将来性のある話題のツールとして、ぜひ覚えておいていただければと思います!