SvelteKit
フォームを Ikiform に直接送信し、JavaScript が読み込まれると fetch で拡張される、プリレンダリングされた SvelteKit のページ。adapter-static でも動きます。
このページにサーバーは不要です。フォームの action は Ikiform のエンドポイントなので、adapter-static やどの静的ホストでも動きます。JavaScript がなければプレーンな HTML のように送信してリダイレクトし、JavaScript があれば fetch で送信して結果をその場に表示します。代わりにシークレットキーを使ってフォームアクション経由で送信するには、Svelte を参照してください。
use:enhance を使わない理由
SvelteKit の use:enhance が動くのは、+page.server.js で定義したアクションに向けた method="POST" のフォームだけです。Ikiform は外部の URL なので、このページでは代わりに小さな onsubmit ハンドラーを使います。プログレッシブエンハンスメントの考え方は同じで、まずフォームが動き、スクリプトがそれを改善します。
セットアップ
公開環境変数を追加する
.env PUBLIC_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx PUBLIC_SITE_URL=https://example.comPUBLIC_SITE_URLは JavaScript なしの場合のリダイレクト用です。プリレンダリング中のpage.url.originは自分のドメインではなくhttp://sveltekit-prerenderなので、そこからリダイレクトを組み立てることはできません。ページをプリレンダリングする
src/routes/contact/+page.js export const prerender = true;フォームを追加する
src/routes/contact/+page.svelte <script> import { PUBLIC_IKIFORM_FORM_ID, PUBLIC_SITE_URL } from "$env/static/public"; const endpoint = `https://ikiform.com/f/${PUBLIC_IKIFORM_FORM_ID}`; let status = $state("idle"); let errors = $state({}); let message = $state(""); async function onsubmit(event) { event.preventDefault(); status = "sending"; try { const response = await fetch(endpoint, { method: "POST", headers: { Accept: "application/json" }, body: new FormData(event.currentTarget), }); const result = await response.json(); if (result.ok) { status = "sent"; return; } errors = result.error.fields ?? {}; message = result.error.message; } catch { message = "Couldn't reach the server. Try again."; } status = "error"; } </script> {#if status === "sent"} <p>Thanks, we got it.</p> {:else} <form action={endpoint} method="POST" {onsubmit}> <label> Email <input name="email" type="email" autocomplete="email" required aria-invalid={errors.email ? "true" : undefined} /> </label> {#if errors.email}<p>{errors.email[0]}</p>{/if} <label> Message <textarea name="message" rows="5"></textarea> </label> <input type="hidden" name="_redirect" value={`${PUBLIC_SITE_URL}/contact/thanks`} /> <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden /> {#if status === "error" && !errors.email}<p role="alert">{message}</p>{/if} <button disabled={status === "sending"}>{status === "sending" ? "Sending" : "Send"}</button> </form> {/if}リダイレクト先として
src/routes/contact/thanks/+page.svelteを追加します。
SvelteKit の CSP を使う場合
kit.csp を設定している場合は、fetch の送信とプレーンなフォームの送信の両方で Ikiform を許可してください。そうしないと、ブラウザーがどちらかをブロックします。
const config = {
kit: {
csp: {
directives: {
"connect-src": ["self", "https://ikiform.com"],
"form-action": ["self", "https://ikiform.com"],
},
},
},
};
export default config;許可ドメイン
本番に加えて、プレビューのホストを登録します。
| フォームが動く場所 | 許可ドメインに追加するもの |
|---|---|
vite dev | localhost。http://localhost:5173 に一致します。Ikiform が比較するのはホスト名だけで、ポートは比較しません。 |
| 自分のドメイン | example.com(www.example.com も含まれます) |
| Vercel | your-project.vercel.app。your-project-git-branch-team.vercel.app のようなプレビュー URL は一致しないので、テストする間はプレビューの正確なホストを追加してください。 |
| Cloudflare Pages | your-project.pages.dev。abc123.your-project.pages.dev のようなプレビュー URL はそのサブドメインなので、すでに一致します。 |
| Netlify | your-site.netlify.app。デプロイプレビュー(deploy-preview-12--your-site.netlify.app)やブランチデプロイ(branch--your-site.netlify.app)はそのサブドメインではないので、テストする間はプレビューの正確なホストを追加してください。 |
vercel.app、pages.dev、netlify.appだけを追加しないでください。他の人のサイトも含め、そのホスト上のすべてのサイトが一致してしまいます。
テストのチェックリスト
- 許可ドメインに
localhostを入れて開発サーバーを実行し、送信します。お礼のメッセージがフォームに置き換わるはずです。 vite buildを実行し、出力のcontact.htmlにすでにフォームが含まれていることを確認します。- JavaScript をオフにし、再読み込みして送信します。
https:のドメインでは/contact/thanksに移動するはずです。 - プレビューのデプロイから送信し、スパムになっていないことを確認します。
トラブルシューティング
| 症状 | 原因 | 対処 |
|---|---|---|
PUBLIC_IKIFORM_FORM_ID が $env/static/public からエクスポートされていないというエラーでビルドが失敗する | ビルドを実行する環境で変数が設定されていない | ローカルでは .env に、ホスティング先ではビルド設定に追加します。 |
送信しても何も起きず、コンソールに x-sveltekit-action ヘッダーに関する CORS エラーが表示される | アプリの外に送信するフォームに use:enhance が付いている | それを削除し、onsubmit ハンドラーを残します。 |
form-action または connect-src のせいで、ブラウザーがフォームの送信を拒否する | kit.csp に Ikiform が含まれていない | 両方のディレクティブに https://ikiform.com を追加します。 |
| JavaScript なしだと Ikiform のサンクスページに移動する | PUBLIC_SITE_URL が http:、またはドメインが許可ドメインにない | https: のアドレスを使い、ドメインを追加します。 |
送信データが origin_mismatch でスパムフィルターの下に届く | 送信したページが、フォームの許可ドメインに含まれていない | 上の表のホストを追加します。Reject を選んでいる場合、同じ送信には代わりに 403 origin_not_allowed が返ります。 |