Heroku上でNuxt.js を使ってサーバサイドレンダリング(SSR)

サーバサイドレンダリングにチャレンジしてみたかったのです。 (やってみたいだけ)

Vue.jsにサーバサイドレンダリング専用のWebサイトがあったのですが、どうやらNuxt.jsの方が簡単にサーバサイドレンダリングできるようです(Vue.jsでもできなくはないけどWebpackの知識が多分に必要らしいのです。。。私そこまでまだ知識ない)。

Nuxt.jsはVue.jsをベースにしたフレームワークですので、Vue.jsを触り始めたばかりの私でも幾分できるのではないか、と、淡い期待を込めて。Nuxt.jsにチャレンジしてみます。

Nuxt.jsの公式ガイドはこちら

ja.nuxtjs.org

になります。

インストール

npmがインストールされていることを前提とします。

$ npx create-nuxt-app .

"."にすると現在のディレクトリに作成されます。新規でディレクトリ作りたければ、ディレクトリ名を与えてください。

コマンドを叩くといろいろ聞かれます。私は下のように答えました。

  • Project name:(お好きなものを)
  • Project description: (お好きな説明を)
  • Use a custom server framework: express
  • Choose features to install: (なし)
  • Use a custom UI framework: bootstrap
  • Use a custom test framework: jest
  • Choose rendering mode: Universal
  • Choose a package manager: npm

インストールすると下記のようなディレクトリ構成になります。

├── assets
├── components
├── layouts
├── middleware
├── node_modules
├── pages
├── plugins
├── server
├── static
├── store
├── test
├── README.md
├── nuxt.config.js
├── jest.config.js
├── package-lock.json
└──package.json

Vue.jsやexpressで見たことあるような階層ですね。

ディレクトリが何を格納しているのかは公式ページ(ディレクトリ構造 - Nuxt.js )で確認することができます。

ローカルで動作確認

下記コマンドを打ちます。

$ npm run dev

http://localhost:3000/にアクセスすると初期画面が見られます。

Vue.jsのときと違って、Vueのロゴが動きますね。 (nuxt.jsのロゴがVue.jsのロゴを元に作られているのをこのとき初めて知りました)

Herokuへデプロイ

公式のWebサイトにHerokuへのデプロイ手順が載っています(https://ja.nuxtjs.org/faq/heroku-deployment/)。 最新情報はこちらを確認したほうが良いと思います。

ここでは私がやった手順のみ並べます。

Herokuに下記3つの環境変数をセットします。

$ heroku config:set NPM_CONFIG_PRODUCTION=false -a (アプリ名)
$ heroku config:set HOST=0.0.0.0 -a (アプリ名)
$ heroku config:set NODE_ENV=production -a (アプリ名)

1つ目の環境変数はnpm run buildの前に、毎度npm installを実行するようにするための設定だそう。

次にpackage.jsonにheroku-postbuildを追加します。

// package.json

// ----------(略)------------------
"scripts": {
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
    "build": "nuxt build",
    "start": "cross-env NODE_ENV=production node server/index.js",
    "heroku-postbuild": "npm run build",  // <-この行を追加
    "generate": "nuxt generate",
    "test": "jest"
  },
// ----------(略)------------------

そして最後にルートに「Procfile」を置きます。

// Procfile
web: npm run start

Herokuのリポジトリにpushし、デプロイ。

アプリのサイトにアクセスし、ローカルで見たのと同じサイトが表示されればOKです!お疲れ様でした。

Vue CLI3 とBootstrap

Vue CLI3でBootstrapを導入してみます。 といってもやったことは公式ページ(BootstrapVue)に書いてあることそのままです。

インストール

npmでインストール。

$ npm i vue bootstrap-vue bootstrap

import

Vueのメインファイル(srcディレクトリ直下のjavascriptファイル。私の環境ではmain.jsファイルがそれに該当します)でbootstrap-vueおよび関連するCSSをimportします。さらにVue.useでbootstrap-vueを指定します。

// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

// ここから
import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.use(BootstrapVue)
// ここまで
Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  router,
}).$mount('#app')

テスト

app.vueファイルのhtml部分に下記を記述します。

<template>
  <div id="app">
    <b-button>Button</b-button>
    <b-button variant="danger">Button</b-button>
    <b-button variant="success">Button</b-button>
    <b-button variant="outline-primary">Button</b-button>
  </div>
