netlify で lambda が使えるようになったので、静的サイト & シンプルなAPI のWebサイトを構成してみようと思い、実践的な内容も踏まえて挑戦してみました。
Lambda On Netlify の詳細に関しては以下を参照。
今回は Connpass API を使って、 Connpass のイベント情報を表示するSPAを作成します。
環境構築
とりあえず nuxt テンプレートを生成
$ vue init nuxt-community/pwa-template myapp
$ cd myapp
$ npm i
必要モジュールをインストール
$ npm i babel-core babel-loader netlify-lambda
$ npm i axios
Lambda 関数の作成
まずは API から作っていきます。裏で Connpass API を叩く部分は再利用可能にしたいので、Lambda のエントリからは分離しておきます。
$ mkdir src
$ mkdir service
$ touch src/events.js
$ touch service/http.js
const axios = require('axios')
exports.api = () => {
const url = 'https://connpass.com/api/v1/event/'
const params = {
series_id: 1712 // PUT YOUR SERIES ID
}
return axios.get(url, {params}).then((result)=>{
return result.data.events
})
}
exports.handler = (event, context, callback) => {
exports.api().then((result) => {
console.log(result)
callback(null, {
statusCode: 200,
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(result)
})
})
}
netlify-lambda serve src
で疎通を確認してください。
環境変数を利用する
series_id などを 柔軟に変更したいので、dotenv-module
を利用して環境変数を参照します。
$ npm i @nuxtjs/dotenv
.env ファイルを作成して、イベントIDを環境変数で記録します。
CONNPASS_SERIES_ID=1712
.env
は忘れずに ignore に入れておきましょう。
ただ、nuxt 側では、モジュールを利用して.env
を参照出来るものの、 netlify-lamdba serve
では .env
を認識しません。
Nuxtのモジュールの中身は dotenv が入るだけなので、以下のコマンドで .env を食わせながら、netlify-lamdba コマンドを実行出来ます。
$ node -r dotenv/config ./node_modules/.bin/netlify-lambda serve src
準備ができたところで、service/http.js
の中身を以下の様に書き換えます。
exports.api = () => {
const url = 'https://connpass.com/api/v1/event/'
const params = {
series_id: process.env.CONNPASS_SERIES_ID
}
return axios.get(url, {params}).then((result)=>{
return result.data.events
})
}
セキュアな情報でもないので、配信時の環境変数は、netlify.toml
に記述しておきます。
[build]
Command = "npm run build"
functions = "functions"
publish = "dist"
[context.production]
[context.production.environment]
CONNPASS_SERIES_ID="1712"
toml 側に数値を書くとエラーになる?っぽいので、 ""
で囲っておく必要があります。
npm run build
をビルドコマンドにしているため、 package.json
側には
"scripts": {
....
"build": "touch .env && netlify-lambda build src && nuxt generate",
....
},
のような設定を入れておきます。
以上を netlify 側に deploy してうまいこと動くこと確認できたらOKです。
Nuxt 側の開発
次は、Nuxt 側の開発です。
まずローカル環境で API を Proxy したいので, @nuxtjs/proxy
を入れます。
$ npm i @nuxtjs/proxy
modules に @nuxtjs/dotenv
も合わせて設定を追加します。
modules: [
'@nuxtjs/dotenv',
'@nuxtjs/proxy',
....
],
proxy: {
'/events': 'http://localhost:9000'
}
とりあえず 簡単な store を作成します。
import axios from 'axios'
export const state = () => ({
events: []
})
export const getters = {
eventById: (state) => (id) => {
for (let event of state.events) {
if (event.event_id === parseInt(id)) {
return event
}
}
return false
}
}
export const mutations = {
ADD_EVENTS (state, events) {
state.events = events
}
}
export const actions = {
async LOAD_EVENTS ({commit}) {
const result = await axios.get('/events', {
baseURL: process.env.FRONT_API_URL
})
commit('ADD_EVENTS', result.data)
return result.data
}
}
process.env.FRONT_API_URL
は API のURL です。とりあえず以下のように .env
に追加します。
CONNPASS_SERIES_ID=1712
FRONT_API_URL=http://localhost:3000
netlify.toml 側では以下のようにします。
[context.production]
[context.production.environment]
CONNPASS_SERIES_ID="1712"
FRONT_API_URL="https://{YOUR_SITE_NAME}.netlify.com/.netlify/functions"
.envの内容は ブラウザ側では動作しないため、 nuxt.config.js に以下のような指定をして、コンパイルのJS内に組み込んでもらいます。
env: {
FRONT_API_URL: process.env.FRONT_API_URL
},
トップのイベント一覧ページの .vue は次のような script 構成になります。
export default {
data () {
return {}
},
computed: {
events () {
return this.$store.state.events
}
},
async fetch ({store}) {
await store.dispatch('LOAD_EVENTS')
}
}
イベントの個別ページは次のような形です。
export default {
data () {
return {}
},
computed: {
eventId () {
return this.$route.params.eventId
},
event () {
const event = this.$store.getters.eventById(this.eventId)
return event
},
},
async fetch ({store, params}) {
const event = store.getters.eventById(params.eventId)
if (event === false) {
await store.dispatch('LOAD_EVENTS')
}
}
}
注意が必要なのは、 fetch 内で this.$store
などが使えない点です。
generate 向けの設定
最後に動的なルートを描画出来るように、generate オプションを指定します。
generate: {
routes (callback) {
const {api} = require('./src/events')
require('dotenv').config()
return api().then((result) => {
const routes = result.map((event) => {
return `/event/${event.event_id}`
})
callback(null, routes)
}).catch(callback)
}
},
@nuxt/dotenv は公式サイトにも以下の記述があるように、ビルドフェーズで動作しないため、明示的にコレを読み込む必要があります。
The dotenv-module won't overload the environment variables of the process running your build.
以上で構築は完了です。
うまいこと レンダリングされた、静的ページが複数生成されると思います。
後で暇があったらデザイン整えて netlify buttonにして公開しようと思います。
(誰かやる気の出るデザインを下さい。)