Use Cases (Atualizado: 02/06/2026)

Desenvolvimento Svelte e SvelteKit com Claude Code

Guia pratico para usar Claude Code com Svelte/SvelteKit: setup, runes, rotas, form actions, testes e mudancas seguras.

Desenvolvimento Svelte e SvelteKit com Claude Code

Por que Claude Code combina com SvelteKit

Svelte e um framework de UI que compila componentes declarativos para JavaScript enxuto. SvelteKit adiciona a camada de aplicacao: rotas por arquivos, renderizacao no servidor, funcoes load, form actions, endpoints e adaptadores de deploy. Em um projeto real, uma pequena funcionalidade costuma tocar src/routes, src/lib/components, $lib/server, tipos gerados e testes.

Claude Code e uma ferramenta agentica de desenvolvimento capaz de ler o repositorio, editar arquivos e executar comandos. Em SvelteKit, o ganho aparece quando a tarefa e bem delimitada: primeiro ler os arquivos, depois explicar o fluxo de dados, propor o plano e so entao alterar o menor conjunto possivel. Pedidos amplos como “crie um SaaS em SvelteKit” misturam UI, banco, autenticacao, seguranca e deploy de uma vez.

Para iniciantes, o ponto critico e Svelte 5. Runes sao a forma atual de escrever reatividade: $props recebe entradas do componente, $state declara estado mutavel, $derived calcula valores a partir do estado e $effect deve ficar para efeitos de navegador. Este artigo usa um pequeno app de tarefas para mostrar setup, componentes, estado compartilhado, rotas, formularios, testes, prompts seguros e armadilhas.

flowchart LR
  A["Escrever um requisito pequeno"] --> B["Claude Code le arquivos relacionados"]
  B --> C["Editar componentes Svelte"]
  C --> D["Verificar load/actions"]
  D --> E["Rodar checks e testes"]
  E --> F["Revisar git diff manualmente"]

Setup do projeto

Para criar um app SvelteKit novo, o caminho oficial atual comeca com a CLI do Svelte: npx sv create my-app. Para um app Svelte independente com Vite, o template svelte-ts tambem e valido. O guia atual do Vite exige Node.js 20.19+ ou 22.12+ para o Vite, entao atualize o Node antes de investigar erros estranhos de build.

npx sv create claude-svelte-demo
cd claude-svelte-demo
npm install
npm run dev

claude

Em um repositorio novo, comece pelo plan mode. Claude Code pode explorar os arquivos e escrever um plano sem editar o codigo-fonte.

/plan
Quero adicionar uma lista de tarefas a este projeto SvelteKit.
Primeiro leia src/routes e src/lib, depois proponha os arquivos a mudar, o fluxo de dados e o plano de testes.
Ainda nao edite arquivos.
claude --permission-mode plan

Regras do projeto devem ficar em CLAUDE.md ou .claude/CLAUDE.md: gerenciador de pacotes, comandos de validacao, preferencia por Svelte 5 runes, uso de form actions, limite de arquivos, segredo apenas em $lib/server e nenhum commit sem pedido explicito. Regras concretas sao melhores do que “deixe o codigo bonito”.

Componentes pequenos com Svelte 5

O componente abaixo pode ser usado como src/lib/components/TaskCard.svelte. Ele recebe uma tarefa e uma funcao onToggle, calcula textos com $derived e mantem aria-pressed no botao.

<!-- src/lib/components/TaskCard.svelte -->
<script lang="ts">
  type Task = {
    id: string;
    title: string;
    done: boolean;
    estimateMinutes: number;
    tags: string[];
  };

  let {
    task,
    onToggle
  }: {
    task: Task;
    onToggle: (id: string) => void;
  } = $props();

  let statusLabel = $derived(task.done ? 'Concluida' : 'Aberta');
  let estimateLabel = $derived(`${Math.ceil(task.estimateMinutes / 15) * 15} min`);
</script>

<article class:done={task.done} class="task-card">
  <div>
    <p class="status">{statusLabel}</p>
    <h3>{task.title}</h3>
    <p>{estimateLabel}</p>
  </div>

  <ul aria-label="Tags">
    {#each task.tags as tag}
      <li>{tag}</li>
    {/each}
  </ul>

  <button type="button" aria-pressed={task.done} onclick={() => onToggle(task.id)}>
    {task.done ? 'Reabrir' : 'Marcar como concluida'}
  </button>
</article>

<style>
  .task-card {
    display: grid;
    gap: 0.75rem;
    border: 1px solid #ddd;
    border-radius: 0.5rem;
    padding: 1rem;
  }

  .done {
    background: #f2fff5;
  }

  .status {
    font-size: 0.875rem;
    font-weight: 700;
  }

  ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    list-style: none;
    padding: 0;
  }

  li {
    border-radius: 999px;
    background: #eef2ff;
    padding: 0.2rem 0.6rem;
  }
</style>

Prompt seguro:

