デザイン部でフロントエンドエンジニアをしているkitoです。
近年のCMS界隈には、いわゆるHeadless化の波がきています。CMSのHeadless化とは、CMS(Content Management System)からクライアントサイドを切り離し、クライアントサイドのフレームワークでUIを構築するアーキテクチャです。
デカップルド・アーキテクチャと呼ばれることがあるようですが、サーバサイドとクライアントサイドがAPIを通じてコンテンツをやりとりすることで、Webアプリだけではなくてネイティブアプリからの要求にも適切に答えられるようになります。スケーリングに関しても、Headless CMSの方が取り回しが良いのではないでしょうか。
WordpressがWP REST APIを開発し、Headless化へと道筋をつけたことは特筆すべきです。WP REST APIの公式サイトでは、冒頭に「WordPress はアプリケーションフレームワークへと生まれ変わろうとしています。」と気負って書かれています。
とはいえ、Headless CMSの主役が、WordPressになるかどうかは未知数です。WordPressのエコシステムは巨大で、蓄積されたリソースは非常に豊かであると思いますが、クライアントサイドのフレームワークとの相性は、おそらく現時点ではReact.jsやVue.jsの周辺から派生してきたHeadless CMSの方が優っているのではないかと思います。
今回は、まだalpha版ですが使ってみて好感触だったstrapiというHeadless CMSと、クライアントサイドはVue.jsのフレームワークでSSR(サーバーサイドレンダリング)に対応しているNuxt.jsをあわせて使ってみたいと思います。
strapi
まずHeadless CMSのstrapiをインストールします。(Node.js 10.x以上、NPM 6.x以上が必要になります)
npm install strapi@alpha -g
インストールできているか確認します。
strapi -v
インストールされていれば、「3.0.0-alpha.x」のようなバージョン番号が表示されます。
データベースを任意に作成してください。MongoDBやPostgreSQLも使えますが、今回はMySQLを使います。
mysql -u root -p mysql> create database strapi_db;
下記コマンドでアプリを作成していきます。 my-project以下にstrapiとnuxt.jsをそれぞれインストールします。
mkdir my-project cd my-project strapi new strapi
使用するデータベースを聞かれるので、MySQLを選択します。
Lets configurate the connection to your database: Choose your main database: MongoDB Postgres ❯ MySQL
データベースの名前を入力してください。
Database name: strapi_db
続いて、Hostやport、UsernameとPasswordを聞かれるのでそれぞれ入力してください。
これでmy-project以下にstrapiがインストールされました。下記でstrapiを起動してみましょう。
cd strapi strapi start
ブラウザが自動で起動するのでユーザ名、パスワード、メールアドレスを入力し「Ready to start」をクリックしてください。
下記のようなadmin画面にログインできます。これでstrapiのインストールは完了です。続いてデータを入力します。
コンテンツタイプ作成から「コンテンツタイプを追加」をクリックします。今回は名前をpostにします。次に「新しいフィールドを追加」を選択し、Stringをクリックして名前を「title」と入力します。続いて、textを選択して「content」、メディアを選択して「cover」と入力します。(「保存」のクリックを忘れないようにしましょう)
次にロールと権限から、Public > Postの権限を変更します。今回はスクリーンショットのようにすべてOKにしてあります。
サイドカラムにあるCONTENT TYPESの箇所にPostがあると思います。そこから、実際のデータを適当に入力してください。
http://localhost:1337/postsにアクセスすると、下記のような先ほど入力したデータがjson形式で表示されるでしょう。これでstrapiの設定は完了です。次にNuxt.jsのインストールです。
[ { "id": 1, "title": "タイトル1", "content": "テキスト1テキスト1", "created_at": "2019-01-15T05:14:40.000Z", "updated_at": "2019-01-15T05:14:40.000Z", "cover": { "id": 1, "name": "150x150.png", "hash": "cffd30f367994f9788ca31c4ab0018af", "sha256": "Lny0dZHead23KZOVGlnYl7e0FTu-FQqzmeokqqZJZxE", "ext": ".png", "mime": "image/png", "size": "0.86", "url": "/uploads/cffd30f367994f9788ca31c4ab0018af.png", "provider": "local", "public_id": null, "created_at": "2019-01-15T05:14:40.000Z", "updated_at": "2019-01-15T05:14:40.000Z" } }, { "id": 2, "title": "タイトル2", "content": "テキスト2テキスト2", "created_at": "2019-01-15T05:15:14.000Z", "updated_at": "2019-01-15T05:15:14.000Z", "cover": { "id": 2, "name": "150x150.png", "hash": "4646c71aaeee40f687cd263cf6afd9f2", "sha256": "Lny0dZHead23KZOVGlnYl7e0FTu-FQqzmeokqqZJZxE", "ext": ".png", "mime": "image/png", "size": "0.86", "url": "/uploads/4646c71aaeee40f687cd263cf6afd9f2.png", "provider": "local", "public_id": null, "created_at": "2019-01-15T05:15:14.000Z", "updated_at": "2019-01-15T05:15:14.000Z" } }, { "id": 3, "title": "タイトル3", "content": "テキスト3テキスト3", "created_at": "2019-01-15T05:15:31.000Z", "updated_at": "2019-01-15T05:15:31.000Z", "cover": { "id": 3, "name": "150x150.png", "hash": "436a2f656ea843f8bb1eda6f2b404794", "sha256": "Lny0dZHead23KZOVGlnYl7e0FTu-FQqzmeokqqZJZxE", "ext": ".png", "mime": "image/png", "size": "0.86", "url": "/uploads/436a2f656ea843f8bb1eda6f2b404794.png", "provider": "local", "public_id": null, "created_at": "2019-01-15T05:15:31.000Z", "updated_at": "2019-01-15T05:15:31.000Z" } } ]
Nuxt.js
先ほど設定したstrapiのjsonデータを、Nuxt.jsで取得して表示させます。 まずmy-projectにNuxt.jsをインストールします。yarnもしくはnpxが必要です。 my-project直下で下記コマンドを実行してください。Use axios moduleはyesにして、それ以外はdefaultでOKです。
yarn create nuxt-app nuxtjs cd nuxtjs npm run dev
http://localhost:3000/ にブラウザでアクセスすると下記のように表示されると思います。これでNuxt.jsのインストールは完了です。
次に、/my-project/nuxtjs/pages にposts.vueファイルを作成して、下記コードを記述してください。 Nuxt.jsは、pages以下のvueファイルとurlが連動するようにルーティングされる規約なので、http://localhost:3000/posts のファイルを作成していることになります。
<template> <section class="container"> <ul> <li v-for="post in posts" :key="post.id">{{post.id}}:{{post.title}}、{{post.content}}、<img :src="`http://localhost:1337/${post.cover.url}`"></li> </ul> </section> </template> <script> import axios from 'axios' export default{ async asyncData({app}){ let res = await axios.get('http://localhost:1337/posts') return {posts : res.data} } } </script>
asyncDataは、Nuxt.jsのメソッドでページコンポーネントがロードされる前に呼び出され、ここでgetしたpostsデータはSSR(サーバサイドレンダリング)されます。strapiとnuxt.jsを起動させた状態で、
http://localhost:3000/postsにアクセスすると、先ほど入力したデータが表示されていると思います。(ブラウザでソースを見て頂ければわかりますが、SSRされています)
これだと流石に見た目がアレなので、Bootstrapで少しスタイルを修正します。
/my-project/nuxtjs/nuxt.config.js のlinkにbootstrapのcssを追加します。
head: { title: pkg.name, meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: pkg.description } ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: 'stylesheet', href: 'https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css' } ] },
/my-project/nuxtjs/layouts/default.vueのtemplateにnavを追加
<template> <div> <nav class="navbar navbar-light bg-dark"> <a class="navbar-brand text-light" href="#"> strapi + Nuxt.js </a> </nav> <nuxt/> </div> </template>
/my-project/nuxtjs/pages/posts.vueを下記のように変更します。
<template> <div class="container"> <div class="starter-template"> <div class="card-deck"> <div class="card" v-for="post in posts" :key="post.id"> <img class="card-img-top" :src="`http://localhost:1337/${post.cover.url}`"> <div class="card-body"> <h5 class="card-title">{{post.title}}</h5> <p class="card-text">{{post.content}}</p> </div> </div> </div> </div> </div> </template> <script> import axios from 'axios' export default { async asyncData({app}) { let res = await axios.get('http://localhost:1337/posts') return {posts: res.data} } } </script> <style> .starter-template { padding: 3rem 1.5rem; text-align: center; } </style>
strapiはcmsなので、もちろん画像やテキストを先ほどのadmin画面から変更できます。
手順としては多少長いですが、思いのほか簡単にインストールできたのではないでしょうか。
個人的には、strapiとNuxt.jsで旧来のモノリシックなCMSでは得られない風通しの良さを感じました。CMSとクライアントサイドが疎結合になることで、必要であればCMS側だけを変更したり、クライアントサイドのフレームワークを変更できるようになります。また、Nuxt.jsのようなクライアントサイドのフレームワークを導入することでGoogle的に質の高いサイトを低コストで構築可能で、メリットは大きいでしょう。
アスタミューゼでは、エンジニア・デザイナーを募集中です。ご興味のある方は遠慮なく採用サイトからご応募ください。お待ちしています。