Edited at

Github pagesでハッシュなしSPAを作る[Vue.js + vue-router]


Results

私のポートフォリオページでこれを実現しています.

Demo


Introduction

Single Page Application(SPA)はファイルの実体が存在していないため,ブラウザをリロードすると404を返されてしまいます.

この問題を解決するためSPAでは基本#/を用いているのですが...

#/ <- こいつすごい気になる!

SPA を構築している殆どの開発者がこう思ったのではないでしょうか?

このハッシュを消す方法はいくつか存在します.

ApacheやNode.js,Nginxなどは公式を参照すると良いかと思います.

しかしながら,この中にはGithub pagesについては記載されていませんでした.

本記事はGithub pagesでもハッシュなしのSPAを実装する方法をご紹介します.


How to

ここを参考にプログラムを修正しました.

SPAに必要なのは遷移先を示すURLなので(https://[:domain]/[:path][:path]),ページリロード時に:pathを取得,その後パラメータとしてURL に:pathを追加してindex.htmlへリダイレクトさせてあげます.


Preparanation

vue-routerhistory mode を有効にします.

const router = new VueRouter({

mode: 'history', // <= ここ
routes: [...]
})


Example

以下の構成でSPAが構築されているとします.

https://hoge.com/

https://hoge.com/foo

この時,https://hoge.com/からhttps://hoge.com/fooへ遷移後,ページをリロードすると404エラーが返ってきます.


Methods

まず,404.htmlを作成します.

Github pages はページが見つからないと作成した404.htmlを表示するためこの特性を利用して以下のscriptを記述します.


  • 2018/2/2 Added: narugitさんからご指摘がありました部分を修正いたしました.

let secmentCount = 1; // [2018/2/2 Added]: 変数が抜けていると指摘がありましたので,追加しました.

let l = window.location;
let port = l.port ? ':' + l.port : ''
l.replace(
`${l.protocol}//${l.hostname}${port}/?p=${l.pathname.split('/').slice(0, 1 + segmentCount).join('/')}`
)

これはhttps://hoge.com/fooというURLが与えられていれば,https://hoge.com/?p=/fooという形でindex.htmlへリダイレクトするスクリプトです.

続いてindex.htmlに以下のスクリプトを追加します.

(function (l) {

if (l.search) {
var q = {};
l.search.slice(1).split('&').forEach(function (v) { // ?p=/fooの分解
var a = v.split('='); // 'p=/foo' となっているはずなので=で分割
q[a[0]] = a[1]; // {p: '/foo'} 形式に修正
});
if (q.p !== undefined) {
window.history.replaceState(null, null, l.pathname.slice(0, -1) + (q.p || '')); // https://hoge.com/fooへ遷移
}
}
}(window.location))

以上で完了です.

index.htmlに入れるスクリプトは必ずVue.jsを読み込むスクリプトの前に書いてください.

<head>内に書いておけば大丈夫かと思います.


Coclusion

遷移時にパラメータを付与したい場合などはここにパラメータ付きの場合のプログラムが掲載されているので利用すると良いかと思います.

参考にまでに私のコードを載せておきます.

srcを参照してください.

以上!


P.S. [2018/07/07 Added]

webpackWebpack-dev-serverを利用しているとネストしたルート(https://hoge.com/foo/bar など)でリロードすると白紙のページが返るくる方がいらっしゃると思いますが,

これは相対パスでコンパイルされたファイルを読み込もうとしているため発生しているエラーです(<script src=bundle.js></script>となっている).

webpack の設定を少し変更するだけで解決します.

webpack.output.publicPath = '[:publicPath]'

上記を追加すると[:publicPath]から先のディレクトリを参照します.

例えば [:publicPath]/にした場合, <script src=/bundle.js></script> となります.

これを追記することでhttps://hoge.com/foo/barでリロードしても問題なく表示されるはずです.


References

Stack Over Flow

SPA github pages