</template>

手元で「npm run serve」してみて、ブラウザからアクセスし、左から順に灰色、緑、赤、白地に青縁取りのBootstrap仕様のボタンが出てきたらOK。

Vue.js + Express + Herokuでwebアプリを作る

フロントエンドはVue.jsで作ります。 本記事はとりあえずVue.jsプロジェクトを作成して、Herokuで見られるようにするところまでの手順をまとめます。

前提

  • 開発マシンにNode.jsがインストール済み
  • 開発マシンでnpmが使える

Vue.jsプロジェクトの作成

まず、vue-cliをインストールします。ローカルマシンでのみグローバルに使うのでオプションは-gにしてます。

$ npm install -g @vue/cli

次に開発を行うディレクトリに移動し、次のコマンドを叩きます。

$ vue create .

カレントディレクトリにVueプロジェクトを構築したかったので、「.」を指定していますが、新規でディレクトリを作りたければ「.」を「ディレクトリ名」に置き換えてください。ディレクトリ名を指定すると、ディレクトリ名のディレクトリを作成して、その中にVueプロジェクトを構築してくれます。

Webサーバーの構築

Herokuで公開するためにWebサーバーをExpressで構築します。 app.jsファイルに以下を記述。

/* app.js */
var express = require('express');
var app = express();

app.set('port', (process.env.PORT || 8080));
app.use(express.static(__dirname + '/dist/'));
app.listen(app.get('port'));

package.jsonの修正

Herokuがアプリ起動時に実行する処理をpackage.jsonに記載します。

/* package.json */
...........(略)..................
"scripts": {
    ...........(略)..................
    "start": "node app.js"        // ←この行を追加
  },
...........(略)..................

Gitにアップロード/デプロイ

あとはgitにpushして、Heroku上でデプロイをするだけです。 アプリのURLにアクセスすると、Vueのデフォルトのトップ画面(「Welcome to Your Vue.js App」というページ)が見られると思います。

ローカルで試したい場合には

$ npm run build
$ npm run serve

を実行後、ブラウザで「http://localhost:8080/」にアクセスすると見ることができます。

SequelizeでHerokuのPostgreSQL接続

DBとのデータのやり取りでSequelizeを使うことにしました。 いろいろハマったのでメモ代わりに残しておきます。

目的

  • SequelizeでHeroku上のPostgreSQLにデータをinsert、select、deleteする。

インストール

Sequelizeをインストールします。

$ npm install --save sequelize

DBがPostgreなのでpg, pg-hstoreをインストールします。

$ npm install --save pg pg-hstore

使っているDBがPostgre以外の場合には、使っているDBに合わせてライブラリをインストールしてください。 インストールしなければならないライブラリはSequelizeの公式サイト(Manual | Sequelize)に載っています。

使用方法

テーブルの作成

データベースに次のようなテーブルを作成したとします。

/* create-table.sql */
create table schema.users (
    id         serial,
    created_at  timestamp with time zone not null default current_timestamp,
    updated_at timestamp with time zone not null default current_timestamp,
    primary key(id)
);

Sequelize:モデルの作成

まずはこのtableにアクセスするためのモデルを作成します。

/* models/user.js */
const Sequelize = require("sequelize");

class User extends Sequelize.Model {
    static init(sequelize) {
        return super.init({
            id: {
                type: Sequelize.INTEGER,
                primaryKey: true,
                autoIncrement: true,
            },
            created_at: Sequelize.DATE,
            updated_at: Sequelize.DATE,
        }, {
            schema: 'schema',
            tableName: 'users',
            timestamps: false,
            freezeTableName: true,
            sequelize ,
        })
    }
}

module.exports = User;

serial型のidには「autoIncrement: true」を指定が必要です。指定しないとinsert時に次のようなエラーを吐きます。

Unhandled rejection SequelizeDatabaseError: null value in column "id" violates not-null constraint

PostgreSQLのserial型はnot null相当なので何の値も指定していないと、Sequelizeがエラーを吐くわけです。autoIncrementを指定することによってSequelizeに自動採番である旨を定義することができ、エラーを吐かなくなります。

Sequelize: データベース接続 & insert/select/destroy

次に実際にモデルを使用してみます。

/* user.js */
var pg = require('pg');
pg.defaults.ssl = true;
const Sequelize = require('sequelize');
const User = require('models/user');

