AmplifyでホスティングしたVueのSPAアプリでサブディレクトリに直接アクセスできるようにする

# AmplifyでホスティングしたVueのSPAアプリでサブディレクトリに直接アクセスできるようにする


## はじめに
[Amplify](https://aws.amazon.com/jp/amplify/)はAWSのBaaSフレームワークです。BaaSフレームワークといえば[Firebase](https://firebase.google.com/?hl=ja)が有名です。確かにFirebaseはAmplifyよりも、クラウドサービスとしての各サービス(functions、DBなど)の管理をより意識せずに使える手軽さが便利で、自分で何でも選んでいい状態であれば選択肢の筆頭に上がるところです。
しかし会社としてAWSをメインで採用していて、新規Webサービスをスピード感をもって立ち上げる、といった際にはAmplifyが有力な選択肢になってくるんじゃないでしょうか。
AmplifyはAmplifyで便利ですし、Firebaseと違ってGraphQLサービスであるAppSyncをバックエンドとして扱えるので、個人開発者の皆さんもぜひAmplifyを視野に入れてみてください。

弊社では現在、Amplifyを用いてVueのSPAアプリケーションを作成しております。
その中でSPAでありがちな、URLのサブディレクトリへの直接アクセスをどう処理するかで悩み、最終的にサブディレクトリへの直接アクセスが可能な設定を達成したので共有いたします。

なお、本記事の内容の実現は基本的に[この記事](https://qiita.com/go6887/items/dcb7aa86ba6a006d4746)を下敷きにしております。
筆者の@go6887様にはこの場を借りて感謝を申し上げます。

## How toを3行で
1. Amplifyコンソールの「書き換えて、リダイレクト」設定で、404時に`/<*>`を`/?redirect_path=<*>`にリダイレクトするように設定。
2. Vue router用のリダイレクト処理を記述。アクセス先URIに`redirect_path`が含まれている場合に、redirect_pathが指すサブディレクトリへリダイレクトするようにする。
3. Vue routerでルートページのbeforeEnterにリダイレクト処理を追加。

以下詳細になります。

## 前提
- Vueを用いて作成したSPAのWebアプリケーションである。
- Amplifyを用いてホスティングを行っている。
- Vue routerの設定をhistoryモードにしている。
- ベースURLは`https://works-hi.com`とする。
- サブディレクトリとして以下を持つとする。
  - mypage
  - history
  - setting

## Amplifyコンソールでのリダイレクト設定
AWSコンソールからAmplifyを開くと、「すべてのアプリ」画面が開くかと思います。設定したいアプリの設定画面へ遷移し、左のサイドバー内から「書き換えて、リダイレクト」を開きます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375883/69c9cce3-029c-df7a-cbba-e1d14d5a30a3.png)
「編集」から編集画面を開き、リダイレクト設定を以下のように設定します。

|送信元アドレス|ターゲットアドレス|入力|
|---|---|---|
|/<*>|/?redirect=path=<*>|404|
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375883/c9ac7717-3c65-e1c0-33eb-84b8d69ab57a.png)

入力を404にしたのは、SPAではサブディレクトリに直接アクセスした際に404になるためです。
ここの設定により、「送信元アドレス」にアクセスした際にHTTPステータスが「入力」のステータスになったら、「ターゲットアドレス」にリダイレクトする、ということが実現されます。

## beforeEnterのリダイレクト処理
基本的には[参考にした記事](https://qiita.com/go6887/items/dcb7aa86ba6a006d4746)と同じですが、Amplifyのリダイレクトの仕様を回避するために少々手を加えます。

```typescript:guard.ts
import { NavigationGuard } from 'vue-router';

const queryKey = 'redirect_path';

export const redirect: NavigationGuard = (to, _, next) => {
  if (to.query[queryKey]) {
    const path = `/${to.query[queryKey]}`.replace('/index.html', '');
    next({ path });
  } else {
    next();
  }
};
```

変わっている部分はreplaceによりpathから`/index.html`を削除している部分です。
Amplifyコンソールにおいて、404に対するリダイレクト処理では末尾に自動的に`/index.html`が付与されてしまいます。
`/index.html`を削除せずにリダイレクトすると、`/setting/index.html`等へルーティングされることになり、結果的にルートページへリダイレクトされてしまいます。

※SPAでないWebアプリケーションにおいては各サブディレクトリに対応するindex.htmlが存在するし、SPAでは[Amplifyの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/redirects.html)でも示されているように、サブディレクトリにアクセスされた場合にはルートディレクトリのindex.htmlに導くのが基本とされているためアシストのつもりなのでしょうが、今回のようなケースにとっては蛇足でしかないため、記載通りのリダイレクトをしてほしいものです。

## Vue routerの設定
最後に、前セクションで作成したguard.tsをVue routerのルーティング設定のbeforeEnterに設定します。

```typescript.router.ts
import Vue from 'vue';
import VueRouter from 'vue-router';
import Main from '@/containers/pages/Main.vue';
import Mypage from '@/containers/pages/Mypage.vue';
import History from '@/containers/pages/History.vue';
import Setting from '@/containers/pages/Setting.vue';
import PageNotFound from '@/containers/pages/PageNotFound.vue';
import { authenticate } from '@/router/authenticate';
import { redirect } from '@/router/guard';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    component: Main,
    name: 'main',
    beforeEnter: redirect,
  },
  {
    path: '/search',
    component: Mypage ,
    name: 'mypage ',
  },
  {
    path: '/history',
    component: History,
    name: 'history',
  },
  {
    path: '/setting',
    component: Setting,
    name: 'setting',
  },
  {
    path: '*',
    component: PageNotFound,
    name: 'notFound',
  },
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach(authenticate);

export default router;
```
※ルートディレクトリに対してのみbeforeEnterを設定しているのは、今回のケースではAmplifyコンソールのリダイレクト処理による向き先がルートディレクトリのみになるためです。

以上の設定により、ユーザーが例えば`https://works-hi.com/setting`に直にアクセスした場合、以下のようにリダイレクトされることになります。

1. Amplifyコンソールの機能により、`https://works-hi.com/?redirect_path=setting/index.html`へリダイレクト。
2. `https://works-hi.com/?redirect_path=setting/index.html`はルートディレクトリなので、Vue routerによりbeforeEnterの処理が行われる。
3. guard.tsの処理により、`https://works-hi.com/setting`へルーティング。

これで、AmplifyでホスティングしたVueのhistoryモードのSPAにおいて、サブディレクトリへの直接アクセスを実現することができました。

## おわりに
[参考記事](https://qiita.com/go6887/items/dcb7aa86ba6a006d4746)でも言及されているように、[Vueの公式ページ](https://router.vuejs.org/ja/guide/essentials/history-mode.html)でも、[Amplifyの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/redirects.html)でも、その他のブログ等でも、基本的にSPAでは、サブディレクトリへの直接アクセスはルートページへ遷移させるように推奨しているケースが多いです。
しかし、例えばQiitaのようなコンテンツ共有サービスであったり、コーポレートサイトをSPAで実装する場合など、サブディレクトリへの直接アクセスを実現したいケースは結構あるんじゃないでしょうか。
ニーズはあるはずなのになんで情報があんまりないんだろう、ともやもやしていたところであったので、同じところで詰まった方々に少しでも本記事が役立てば幸いです。

## 参考
https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/redirects.html
https://router.vuejs.org/ja/guide/essentials/history-mode.html
https://qiita.com/go6887/items/dcb7aa86ba6a006d4746