SvelteKit
폼이 Ikiform으로 바로 POST하고, JavaScript가 로드되면 fetch로 향상되는 프리렌더링 SvelteKit 페이지. adapter-static과 함께 작동합니다.
이 페이지는 서버가 필요 없습니다. 폼의 action이 Ikiform 엔드포인트이므로 adapter-static과 모든 정적 호스트에서 작동합니다. JavaScript가 없으면 일반 HTML처럼 POST하고 리디렉션하며, JavaScript가 있으면 fetch로 POST하고 결과를 그 자리에 보여 줍니다. 대신 시크릿 키를 사용하는 폼 액션으로 POST하려면 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 POST와 일반 폼 POST 모두에 Ikiform을 허용하세요. 그렇지 않으면 브라우저가 둘 중 하나를 막습니다.
const config = {
kit: {
csp: {
directives: {
"connect-src": ["self", "https://ikiform.com"],
"form-action": ["self", "https://ikiform.com"],
},
},
},
};
export default config;Allowed domains
프로덕션과 미리보기 호스트를 등록하세요.
| 폼이 실행되는 곳 | Allowed domains에 추가할 값 |
|---|---|
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에서 export되지 않았다며 실패함 | 빌드가 실행되는 곳에 변수가 설정되지 않음 | 로컬의 .env와 호스트의 빌드 설정에 추가하세요. |
제출해도 아무 일이 없고, 콘솔에 x-sveltekit-action 헤더에 관한 CORS 오류가 표시됨 | 앱 밖으로 POST하는 폼에 use:enhance를 사용함 | 제거하고 onsubmit 핸들러를 유지하세요. |
form-action이나 connect-src 때문에 브라우저가 폼 전송을 거부함 | kit.csp에 Ikiform이 없음 | 두 지시어 모두에 https://ikiform.com을 추가하세요. |
| JavaScript 없이 제출하면 Ikiform의 감사 페이지로 이동함 | PUBLIC_SITE_URL이 http:이거나, 도메인이 허용 도메인에 없음 | https: 주소를 사용하고 도메인을 추가하세요. |
제출이 origin_mismatch와 함께 스팸 필터에 들어감 | POST한 페이지가 폼의 허용 도메인에 없음 | 위 표의 호스트를 추가하세요. Reject를 골랐다면 같은 POST가 대신 403 origin_not_allowed를 받습니다. |