Melhore src/lib/components/TaskCard.svelte mantendo a sintaxe Svelte 5 runes.
Condicoes:
- Nao altere o tipo Task nem a assinatura onToggle.
- Mantenha onclick e nao volte para on:click.
- Mantenha aria-pressed no botao.
- Melhore apenas layout e estados vazios.
- Depois sugira um teste de componente.

Esse nivel de detalhe impede que Claude Code altere a API publica do componente ou mexa em arquivos fora do escopo.

Estado compartilhado: runes primeiro, stores quando necessario

Svelte 5 permite usar runes em arquivos .svelte.ts. Eles sao bons para logica reativa reutilizavel e estado compartilhado. svelte/store ainda faz sentido para fluxos assincronos complexos, inscricoes manuais ou integracao com bibliotecas que ja usam stores.

// src/lib/state/taskFilters.svelte.ts
export type TaskStatus = 'all' | 'open' | 'done';

export const taskFilters = $state({
  query: '',
  status: 'all' as TaskStatus,
  tag: ''
});

export function resetTaskFilters() {
  taskFilters.query = '';
  taskFilters.status = 'all';
  taskFilters.tag = '';
}
<!-- src/lib/components/TaskFilterPanel.svelte -->
<script lang="ts">
  import { resetTaskFilters, taskFilters } from '$lib/state/taskFilters.svelte';
</script>

<section aria-label="Filtros de tarefas">
  <label>
    Palavra-chave
    <input bind:value={taskFilters.query} placeholder="Fatura, artigo, revisao..." />
  </label>

  <label>
    Status
    <select bind:value={taskFilters.status}>
      <option value="all">Todas</option>
      <option value="open">Abertas</option>
      <option value="done">Concluidas</option>
    </select>
  </label>

  <button type="button" onclick={resetTaskFilters}>Resetar</button>
</section>

O erro comum e esquecer SSR. window, document e localStorage nao existem no servidor. Para persistir algo no navegador, use browser de $app/environment.

// src/lib/state/theme.svelte.ts
import { browser } from '$app/environment';

export const themeState = $state({
  theme: 'system' as 'system' | 'light' | 'dark'
});

export function loadTheme() {
  if (!browser) return;
  const saved = localStorage.getItem('theme');
  if (saved === 'light' || saved === 'dark' || saved === 'system') {
    themeState.theme = saved;
  }
}

export function saveTheme(nextTheme: typeof themeState.theme) {
  themeState.theme = nextTheme;
  if (browser) localStorage.setItem('theme', nextTheme);
}

Rotas, load e fronteira do servidor

SvelteKit usa roteamento por arquivos. src/routes/about cria /about; src/routes/tasks/[slug] cria uma rota dinamica com parametro slug. Se a pagina precisa de dados antes de renderizar, use +page.server.ts. Banco de dados, chaves privadas e APIs privilegiadas devem ficar em $lib/server.

// src/lib/server/tasks.ts
export type Task = {
  id: string;
  slug: string;
  title: string;
  done: boolean;
  estimateMinutes: number;
  tags: string[];
};

const tasks: Task[] = [
  {
    id: 'task-1',
    slug: 'write-svelte-guide',
    title: 'Rascunhar o artigo de SvelteKit',
    done: false,
    estimateMinutes: 45,
    tags: ['writing', 'svelte']
  }
];

export async function getTaskBySlug(slug: string) {
  return tasks.find((task) => task.slug === slug) ?? null;
}
// src/routes/tasks/[slug]/+page.server.ts
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
import { getTaskBySlug } from '$lib/server/tasks';

export const load: PageServerLoad = async ({ params }) => {
  const task = await getTaskBySlug(params.slug);

  if (!task) {
    error(404, 'Task not found');
  }

  return { task };
};
<!-- src/routes/tasks/[slug]/+page.svelte -->
<script lang="ts">
  import type { PageProps } from './$types';

  let { data }: PageProps = $props();
</script>

<svelte:head>
  <title>{data.task.title} | Tasks</title>
</svelte:head>

<article>
  <p>{data.task.done ? 'Concluida' : 'Aberta'}</p>
  <h1>{data.task.title}</h1>
  <p>Estimativa: {data.task.estimateMinutes} minutos</p>
</article>
Leia src/routes/tasks/[slug] e src/lib/server/tasks.ts.
Adicione um campo dueDate ao Task e mostre na pagina de detalhe.
Mantenha acesso a dados do servidor em $lib/server.
Nao renomeie o diretorio [slug].
Execute npm run check no final.

Form actions e melhoria progressiva

SvelteKit form actions permitem exportar actions de +page.server.ts e enviar um <form method="POST"> ao servidor. O formulario funciona sem JavaScript; use:enhance melhora a experiencia quando JavaScript esta disponivel.

// src/routes/contact/+page.server.ts
import { fail } from '@sveltejs/kit';
import type { Actions } from './$types';

