Cal.com Vanilla JavaScript嵌入SvelteKit失败,报错Cal未找到及500错误
I've run into this exact issue when embedding Cal.com in SvelteKit, and the problem boils down to two key factors: server-side rendering (SSR) limitations and missing type declarations for the global Cal variable. Here's how to fix it step by step:
1. Why You're Seeing These Errors
- 500 Internal Error: SvelteKit runs your code on the server first, where the
windowobject doesn't exist. The vanilla Cal.com init code tries to accesswindowdirectly, which crashes during SSR. - "Cannot find name 'Cal'": Svelte's (or TypeScript's) type checker doesn't recognize the global
Calfunction injected by the Cal.com embed script.
2. Working Solution for SvelteKit
Option 1: Client-Side Only Initialization with onMount
Wrap the Cal.com init code in Svelte's onMount hook, which only runs in the browser (not on the server). This fixes the SSR issue, and we'll explicitly reference window.Cal to avoid type errors:
<script> import { onMount } from 'svelte'; onMount(() => { // Inject the Cal.com embed script and initialize (function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; typeof namespace === "string" ? (cal.ns[namespace] = api) && p(api, ar) : p(cal, ar); return; } p(cal, ar); }; })(window, "https://cal.com/embed.js", "init"); // Initialize Cal.com using window.Cal to bypass type checks window.Cal("init"); }); </script> <!-- Add your Cal.com embed element here --> <div data-cal-link="your-cal-username/your-event-slug"></div>
Option 2: Add Type Declarations (For TypeScript Users)
If you're using TypeScript, you can declare the global Cal variable to avoid the "Cannot find name" error without using window.Cal:
- Create or edit
src/app.d.tsin your SvelteKit project:
declare global { interface Window { Cal: (...args: any[]) => void; } } export {};
- Now you can use
Cal("init")directly inside theonMounthook, just like the vanilla docs:
<script> import { onMount } from 'svelte'; onMount(() => { // [Cal.com init code here] Cal("init"); // No more type errors! }); </script>
3. Alternative: Load the Script in app.html
If you want the Cal.com script loaded site-wide, you can add it to the end of the <body> tag in src/app.html:
<!-- src/app.html --> <body> %sveltekit.body% <script> (function (C, A, L) { // [Cal.com init code here] })(window, "https://cal.com/embed.js", "init"); Cal("init"); </script> </body>
This ensures the script runs only in the browser, but it's less flexible if you only need Cal.com on specific pages.
Key Takeaways
- Always wrap browser-specific code (like accessing
windowor third-party scripts) inonMountin SvelteKit to avoid SSR crashes. - For global variables from third-party scripts, either reference them via
windowor add type declarations to keep your code type-safe.
内容的提问来源于stack exchange,提问作者acerblaze

