はじめに
Nuxt.jsで作ったフロントエンドアプリを、Dockerイメージにビルドする方法を記載します。
簡単にできると思いきや、環境変数周りでいろいろはまったため、その点も備忘録として記載します。
Dockerfile
ビルド環境に依存しないよう、nuxtアプリのビルドもイメージビルド時にするようにしてます。
また、.dockerignore
を使うことで、コンテナ内で生成される各種ファイルが、ビルドコンテキストに追加されないようにしてます。
これがないと、ローカルのnode_modulesをビルドコンテキストにコピーしてしまうため、だいぶ遅くなります。
FROM node:10-alpine
WORKDIR /app
ENV NUXT_HOST 0.0.0.0
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
RUN yarn run build
EXPOSE 3000
CMD ["yarn", "run", "start"]
node_modules
.nuxt
ほんとは、マルチステージビルドを使って、nuxt startに必要なもののみ実行用イメージにコピーすれば、イメージサイズはかなり小さくなりそうですが、なにが必要なのか厳密によくわかってないのと、nuxtのバージョンにより必要なファイルが変わりそうなのとで、頑張るのやめました。
環境変数周りの注意事項
Nuxt.jsでは、nuxt.config.js
で環境変数を定義できますが、これらの環境変数は、nuxt build
時に文字列リテラルに置き換えられる仕組みになってます。axiosモジュールのように、nuxt.config.js
以外に環境変数から設定値を読み込む様になっているものもありますが、いずれにせよ、ビルド時に文字列リテラルに置き換えられます。
なので、実行環境に応じて変更したいものは、nuxt start
時ではなく、nuxt build
時に、環境変数またはnuxt.config.js
で指定する必要があります。
つまり、ビルド時に設定値が固定化されてしまうため、環境ごとに設定値を変更したい場合は、環境ごとに別のイメージをビルドする必要があります。Dockerイメージで使用する設定は、Twelve-Factor Appでも言われている通り、実行時に環境変数として指定するのが望ましいため、なんとかしたくなります。
対策として、nuxt-envを利用すると、nuxt start
時に指定した環境変数に、以下のようにアクセスできるようになります。
<script>
export default {
mounted() {
// コンポーネント内では、this.$envでアクセスできる
console.log(this.$env.hoge)
},
asyncData(ctx) {
// nuxtのコンテキスト経由でアクセスできる
return {
hoge: ctx.$env.hoge
}
}
}
</script>
export actions = {
someAction(ctx) {
// Vuex store内では、this.$envでアクセスできる
console.log(this.$env.hoge)
}
}
VueコンポーネントやStoreで使用する設定値を変更したい場合はこの方法でなんとかなりますが、モジュールに渡す設定値を可変させたい用途では、残念ながらこの方法は使用できません。
結局は、環境別にイメージをビルドし直すしか、現状は方法がないようです。
Nuxt.js自体が、SPA+SSRを簡単にやるためのフレームワークであり、SPAの場合は環境別の設定はビルド時に組み込んじゃうのが一般的なので、しょうがないかなという感じはしますが、将来的になんとかなってほしいところです。