応募フォームをできるだけフロントエンドで作ってみた

今、弊社では日中交流プロジェクト「対話山東」に携わっているのですが、その中で応募フォームを作成する必要が出てきました。 サーバーを借りることは難しかったので、できるだけフロントエンドで完結するように作ってみました。 実際につくったもの

オンライン参加も受け付ける予定なので、奮ってお申し込みください!

以下、制作の記録と自戒メモです。

# 使ったライブラリ

  • Vue.js

電氣羊のお気に入りフレームワークです。 これがないと話になりません。最初はhtmlに生のJavaScriptを書いていたのですが、規模が大きくなってきたので、TypeScriptを使ったWebアプリに書き換えました。 うん、最初からこっちにするべきだったかもしれません。

  • Bulma

これまたお気に入りのCSSフレームワーク。 仮想DOMと相性がいいそうなので、愛用しています。 ~~ 最初からWebアプリで作るならVuetifyの方が ~~

色見やグリッドデザインなど、やっぱりすごい人の作ったものは楽ができますね。

  • Airtable

集計したデータを可視化するためのLowCodeなデータベース。 GAS + Googleスプレッドシートも考えましたが、GASの6分/時間制限にひっかかりそうだったので、こちらを選択。 実験中にリクエストを投げすぎて30秒止まってしまったのは内緒。

@typeもあったはずですが、今回は面倒だったので @ts-ignore してしまいました。

  • elastic email

応募フォームだと、受け付けた内容をメールで返すのが一般的ですが、フロントエンドだけだとどうしたものか…… そこで見つけたのがこれ。 elastice email は npm にも公式ライブラリがあったので、smtp.js自体は使いませんでしたが、勉強になりました。

  • Dark

Airtableもelastic emailもAPI Keyで認証するのですが、ハードコーディングしていいものか、迷っていました。 せめてOrigin認証くらいはしようか、ということで

一旦TokenをDarkに送る → TokenとOriginを見て正しければ上記2つのAPI Keyを返す

という構造にしました。

これまでに使ったことのあるライブラリをメインに、欲張りセットで頑張ります。 作業日数は2日強! めぇ~~~~ん

# つくってみた

Vueアプリの土台づくり~ライブラリ導入です。

vue create myform
yarn add bulma sass-loader node-sass airtable elasticemail

簡単ですね。あ、VuexとTypeScriptを使う設定です。 上でも書いた通り、airtabelはType定義無しで使っちゃいました。 だってどうせ上手く使わないとRecordsってanyみたいなもんだし

あとは参加者情報、午前の部、午後の部、マッチング会とコンポーネントをガリガリ書いていきます。 情報はVuexがまとめて持ってくれるので楽です。 最後にDarkにFetch、Originが正しければAPI Keyを入手できるので、Airtableにレコードを作成し、elasitic email経由でメールを出すだけです。

# ハマったところ

  • Vueのstyleの初期設定に text-align: centermargin-top: 60px があるのをうっかり忘れて頭をかく。

  • Vueの開発用サーバーがポート番号8080なのを忘れていて、Origin認証に失敗する。

  • Vueアプリの置き場所がTOPではない場合の設定の書き方を忘れて、アップしてから焦る。 vue.config.jsのpublicPathでしたね。

  • VueのPublicPathを本番環境に合わせたところ、今度は開発用サーバーが立ち上がらない。  process.env.NODE_ENV === 'production' ? '/shandong/' : '/' だよ!

  • Form内のButtonタグのClickイベントで @click.prevent.stop を忘れる。

と、本当にVue使いか!と突っ込まれそうなうっかりミス多発でした。

  • fromとformをタイポ。そして気が付かない。

  • 電話番号とFAX番号にバリデーションを付けてみた……ら、必須ではないはずのFAX番号が必須になっていた。  ちゃんと空白をはじいておきましょうね。

  • AirtableのSingle Selectの項目名を変更忘れ。Fetchが通らなくなった。  ちゃんとRecordの型定義をしましょう。

  • Airtableの負荷制限にひっかかる……

  • Darkから返ってくるStringは "\"string\"" とダブルクォーテーション付きの文字列だった!

  • res.text() にcatch()を書いてエラーがでる

