AngularでビルドしたWEBアプリをnginxにデプロイすると リロードしたときにNot Foundになるやつの対策
事象
ng serve
で起動した開発サーバーは特定のページで再読み込みをすると正常に表示されるのに、
ng build
でビルドしたアプリをnginxでデプロイするとNot Foundになってしまう。
環境
ミドルウェア名 | バージョン |
---|---|
angular | 12.0.3 |
angular-cli | 12.0.3 |
nginx | 1.21.1 |
結論
対策
1. HashLocationStrategyを使用する
app-routing.module.tsで{ useHash: true }
を記述する。
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TopComponent } from './top/top.component';
import { LoginComponent } from './login/login.component';
const routes: Routes = [
{
path: '',
component: TopComponent
},
{
path: 'login',
component: LoginComponent,
},
];
@NgModule({
imports: [ RouterModule.forRoot(routes, { useHash: true }) ],//ここ!
exports: [ RouterModule ],
})
export class AppRoutingModule {}
こうすることによって
https://contoso.com/signin
というURLだった場合、
http://contoso.com/#/signin
となる。
間に#が入っているとURLっぽいけど実は常にルートを見に行っているらしい。
2. nginxのdefault.confを変更する
nginxのtry_filesディレクティブを使用する。
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html; #これを追加!
}
この一文は
- URLのパス($uri)にファイルがあれば返す
- 1がない場合、URLのパス($uri/)にディレクトリがあれば返す
- 2.がない場合、ルートのindex.htmlを返す
という設定になってる。
default.confを変更したらnginx reload
で設定再読み込みで反映されるはず
どっちを採用する?
開発の初期からであればどっちを採用しても問題ないが、開発途中での変更の場合はデメリットがある。
まあでもnginxの設定変更ならほぼダメージ無いのでこっちがいいかな。
デメリット | |
---|---|
HashLocationStrategy | URLが変更になる |
nginx設定変更 | nginxの設定変更が必要 |
事象が起きる原因
AngularはSPA(Single Page Application)であり、ページ遷移の際にURLが変わっているが、
実は一つのページ内で描画するコンポーネントを変えている。
これはHTML5のHistory APIという機能を使って実現しているらしい。
(ってことはこの機能を使ってるフレームワークはこの現象が起こりうるのかな?)
なので、ng build
でビルドされたファイルを見るとhtmlファイルがindex.html
一つしかない。
ルートにしかindex.html
がないんだからそりゃNot Foundになってしまう。
ng serve
だとNot Foundにならないの?
なんでng serve
で起動した開発サーバーはNot Foundエラー(404)が発生した場合、index.htmlを返してくれるようになっているそうです。
それはそれで便利なんだろうけど、ずっとng serve
で開発してきてビルドしたらNot Foundになるから最初に遭遇したときは焦る。。
参考
Discussion