NNicheStackTutorials
← All tutorials
SvelteKit

Build a Mini Converter Tool in SvelteKit (100% Static, Client-Side Only)

JSON-to-YAML converter as a prerendered page with csr:true. No API routes, works on GitHub Pages.

·13 min read·SvelteKit
Build a Mini Converter Tool in SvelteKit (100% Static, Client-Side Only) cover

Tested on: SvelteKit 2.16, js-yaml 4.1 Goal: /tools/json-to-yaml — paste JSON, get YAML. Zero server.

Route setup

src/routes/tools/json-to-yaml/
├── +page.svelte
└── +page.ts

+page.ts:

export const prerender = true;
export const csr = true; // needs interactivity

The page

<script lang="ts">
  let input = $state('{"hello": "world"}');
  let output = $state('');
  let error = $state('');

  async function convert() {
    error = '';
    output = '';
    try {
      const obj = JSON.parse(input);
      const yaml = await import('js-yaml');
      output = yaml.dump(obj, { indent: 2, lineWidth: 80 });
    } catch (e) {
      error = e instanceof Error ? e.message : 'Invalid JSON';
    }
  }
</script>

<svelte:head>
  <title>JSON to YAML Converter</title>
  <meta name="description" content="Free client-side JSON to YAML converter." />
</svelte:head>

<h1>JSON → YAML</h1>
<textarea bind:value={input} rows="12" class="w-full font-mono"></textarea>
<button onclick={convert}>Convert</button>

{#if error}
  <p class="text-red-600">{error}</p>
{/if}

{#if output}
  <pre class="bg-gray-100 p-4 rounded"><code>{output}</code></pre>
  <button onclick={() => navigator.clipboard.writeText(output)}>Copy</button>
{/if}

Error — yaml in server bundle

'js-yaml' is imported by ... but could not be resolved during SSR

Dynamic import inside the click handler (shown above) keeps it client-only.

SEO for tool pages

Add structured data in +page.svelte:

<svelte:head>
  {@html `<script type="application/ld+json">${JSON.stringify({
    '@context': 'https://schema.org',
    '@type': 'WebApplication',
    name: 'JSON to YAML Converter',
    applicationCategory: 'DeveloperApplication',
    offers: { '@type': 'Offer', price: '0' }
  })}</script>`}
</svelte:head>

Shared tools layout

src/routes/tools/+layout.svelte:

<script lang="ts">
  let { children } = $props();
</script>

<nav>
  <a href="/tools/json-to-yaml/">JSON→YAML</a>
  <a href="/tools/base64/">Base64</a>
</nav>
{@render children()}

src/routes/tools/+layout.ts:

export const prerender = true;
export const csr = true;

Build output check

npm run build
ls build/tools/json-to-yaml/
# index.html + _app/ chunks with js-yaml lazy chunk

Real user error handling

JSON.parse: Unexpected token } in JSON at position 47

Show the raw message — developers need line-level feedback, not "Something went wrong."

Metrics after deploy

Page weight: 12 KB HTML + 48 KB JS (on first convert click)
Lighthouse Performance: 96
Works on Cloudflare Pages, Netlify, GitHub Pages
Zero server cost per conversion

Tags: SvelteKitToolsStatic SiteClient-Side