function databaseTest(request) {
    const seq = new Sequelize(
        // 「heroku config -a (アプリ名)」で出てきた「DATABASE_URL」の値を記入
        'postgres://(user):(password)@(host):(port)/(database)',
    );
   // さっき宣言したモデルの呼び出し
    const user = User.init(seq);

    var current = new Date();

    // データをinsert
    user.create({
        created_at: current,
        updated_at: current,
    })
    .then((result) => Promise.resolve(result.id))
    // データをselect
    .then((userId) => user.findOne({
        where: {
            id: userId
        }
    }))
    .then((result) => {
        console.log(result)
        return Promise.resolve(result.dataValues.id)
    })
    // データをdestroy
    .then((userId) => user.destroy({
        where: {
            id: userId
        }
    }));
}

databaseTest();

pg.default.sslをtrueにセットする必要があったのですが、それに気がつかず、エラーで何度もハマりました。

さて、これで最低限アクセスできるようになりました。

今回はやっていないけれどちゃんとトランザクション張った処理もできます。 Promiseで返ってくるから同期処理もやりやすいし、クラス定義っぽくアクセスできるし便利。

herokuでバックエンド作成

お仕事でjavascriptを使っているのもあり、バックエンドもjavascriptで作成します。

Node.js + Expressの環境構築

Expressを使ったことないけど、使ってみます。主に下記サイトを参考に環境を立ち上げました。

https://qiita.com/hkusu/items/e46de8c446840c50aefe

ほとんど上記のブログのままに実施しました。 一点だけ違いは、herokuではなくgithub経由でデプロイすることにしたので、 git push heroku masterではなく、githubにpush→masterブランチへプルリク→herokuのwebアプリから手動でデプロイ指示、としました。

アプリURLにアクセスして「Hello word」が表示されているのを確認して、完了です。

masterブランチから自動でデプロイすることも可能だけれど、現在はまだお試し段階なので、 しばらくは手動でいいかな。そのうち自動に切り替えます。

herokuでパスワードやデータベースのアクセス情報などをどう管理するか

herokuへデプロイするのにgithubを使っています。 Webアプリを作っていますので、データベースへのアクセス情報なんかが必要になるわけです。 デプロイ用リポジトリはプライベートリポジトリにしていますが、パスワードやアクセス情報なんかはやっぱりpushしたくない。 しかし、herokuで内部変数みたいなのってどうやって持つの.....?

と思って調べてみたら、herokuの各アプリに環境変数を設定できるみたいです。

環境変数はheroku login後、下記コマンドでセットできます。

$heroku config:set 環境変数名=値 --app アプリ名

環境変数一覧は下記コマンドで見られます。

$heroku config --app アプリ名

ちなみにpostgreへのアクセス用URLはすでに環境変数に登録されていました。 add-onとしてインストールすると、自動で環境変数が登録されるみたいですね。便利。

HerokuでPostgre SQL

Web周りのお勉強がしたいと思い、Herokuに登録しました。 とりあえずまず、データベースとしてPostgre SQLにチャレンジしてみます。

Postgre SQLの登録

  1. Herokuに新規アプリケーションを作成
  2. アプリケーションのページへ移動
  3. 「Resources」タブのadd-on追加より「Heroku Postgres」を追加

Postgres SQLのインストール

  1. Macの場合、下記コマンド

     $ brew update
     $ brew install postgresql
    
  2. Windowsの場合、PostgreSQLのサイトからインストーラをダウンロードし、インストール。その後、Pathを通します。Pathは「コントロールパネル>ユーザーアカウント>環境変数の設定」から設定できます。Pathを通すディレクトリは下記のような感じ。

     C:\Program Files\PostgreSQL\(バージョン)\bin
    

Postgre SQLへの接続

  1. HerokuのWebサイト上の、アプリケーションのページへ移動
  2. 「Settings」タブの「Config Vars」にデータベースの接続情報が下記形態で書かれています。

     postgres:// username:password@hostname:port/databasename
    
  3. 下記コマンドでPostgre SQLへ接続 (hostname、username、databasenameは上で調べたものに置き換えてください)

     $ psql -h hostname -U username -d databasename
    
  4. パスワードを求められたらpasswordを入力

あとがき

  • URLによると、HerokuのPostgresはAmazonのec2上で動いているみたい?知らなかった