実際に書いていたのはこんなスクリプト。

res.text().then((t) => {
	// なぜかcatchブロックの後にthenブロックが実行される
    if (t !== '"access_invalid"') {
		dispatch('createRecords', t);
    } else {
    	commit('raiseFetchError', 'access_invalid');
 	}
}).catch(() => {
    // なぜかthenより先にここが実行される
	commit('raiseFetchError', 'res.text()_failed');
})

MDNをよく見たら、Body.text()にはthen()しか定義されていない模様。 やっぱりドキュメントをちゃんと読まなきゃ。

# 新しく使った技術メモ

# elastic email

elastic email は初めて使ったけれど便利。 100通/日まではトライアルアカウントで送れるし、課金しても0.09$/1000通と破格。 クレジットカードで10$~

なお、npmの公式ページにはなかったような気がするけれど、 body_textbody_html にするとHTMLメールを送ることができた。 次はテンプレートにも挑戦したい。

const client = elasticemail.createClient({
    username: 'USER_NAME',
    apiKey: 'MY_API_KEY',
});

// 中略

const msg = {
    from: 'abc@xyz.com',
    from_name: 'NAME',
    to: 'xyz@abc.com',
    subject: 'お申込みありがとうございます',
    // body_text: mailBody,
    body_html: mailBody, // ここを変えた
};

client.mailer.send(msg, (err: any, result: any) => {
    if (err) {
        commit('raiseFetchError', 'mail_send_failed');
    } else {
        commit('mailOk', result);
    }
});

# Dark

Darkは遊びでしか触っていなかったけれど、めちゃくちゃ楽しい。 Trail Drivenというのが素晴らしい。 とにかくやってみて、失敗したときの変数や記録を残してくれているのがすごい。 そしてプログラムを書き換えたときに、同じ条件でやり直してくれる。 可視化の程度がすごすぎる。Dark大好き。Dark Love。 まだベータ段階で将来的な料金設定がどうなるか分からないけれど、絶対に使い続けたい。

Dark

強いていえば、ググラビリティが低いのが難点。 Darkで調べているのに、 「もしかして Dart と言われてしまう。 プログラミング言語同士、いっしょに検索する単語が似通っているのか、Darkと思って読んでいたらDartだったこともしばしば。 ここはDarkのこれからに期待。

# iframe

実はこれまであまり使っていなかった。 srcにv-bindできるのか、と思ってやってみたら成功したので、今回取り入れてみました。 データを別の静的HTMLにおいておけるから、便利かもしれない。

# 時間の都合で諦めたもの

# transition

Vueのtransitionを上手く使えたらもっとスムーズな挙動になったのですが、時間の都合で断念。 Vuetifyにしていれば、 y-transition とかですぐにできたのだけれど……

# Webフォントやアイコン

これも本当はこだわるべきなんだろうけど、手が回らず…… 次に機会があれば手を出したい。

# フォームのサイズやグループ

これも全くこだわれなかった部分。 どんな長さが想定される入力部分も、とりあえず一行分確保しているのでメリハリがない…… 本職の方々の力を思い知るところ。

# 最後に

突貫工事のため、いくつかうっかりミスがあったり、変なところで躓いたりしましたが、今は上手く動いてくれるのを祈るばかり。 あ、最後の最後に大量の静的サイトを作るのに、Jupyterを使ったのですが、やっぱりPythonは楽ですね。 {}でブロックを作らないのが見やすいし、同期/非同期をあまり意識しないので頭への負荷が低い気がします。 次はPython + Darkで何かしてみたいなぁ。

# PR

JavaScript 至極の入門書!すぐに動かして楽しめるVue/Nuxtもオススメ!

ゴールデンブリッジでは、
翻訳・通訳・インバウンドツアー・国際会議運営など
ご用命をお待ちしております!
また、翻訳に関わるツール・ソフトウェアの開発等についてもお気軽にお声掛けください。

株式会社ゴールデンブリッジ 公式Webサイト