Vue.js と microCMSでブログを作ってNetlifyにデプロイする
はじめに
動機
友達がポートフォリオサイトを作りたいと言っていたので、以下の要件でどうサイトを作るか考えて、Vue.js と microCMS、Netlify を使おうと思い、試しにブログ風のサイトをつくりました。本記事はそれのアウトプットです。
要件
- プログラミングの知識がなくてもサイトを更新できる。
- 個人的にWordPress は興味が湧かないので使いたくない。ヘッドレス CMS 使ってみたい。
- 業務でも触れている Vue.js を使いたい。
- できるだけお金をかけない方法が良い。
今回作るもの
ブログっぽいサイト。とりあえず記事一覧と記事詳細画面を作ります。
サイトを作る
Netlify へのデプロイ時に Github を連携させるので、repositoryの 作成、commit, push はよしなにやってください。
vue をインストールしていない場合は、こちらを参考にインストールお願いします。https://jp.vuejs.org/v2/guide/installation.html
この記事を書いたときのvue cliのversionは3.11.0
でした。
プロジェクト作成
それでは作っていきます。
$ vue create my-blog
Please pick a preset
と聞かれますが、こだわりがなければ default (babel, eslint)
で良いと思います。
成功したよと表示されたら、動くか確認しましょう。
$ cd my-blog
$ npm run serve
http://localhost:8080/
に Vue のロゴ等が表示されたら OK です。
Vuetify を入れる
次にデザインを楽して綺麗に整えたいので、Vuetify を入れます。
必須ではないですが、これからは Vuetify を使っている前提で書いてきます。
$ vue add vuetify
Choose a preset: (Use arrow keys)
❯ Default (recommended)
インストールできたら npm run serve
をして、またhttp://localhost:8080/
を見てみます。Vuetify のロゴ等が表示されていたら OK です。
Vue Router を入れる
ページ遷移するためにVue Router を入れます。
$ vue add router
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
これで下準備が整いました。
ナビゲーションを整える
Vuetify App barsを使ってナビゲーションを整えましょう
<template>
<v-app>
<v-container>
<!-- スタイルは本記事のメインではないので雑に設定しています。この辺りもお好みで! -->
<v-app-bar color="#FFFFFF" flat max-height="100" class="mb-5">
<v-toolbar-title>
<h1><router-link to="/" class="logo">ブログ!</router-link></h1>
</v-toolbar-title>
<v-spacer></v-spacer>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
</v-app-bar>
<router-view />
</v-container>
</v-app>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
a {
color: #2c3e50;
text-decoration: none;
}
}
#nav {
padding: 30px;
.router-link-exact-active {
color: #42b983;
}
}
</style>
ヘッダーがこんな見た目になったと思います。
記事一覧画面を作る(トップページ)
vue-router を入れたときに作られた Home.vue を記事一覧画面にしていきます。
レイアウトには Vuetify のCardsを使っています。
また複数のカードを並べて表示するのでグリッドシステムのv-row, v-col を使っています。
雑に複数のカードを並べてみましょう。
<template>
<div>
<v-row>
<v-col>
<v-card class="mx-auto" width="300" height="330">
<v-img
class="white--text align-end"
height="200px"
src="https://cdn.vuetifyjs.com/images/cards/docks.jpg"
>
<v-card-title>Top 10 Australian beaches</v-card-title>
</v-img>
<v-card-text class="text--primary">
<div>Whitehaven Beach</div>
<div>Whitsunday Island, Whitsunday Islands</div>
</v-card-text>
<v-card-actions>
<v-btn color="orange" text>More</v-btn>
</v-card-actions>
</v-card>
</v-col>
<v-col>
<v-card class="mx-auto" width="300" height="330">
<v-img
class="white--text align-end"
height="200px"
src="https://cdn.vuetifyjs.com/images/cards/docks.jpg"
>
<v-card-title>Top 10 Australian beaches</v-card-title>
</v-img>
<v-card-text class="text--primary">
<div>Whitehaven Beach</div>
<div>Whitsunday Island, Whitsunday Islands</div>
</v-card-text>
<v-card-actions>
<v-btn color="orange" text>More</v-btn>
</v-card-actions>
</v-card>
</v-col>
<v-col>
<v-card class="mx-auto" width="300" height="330">
<v-img
class="white--text align-end"
height="200px"
src="https://cdn.vuetifyjs.com/images/cards/docks.jpg"
>
<v-card-title>Top 10 Australian beaches</v-card-title>
</v-img>
<v-card-text class="text--primary">
<div>Whitehaven Beach</div>
<div>Whitsunday Island, Whitsunday Islands</div>
</v-card-text>
<v-card-actions>
<v-btn color="orange" text>More</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: "Home"
};
</script>
こんな見た目になったと思います。
記事詳細画面を作る
次に記事の詳細画面を作ります。
ファイルを用意します。
$ touch src/views/ArticleDetail.vue
<template>
<v-card flat>
<v-img
height="400"
src="https://cdn.vuetifyjs.com/images/cards/docks.jpg"
></v-img>
<v-card-title>Top 10 Australian beaches</v-card-title>
<v-card-text>
<div>Whitehaven Beach</div>
<div>Whitsunday Island, Whitsunday Islands</div>
</v-card-text>
</v-card>
</template>
<script>
export default {
name: "ArticleDetail"
};
</script>
コンポーネントの準備ができたらルーティングを設定します
import Vue from "vue";
import VueRouter from "vue-router";
const Home = () => import("../views/Home.vue");
const About = () => import("../views/About.vue");
const ArticleDetail = () => import("../views/ArticleDetail.vue");
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home
},
// Aboutページは作りませんが、vue-routerを入れたときに作られていたのでそのままにしています。
// 必要に応じて設定してください。
{
path: "/about",
name: "About",
component: About
},
{
path: "/articles/:id",
name: "article-detail",
component: ArticleDetail
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
コンテンツを入れる
microCMS に登録 & サービスを作成する
microCMS のアカウントを作ります。そして、サービスを作成します。
公式ブログの説明が分かりやすかったので、こちらを見ていただければと思います。
ブログの記事を登録して、API を作成する
それでは記事を取得するためのAPIを作成します。
API名とエンドポイントを決めます。
複数の記事を取得したいので、リスト形式にします。
APIスキーマを以下のように定義します。
記事を登録しましょう。
記事を取得して表示する
microCMS に登録した記事を API 経由で取得して、表示できるようにします。
microCMS の API キーを取得してください。
左上の歯車アイコンをクリックすると設定画面に飛ぶので、API-KEY を表示してコピーしてください。
API-KEY は env ファイルに書いておきます。
$ touch .env.local
VUE_APP_X-API-KEY=コピーしたAPIキーをペースト
そして、API からデータを取得できるようにするために、今回は HTTP クライアントのaxiosを使います。
$ npm install axios
<template>
<div>
<v-row>
<v-col v-for="article in articles" :key="article.id">
<v-card class="mx-auto" width="300" height="330">
<v-img
class="white--text align-end"
height="200px"
:src="article.image.url"
>
<v-card-title>{{ article.title }}</v-card-title>
</v-img>
<v-card-text class="text--primary">
<div class="summary">{{ article.summary }}</div>
</v-card-text>
<v-card-actions>
<v-btn color="orange" text>More</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "Home",
data: () => ({
articles: []
}),
async mounted() {
// 記事を取得する
const response = await axios.get(
"https://my-blog-harasho.microcms.io/api/v1/articles",
{
headers: { "X-API-KEY": process.env.VUE_APP_X_API_KEY }
}
);
this.articles = response.data.contents;
}
};
</script>
<style scoped>
.summary {
white-space: pre-wrap;
}
</style>
画像
microCMS に登録した記事を取得できていることが確認できました。
記事一覧画面から詳細画面へのリンクを追加します。
<v-card-actions>
<!-- 詳細画面で記事を取得できるように、記事のidをパラメーターとして渡す -->
<router-link :to="{ name: 'article-detail', params: { id: article.id } }">
<v-btn color="orange" text>More</v-btn>
</router-link>
</v-card-actions>
記事詳細画面で、特定の記事を取得して表示できるようにします。
microCMS で記事に埋め込んだ画像を表示できるようにv-html
を使います。
記事は自身で作ったものですが、念のためサニタイズも行います。
$ npm install sanitize-html
<template>
<v-card flat>
<v-img height="400" :src="article.image.url"></v-img>
<v-card-title>{{ article.title }}</v-card-title>
<v-card-text>
<div v-html="sanitizedBody"></div>
</v-card-text>
</v-card>
</template>
<script>
import axios from "axios";
import sanitizeHtml from "sanitize-html";
export default {
name: "ArticleDetail",
data: () => ({
article: {}
}),
computed: {
sanitizedBody() {
// imgタグのみ使えるようにする
return sanitizeHtml(this.article.body, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"])
});
}
},
async mounted() {
// idを指定して特定の記事を取得する
const response = await axios.get(
"https://my-blog-harasho.microcms.io/api/v1/articles/" +
this.$route.params.id,
{
headers: { "X-API-KEY": process.env.VUE_APP_X_API_KEY }
}
);
this.article = response.data;
}
};
</script>
これで画面は完成とします。
デプロイする
Netlifyを使います。アカウントがある人はログイン。ない人は登録してください。
手順は次のようになります。
- 管理画面のトップページの New site from Git をクリック
- Github と連携
- デプロイするリポジトリを選択
- Basic build settings の Build command は npm run build, publish directory は dist にする
- show advanced -> New variable をクリックして、環境変数 VUE_APP_X_API_KEY を設定する
- Deploy Site をクリック
- サイトが公開されます!
※今後は 選択した branch に push するたびにサイトが更新されます。
※設定方法はこちらのサイトがわかりやすいです。
追加の設定
サイト上でリロードをしたり、 URL を直接指定すると、404 エラーとなります。
これは困るので、index.html を返すように、リダイレクトの設定を追加します。
$ touch public/_redirects
/* /index.html 200
あとがき
ざっくり作り終えて以下のやり残しがあるなと思いました。気が向いたら追加していきます…!
- API を何度も叩くのは無駄なので、Vuex などで管理して、できるだけ API を叩く回数を減らしたいです。
- APIから記事を取得できるまでの間は、ローディング画面など入れたいです。
- 404ページを作っていません。
- エラーハンドリングしていません。
- 記事が増えてきたら、ページネーションが欲しくなりますね。
- 実際にブログとして運用するとなったらSSR していないので SEO が少し不安です。
Discussion