LoginSignup
1
1

More than 1 year has passed since last update.

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

Posted at

ネット上にある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になります。

スクリーンショット 2022-05-30 7.30.58.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の方にだいたい入ってます。

<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

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1