docker-composeのNuxt.jsからAPIをコールしたら「[HPM] Error occurred while trying to proxy request」
こういう構成のdocker-composeで、frontendコンテナ(Nuxt.js:localhost:3000)から
backendコンテナ(Laravel:localhost:8000)にAPIリクエストをしたら
[HPM] Error occurred while trying to proxy request /api/hoge from localhost:3000 to http://localhost:8000/
という504エラーが返ってきて、backendまで届いていない。。
これは フロントエンドの nuxt.config.js
のproxy設定が間違っていて、
proxy: { '/api': { target: 'http://localhost:8000/api', pathRewrite: { '^/api/': '/' } } },
を以下のように修正してリスタートしたらなおった。
proxy: { '/api': { target: 'http://backend:8000/api', # コンテナ名に変更! pathRewrite: { '^/api/': '/' } } },
[HPM] Error occurred while trying to proxy request
、webフロントエンド作るたびに言われてる気がする。
【メモ】docker-composeで起動したNuxt.jsアプリに繋がらない
コンテナでは起動を確認できる( docker-compose exec [コンテナ名] bash
で、 curl localhost:8080
とすると起動してればhtmlが返る )のに、ホスト側で見れない。
package.json
を以下のように書き換えたら見られるようになった。
# これを "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate" }, # こうじゃ! "scripts": { "dev": "HOST=0.0.0.0 PORT=8080 nuxt", # ココを変えた! "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate" },
【メモ】create-nuxt-appで失敗する
throw new SAOError(`Failed to install ${packageName} in ${cwd}`)
とか出て進まない。メッセージ違うけど、前もあったなこれ・・・
今回はESListを外したら成功しました。成功した組み合わせ置いておきます。
? Choose the package manager Yarn ? Choose UI framework Element ? Choose custom server framework None (Recommended) ? Choose Nuxt.js modules Axios ? Choose linting tools Prettier ? Choose test framework None ? Choose rendering mode Single Page App
【メモ】Nuxt.js: axiosでオフライン状態(NetworkError)を捕捉する
axiosでAPIにアクセスするとき、エラーレスポンスをハンドリングすることは出来るんだけど、接続エラーなどの、サーバーからレスポンスが何も帰ってこないエラー(ネットワークエラー)は onError
にも onResponse
にも入ってこない。
// @/plugins/axios.js export default function({ $axios }) { $axios.onRequest(req => { // リクエスト前に呼び出されるコード }) $axios.onResponse(res => { // 成功レスポンスを受け取った時に呼び出されるコード // 接続エラーはここにこない(レスポンス自体ないから) }) $axios.onError(res => { // エラーレスポンスを受け取った時に呼び出されるコード // 接続エラーはここにこない(レスポンス自体ないから) }) }
一日考えた挙句、そうかリクエスト前にチェックすれば良いんだわということに気が付いた(遅)
window.navigator.onLine
で、オンライン状態を確認できるので、onRequest
にこのチェックを追加。
// @/plugins/axios.js import Vue from 'vue' export default function({ $axios }) { $axios.onRequest(req => { if (!window.navigator.onLine) { Vue.toasted.error( // オフライン時にAPIリクエストがあったときにtoastを表示するようにした '現在オフラインです。' ) return Promise.reject(req) } // リクエスト前に呼び出されるコード }) $axios.onResponse(res => { // 成功レスポンスを受け取った時に呼び出されるコード }) $axios.onError(res => { // エラーレスポンスを受け取った時に呼び出されるコード }) }
無事捕捉することが出来ました。
Vue Test Utilsでコンポーネントのdata()を評価したい
なぜかうまくいかず時間がかかったのでメモ
こういうページネーションのコンポーネントのテストを書くとき、
コンポーネントのpropsには以下のような値(現在のページ,ページあたりの件数,トータル件数)を設定できるとして
<Pagination :config="{ current: 1, limit: 20, total: 100 }" @movePage="load" />
propsに値を設定したことを受け、watch
に定義したメソッドで、data()
の最終ページ lastPage
の値を算出したい。
watch: { config: function(payload) { // ここではわかりやすく「5ページ >>」とか変数にいれてる this.lastPage = Math.ceil(payload.total / payload.limit) + 'ページ >>' // 上記例の設定値だと「5ページ >>」になる } }
この「5ページ >>」を検査したかったのだけど、テストコードで propsData
をセットしてもなぜかwatchが発火しない。
<template> ... <a class="pagination-link last-page" :disabled="currentPage === lastPage" aria-label="Goto last page" @click="moveLast" > {{ lastPage }} <!-- 「5ページ >>」 --> </a> ... </template>
describe('components/Pagination.vue', () => { let wrapper describe('template', () => { beforeEach(() => { wrapper = mount(Pagination, { propsData: { config: { nextPage: 2, limit: 20, total: 100 } } // propsにセットしたのだからwatch発動してほしい! }) }) test('最終ページは5ページ目であること', () => { const page = wrapper.find('.last-page') expect(page.text()).toBe('5ページ >>') // 失敗。got:null }) }) })
props
を2回セットしたら思った通り動くようになった。
describe('components/Pagination.vue', () => { let wrapper describe('template', () => { beforeEach(() => { wrapper = mount(Pagination, { propsData: { config: { nextPage: 2, limit: 20, total: 100 } } }) }) test('最終ページは5ページ目であること', () => { wrapper.setProps({ config: { nextPage: 2, limit: 20, total: 100 } }) // これを足した。 const page = wrapper.find('.last-page') expect(page.text()).toBe('5ページ >>') // 成功した! }) }) })
2度setProps
していてなんかモヤるけど、やりたいことはできた。
【メモ】Nuxt.js/BulmaのNavbarでdropdownが残ってしまう(:focus-withinが効きっぱなし)
よくあるSPAのドロップダウン。
<n-link class="navbar-link" to="/members"> <span class="icon is-medium"> <i class="fas fa-lg fa-user"></i> </span> <span>メンバー管理</span> </n-link> <div class="navbar-dropdown"> <n-link class="navbar-item" to="/members">メンバー一覧</n-link> <n-link class="navbar-item" to="/members/new">メンバー登録</n-link> </div>
これ、なぜか n-link
click後にフォーカス状態が残ってしまい、閉じてくれない。
これは @click.native
イベントに一行追加することで、閉じてくれるようになりました(手元のChromeとFirefoxで確認)。
<n-link class="navbar-link" to="/members" @click.native="hideMenu"> <span class="icon is-medium"> <i class="fas fa-lg fa-user"></i> </span> <span>メンバー管理</span> </n-link> <div class="navbar-dropdown"> <n-link class="navbar-item" to="/members" @click.native="hideMenu">メンバー一覧</n-link> <n-link class="navbar-item" to="/members/new" @click.native="hideMenu">メンバー登録</n-link> </div>
んで、このメソッドを追加。
<script> export default { methods: { hideMenu(e) { e.target.blur() } } } </script>
以上です。
この一行を追加するまで、謎にえらい時間を費やしてしまったので、メモとして残します。