ネット上にあるNuxt+Netlify Formの記事が情報錯綜していたので、令和4年で正しいと思われる情報を整理しました。
お急ぎの人向け 最初に結論
nuxt.config.jsの設定が・・・
SPAの場合 → ダミーフォームかプリレンダリングが必要
SSR/SSGの場合 → 公式通りに正しくタグを書くだけでOK
以下は解決までの経緯と詳細な情報、サンプルコードなどです。
Netlify Formの公式ドキュメント
公式では、以下のようにformタグにname属性とdata-netlify="true"を入れるだけでNetlify Formが動くよ、と書いてある。しかしVueやReactだと動かないという人が多数出現している。私もそうだった。
<form name="contact" method="POST" data-netlify="true">
公式の回答
公式フォーラムで「フォーム動かねぇよ!」という人には
だいたいこれを見ろ!!って回答されている
要約するとちゃんとタグ書いてるか?って事なのですが、それは問題ないんだ!!!という感じ。
フォーラムを掘り下げていくとこんな情報が出てくる
vueでnetlifyのformを作る場合、staticフォルダにダミーのHTMLフォームを置けよ。という情報。日本語のNetlify+Formのトラブルシューティング系の記事も、この情報を参考に動いた!という記事がいくつかあった。
これでも動くんだけど、本フォームの変更があるたびにダミーフォームも変更しないといけないし、動的にフォームを生成する場合はどうするの?という問題がある。
そんなものなくても動くという情報。
ダミーフォームを置くか、<no-ssr>
や<client-only>
で囲むだけで認識してくれるよ、という内容、しかしこれも重要な情報が不足していて、nuxtの設定がSPAの場合はタグで囲もうが囲まないが、認識されません。
結論
色々調べた結果、結論としては以下のサポートフォーラムで示されている、このリポジトリのソースコードが完全に正しいです。
該当のコード・リポジトリを解説
当初の公式ドキュメント通りのFORMタグの書き方で、普通に動いています。
staticフォルダにダミーのHTMLもないし、<no-ssr>
や<client-only>
で囲まれていません。
重要なポイントはnuxt.config.jsのSSRの設定
どの記事やフォーラムにも前提となる重要な情報が不足していたのがこれ。
「そもそもnuxtのSSR設定どうなっているんよ?」 というところ。
実は、SPAでビルドしたものをNetlify Formで動かす場合は、ダミーHTMLのFORMが必要で、SSRでSSGしたビルドであれば、普通にビルドした解析してくれるという事が判明。
そのnuxt.config.jsの設定がこれ
export default {
mode: 'universal',
これだけ。ただしmodeオプションはもうdeprecatedなので、正しい書き方はこう
export default {
ssr: true,
target: 'static',
上記の設定であれば、公式ドキュメントの通りに書いたソースを
Netlifyが解析して、Formとして動くようにしてくれます。
なにかの事情でSPAじゃないとだめって場合は、素直にダミーのHTMLフォームを作るか、prerenderSPAPlugin(未検証)を使ってください。
おまけ
正しくフォームが認識されていれば、Netlify管理画面のForms > Active Formsに表示されるはずです。それが表示されていない場合は何をやっても404になります。
Vuetifyも使えるよ
v-formやv-text-fieldなどのVuetifyのタグも、問題なく認識されます。
Nuxt+Vuetify+Netlify form サンプルコード
Nuxt+VuetifyのNetlify formのサンプルコードは以下になります。
v-forとかで動的にタグを生成してもOK。
formのsubmitでも、API POSTでもどちらでも動きます。
なお、送信してThank youページが出てるのに届かねーよ!って時は、FormsのSpam submissionsの方にだいたい入ってます。
<template>
<v-container tag="section">
<v-form :name="formName" method="post" action="/thankyou" data-netlify="true" data-netlify-honeypot="bot">
<input type="hidden" name="form-name" :value="formName" />
<v-row>
<v-col cols="12">
<v-text-field v-model="name" label="name" name="name" />
<v-text-field v-model="sex" label="sex" name="sex" />
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field v-model="mail" label="mail" name="mail" />
<v-text-field v-model="postcode" label="postcode" name="postcode" />
<v-text-field v-model="address" label="address" name="address" />
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field v-for="i in 5" :key="i" v-model="custom[i]" :label="`custom${i}`" :name="`custom${i}`" />
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field v-model="subject" label="subject" name="subject" />
<v-textarea v-model="body" label="body" name="body" />
<v-text-field v-show="false" v-model="bot" />
</v-col>
</v-row>
<v-row>
<v-col>
<v-btn type="submit"> submit </v-btn>
<v-btn @click="post"> post </v-btn>
</v-col>
</v-row>
</v-form>
<pre>{{ response }}</pre>
</v-container>
</template>
<script>
export default {
name: 'TestForm',
data() {
return {
formName: 'contact-inspire-vform-3',
name: '',
mail: '',
body: '',
subject: '',
address: '',
sex: '',
postcode: '',
custom: [0, 1, 2, 3, 4, 5],
response: {},
}
},
methods: {
async post() {
const params = new FormData()
params.append('form-name', this.formName)
params.append('name', this.name)
params.append('mail', this.mail)
params.append('body', this.body)
params.append('sex', this.sex)
params.append('postcode', this.postcode)
params.append('subject', this.subject)
params.append('address', this.address)
params.append('custom1', this.custom[1])
params.append('custom2', this.custom[2])
params.append('custom3', this.custom[3])
params.append('custom4', this.custom[4])
params.append('custom5', this.custom[5])
try {
const response = await this.$axios.$post(window.location.origin, params)
this.response = response
this.$router.push("/thankyou")
} catch {
this.$router.push("/error")
}
},
},
}
</script>
この記事がNetlify Formでハマっている人に届きますように・・・
参考
SPA/SSRの情報が抜けてたり、不完全だったりします。
https://qiita.com/shozzy/items/9ff95ddaf878d1be0c31
https://qiita.com/toshikisugiyama/items/b523bb47e463060040cc
https://qiita.com/miiina016/items/e86c0bf4f8808dd6b6ae
https://qiita.com/hiropy0123/items/2e8d14ea66b78ab64847