export const actions = {
  default: async ({ request }) => {
    const formData = await request.formData();
    const values = {
      name: String(formData.get('name') ?? '').trim(),
      email: String(formData.get('email') ?? '').trim(),
      message: String(formData.get('message') ?? '').trim()
    };

    const errors: Record<string, string> = {};
    if (values.name.length < 2) errors.name = 'Digite pelo menos 2 caracteres.';
    if (!values.email.includes('@')) errors.email = 'Confira o email.';
    if (values.message.length < 10) errors.message = 'Digite pelo menos 10 caracteres.';

    if (Object.keys(errors).length > 0) {
      return fail(400, { values, errors });
    }

    console.log('New inquiry', values);
    return { success: true };
  }
} satisfies Actions;
<!-- src/routes/contact/+page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
  import type { PageProps } from './$types';

  let { form }: PageProps = $props();
</script>

{#if form?.success}
  <p role="status">Enviado. Responderemos em 1 a 3 dias uteis.</p>
{/if}

<form method="POST" use:enhance>
  <label>
    Nome
    <input name="name" value={form?.values?.name ?? ''} aria-invalid={!!form?.errors?.name} />
  </label>
  {#if form?.errors?.name}<p>{form.errors.name}</p>{/if}

  <label>
    Email
    <input name="email" type="email" value={form?.values?.email ?? ''} aria-invalid={!!form?.errors?.email} />
  </label>
  {#if form?.errors?.email}<p>{form.errors.email}</p>{/if}

  <label>
    Mensagem
    <textarea name="message" rows="5" aria-invalid={!!form?.errors?.message}>{form?.values?.message ?? ''}</textarea>
  </label>
  {#if form?.errors?.message}<p>{form.errors.message}</p>{/if}

  <button type="submit">Enviar</button>
</form>

Nao use GET para efeitos colaterais, nao exponha chaves privadas no cliente e nao renderize HTML nao confiavel com {@html} sem sanitizacao. No prompt, escreva que a validacao no servidor, o funcionamento sem JavaScript e os atributos de acessibilidade devem permanecer.

Testes, casos de uso e armadilhas

A documentacao de testes do Svelte aponta Vitest como uma boa escolha para projetos Vite e SvelteKit. Testing Library ajuda a testar comportamento de usuario; Playwright fica para fluxos completos.

// src/lib/components/TaskCard.test.ts
import { fireEvent, render, screen } from '@testing-library/svelte';
import { describe, expect, it } from 'vitest';
import TaskCard from './TaskCard.svelte';

describe('TaskCard', () => {
  it('toggles the task when the button is clicked', async () => {
    let toggledId = '';

    render(TaskCard, {
      task: {
        id: 'task-1',
        title: 'Escrever o artigo de SvelteKit',
        done: false,
        estimateMinutes: 45,
        tags: ['writing']
      },
      onToggle: (id) => {
        toggledId = id;
      }
    });

    await fireEvent.click(screen.getByRole('button', { name: 'Marcar como concluida' }));
    expect(toggledId).toBe('task-1');
  });
});
npm run check
npm run test
npm run build
git diff -- src/lib src/routes
Caso de usoBom trabalho para Claude CodeRevisao humana
Filtros adminSeparar filtros com $state e $derivedCondicoes na URL e campos por permissao
Blog ou CMSConectar [slug], load, SEO e 404Sanitizacao HTML, rascunhos e preview
Formularios de leadsActions, validacao, use:enhance, testesPrivacidade, spam, destino da notificacao
Migracao Svelte 4 para 5Converter componentes escolhidos para runesEvitar mudancas grandes sem revisao

As falhas comuns sao pedir tudo de uma vez, misturar sintaxe Svelte 4 e 5, importar $lib/server em componentes, usar $effect para calculos que deveriam ser $derived, e aceitar testes fracos. Para monetizacao, SvelteKit conecta conteudo tecnico a formularios e consultoria; veja a pagina de consultoria Claude Code. Continue com o guia inicial, dicas TypeScript e estrategias de teste.

Fontes oficiais e resultado testado

Use fontes oficiais quando o comportamento importar: Svelte docs, SvelteKit docs, SvelteKit form actions, Vite guide e Claude Code docs.

Leia a estrutura atual do SvelteKit e altere apenas este escopo.
Arquivos: src/routes/contact/+page.svelte e src/routes/contact/+page.server.ts
Objetivo: adicionar campo company ao formulario.
Restricoes:
- Manter Svelte 5 runes.
- Nao remover use:enhance.
- Adicionar validacao no servidor.
- Nao alterar texto de CTA nem classes de layout.
- Executar npm run check antes de terminar.
Finalize com 3 linhas: mudancas, risco e testes faltantes.

Masa testou esse fluxo em um app pequeno de tarefas com SvelteKit. Comecar em plan mode reduziu retrabalho. As instrucoes “manter runes”, “executar npm run check” e “nao fazer commit” produziram diffs menores e mais faceis de revisar.

#Claude Code #Svelte #SvelteKit #frontend #TypeScript
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.