🗿
【Nuxt3】useFetch()のCORSエラーの原因がViteのHot Updateにあった話
環境
Nuxt3.10.3
package.json
{
"name": "nuxt-app",
"private": true,
"type": "module",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@nuxt/content": "^2.7.0",
"@nuxtjs/device": "^3.1.1",
"@nuxtjs/tailwindcss": "^6.7.0",
"@vueuse/components": "^10.4.1",
"@vueuse/core": "^10.4.1",
"@vueuse/nuxt": "^10.4.1",
"nuxt": "^3.10.3",
"tailwindcss": "^3.3.2",
"vue": "^3.4.19",
"vue-markdown-render": "^2.0.1",
"vue-router": "^4.3.0"
}
}
発生した問題
上で紹介されているようにzennの記事を取得できるAPIがあるので,それを自分のサイトにも導入しようとしたところ,次のような挙動を取りました。
- 初回読み込み時(F5)にはFetch出来ている。
- script setup内のコードを変更し,Hot Updateが行われると
CORS header 'Access-Control-Allow-Origin' missing
エラーとなりFetchに失敗する。
コード
<script setup>
const {data, pending, error, refresh} = await useFetch('https://zenn.dev/api/articles?username=nemunyan')
const articles = data.value.articles
console.log(articles)
</script>
原因
useFetchはサーバーサイドでAPIリクエストを行うのでCORSエラーを起こさないが,コーディングしてHot Reloadが行われるとクライアントサイドでコードを実行し更新を反映しようとするためCORSエラーが発生する。
実験
$fetchをonMounted()内で実行してみる
useFetchをmounted内で使うべきではないとのことなので$fetchを使ってます。
<script setup>
const {data, pending, error, refresh} = await useFetch('https://zenn.dev/api/articles?username=nemunyan')
const articles = data.value.articles
console.log(articles)
onMounted(async() => {
console.log('mounted')
const {data, pending, error, refresh} = await useFetch('https://zenn.dev/api/articles?username=nemunyan')
console.log(data.value.articles)
})
</script>
結果
useFetchは正常にGET出来ていますが,$fetchのほうは失敗しています。これはonMounted内はブラウザ上で実行されるからです。
fetchを使ってみる
<script setup>
const {data, pending, error, refresh} = await useFetch('https://zenn.dev/api/articles?username=nemunyan')
const articles = data.value.articles
console.log(articles)
fetch('https://zenn.dev/api/articles?username=nemunyan')
.then(response => response.json())
.then(data => console.log(data))
</script>
結果
fetchはブラウザ上で実行されるリクエストのため失敗しています。
Hot Updateをする
初期のコードでページを開いてから,``console.log('updated')を追加してHot Updateさせる。
<script setup>
console.log('updated')
const {data, pending, error, refresh} = await useFetch('https://zenn.dev/api/articles?username=nemunyan')
const articles = data.value.articles
console.log(articles)
</script>
結果
console.log('updated')までは正常に実行されているが,useFetchに失敗していることが分かります。
まとめ
- Nuxtではユニバーサルレンダリングが用いられており,
<script setup>
内のコードはサーバーサイドで実行されたりクライアントサイドで実行されたりする。 - useFetchはサーバーサイドで実行され,Hydrationの際にクライアントに値を渡す挙動を取るので,CORSに引っかからない。
- ViteのHot Update機能はページの更新なしで変更箇所を反映することで爆速な環境を提供してくれているが,この際にuseFetchはクライアントサイドで行われるのでCORSエラーとなる。
- Hot Updateは本番環境では用いられない(と思う)ので,useFetchを用いたことによるCORSエラーは無視して良いエラーである。
特に意識せずとも快適に開発をさせてもらっているNuxtがこういう形で牙を出してくるとは思いませんでした。NuxtのHydrationの仕組みやクライアントサイド/サーバーサイドの関係性,Viteの仕組みまで学習する良い機会でした。
Discussion