Help us understand the problem. What is going on with this article?

Vue.jsプロジェクトをサブディレクトリで配信するときの注意点

More than 1 year has passed since last update.

はじめに

この記事は以下の説明をしているものです。

  • vue-cliでビルドした静的ファイルを配信する方法(Nginx)
  • vue-cliでビルドした静的ファイルをサブディレクトリで配信する方法(Nginx)

環境

  • vue 2.5.17
  • vue-cli 3.1.1

vue.js (vue-cli) でビルドした静的ファイルをnginxで配信する

vue-cliはハッシュモードとヒストリーモードを設定できます。
デフォルトはハッシュモードであり、vue-cliでプロジェクトを作るとデフォルトではURLが https://example.or.jp/#/ のように勝手に#がついているのが分かります。
URLが変化したときにブラウザのリロードにもしっかり対応してくれるのでラクなのですが、見た目があまりよろしくないのでヒストリーモードにします。
しかし、ヒストリーモードではvue-cliで作った静的ファイルを配信するnginxなどのウェブサーバーアプリケーションの設定をしっかり行わないとassetを一切読み込んでくれなくなったりします。
その設定が以下です。

server {
  listen 80;
  server_name example.or.jp;
  return 301 https://$host$request_uri;
}
server {
  listen 443 ssl http2;
  server_name example.or.jp;
  root /var/apps/example.or.jp/dist;
  ssl_certificate /etc/letsencrypt/live/example.or.jp/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.or.jp/privkey.pem;

  location / {
    try_files $uri $uri/ /index.html;
  }
  location /favicon.ico {
    root /var/apps/example.or.jp/static;
  }
}

httpsへのリダイレクトをしたくない場合は適宜省略していただいて、location / ディレクティブのように設定してしまえば問題ありません。

HTML5 History モードにも記載があります。

サブディレクトリで配信

APIとViewが別アプリケーションなのに同じドメインで動かそうとする場合、注意が必要です。
ここでは、
View: https://example.or.jp/aaa/view/....
API: https://example.or.jp/aaa/[view以外]

で使い分けるようにします。また、APIはRails、unicornで作っているとします。
locationディレクティブだけピックアップすると以下のようになります。

location / {
  proxy_set_header Host $http_host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Client-IP $remote_addr;
  proxy_set_header X-Forwarded-For $remote_addr;
  proxy_pass http://new-example-http;
}
location ~ ^/aaa/view/(.+\..+$) {
  alias /var/apps/example.or.jp/dist/$1;
}
location ~ ^/aaa/view/(.+) {
  alias /var/apps/example.or.jp/dist/;
  try_files $uri $uri/ /index.html = 404;
}

正規表現で書かれたlocationがまず優先されて、合致しなかった場合location / に到達します。
'/var/apps/example.or.jp/dist/'がvue-cliでビルドしたファイルのindexが置かれている場所です。
location / の中のproxy_passはunicornの設定によるもので、upstreamに任意につける名前です。
/aaa/view/(.+..+$)は、.を含むファイル(aaa.pngやhoge.textなど)を表し、静的ファイルにも対応できるようにします。

本来は/aaa/view/(.+..+$)と/aaa/view/(.+)で分ける必要ないと思われますが、ファイルを見に行こうとしているのかvue-routerにリクエストを渡そうとしているのか区別を付ける必要があります。

https://example.or.jp/aaa/view (末尾のスラッシュ無し)はAPIの方に行ってしまうので、もしそれがまずい場合は別の対応を取る必要があります。~ ^/aaa/view(.+)ではうまく動きませんでした。

vue-cli側の対応

アプリ側でもbase urlを設定する必要があります。
以下はrouter.jsの例です。

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/list/:roman_name',
      name: 'index',
      component: Index
    },
    {
      path: '/:id',
      name: 'show',
      component: () => import('./views/Show.vue')
    }
  ]
})

process.env.BASE_URLを変える必要があります。
ルート (package.jsonがあるところと同じ階層) に vue.config.js というファイルを作り以下のように記述します。

module.exports = {
  baseUrl: '/aaa/view',
}

最後に

Nginx力がそんなに高くないのでもっと良い記述方法があるかもしれません。
何かありましたらコメントでご教授してくださると幸いです。

Hirata-Masato
Webプログラミング経験3年、機械学習・ディープラーニングの経験2年です。オートエンコーダに興味あり
ikyu
「こころに贅沢を」をコンセプトに一休.com、一休レストランなどのサービスを提供しています。
https://www.ikyu.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away