【令和4年最新版】Nuxt.js+VuetifyでNetlifyのForm機能をスマートに使う方法（SSR/SPA）

ネット上にあるNuxt+Netlify Formの記事が情報錯綜していたので、令和４年で正しいと思われる情報を整理しました。

# お急ぎの人向け 最初に結論

nuxt.config.jsの設定が・・・
SPAの場合 → ダミーフォームかプリレンダリングが必要
SSR/SSGの場合 → 公式通りに正しくタグを書くだけでOK

以下は解決までの経緯と詳細な情報、サンプルコードなどです。

## Netlify Formの公式ドキュメント
https://docs.netlify.com/forms/setup/

公式では、以下のようにformタグにname属性とdata-netlify="true"を入れるだけでNetlify Formが動くよ、と書いてある。しかしVueやReactだと動かないという人が多数出現している。私もそうだった。

```
<form name="contact" method="POST" data-netlify="true">
```

## 公式の回答
公式フォーラムで「フォーム動かねぇよ！」という人には
だいたいこれを見ろ！！って回答されている

https://answers.netlify.com/t/support-guide-form-problems-form-debugging-404-when-submitting/92


要約するとちゃんとタグ書いてるか？って事なのですが、それは問題ないんだ！！！という感じ。

## フォーラムを掘り下げていくとこんな情報が出てくる

https://www.netlify.com/blog/2018/09/07/how-to-integrate-netlify-forms-in-a-vue-app/#stand-in-static-forms

vueでnetlifyのformを作る場合、staticフォルダにダミーのHTMLフォームを置けよ。という情報。日本語のNetlify+Formのトラブルシューティング系の記事も、この情報を参考に動いた！という記事がいくつかあった。

これでも動くんだけど、本フォームの変更があるたびにダミーフォームも変更しないといけないし、動的にフォームを生成する場合はどうするの？という問題がある。

## そんなものなくても動くという情報。

https://qiita.com/yahsan2/items/a70c4c8f617ee9b1f9ff

ダミーフォームを置くか、`<no-ssr>`や`<client-only>`で囲むだけで認識してくれるよ、という内容、しかしこれも重要な情報が不足していて、nuxtの設定がSPAの場合はタグで囲もうが囲まないが、認識されません。

## 結論

色々調べた結果、結論としては以下のサポートフォーラムで示されている、このリポジトリのソースコードが完全に正しいです。

https://answers.netlify.com/t/vue-nuxt-js-prerender-form-not-showing-in-forms-page-on-dashboard/2143

https://github.com/shortdiv/netlify-nuxt-forms

### 該当のコード・リポジトリを解説

https://github.com/shortdiv/netlify-nuxt-forms/blob/master/pages/index.vue

当初の公式ドキュメント通りの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（未検証）を使ってください。

https://github.com/chrisvfritz/prerender-spa-plugin

## おまけ

正しくフォームが認識されていれば、Netlify管理画面のForms > Active Formsに表示されるはずです。それが表示されていない場合は何をやっても404になります。

![スクリーンショット 2022-05-30 7.30.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266846/31cd651f-8d12-2c1f-4600-4b9d4160f92a.png)

### 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の方にだいたい入ってます。

```vue
<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