Results
私のポートフォリオページでこれを実現しています.
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-router
の history 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]
webpack
とWebpack-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
でリロードしても問題なく表示されるはずです.