Lesson 1 of 5 · Full-Stack & Middleware Engineering
SvelteKit & TypeScript
SvelteKit builds full apps from reusable components; TypeScript helps catch type mistakes when you run the project's checks; runtime validation is still required.
This lesson is locked. You can read ahead, but finish earlier stops to earn progress.
Listen
Watch
Read
Why leave handwritten pages?
Your Level 3 calculator manages selectors and DOM updates manually. A component framework connects data and interface more directly. A component bundles a reusable piece of interface and its behaviour. Svelte compiles components; SvelteKit adds routing, server endpoints, development tooling and deployment support. TypeScript checks the shapes of values before you run them.
You are learning this stack in a separate project, not replacing your working studio website. Keep the earlier product and its Git history intact. The final level combines a reactive page, hosted data and a validated server endpoint into one real product.
Scaffold in a deliberate location
Confirm Node LTS and npm work using node -v and npm -v. In VS Code's terminal, navigate to the parent workspace folder, not inside your existing website or node_modules. Use pwd on Mac or Get-Location in PowerShell to confirm.
npx sv create svelte-studio
sv is Svelte's scaffolder. It downloads/runs a tool and asks about the starter project. Read the prompts; wording can change with versions. Choose the minimal SvelteKit template and TypeScript. Optional extras are not needed for the first rehearsal. If it offers to install dependencies, note whether it actually did.
cd svelte-studio npm install npm run dev -- --open
npm install resolves the project's dependencies. If the wizard already installed them, rerunning it is normally unnecessary but does not create a second project. -- --open passes the open-browser option to the development command. Use the exact URL printed by the terminal; a busy port can produce a different one. Keep the terminal running. Stop with Ctrl+C when finished.
Find the files before editing
| File or folder | Purpose |
|---|---|
| package.json | Dependencies and named scripts |
| package-lock.json | Exact resolved dependency versions; keep it in Git |
| src/routes/+page.svelte | Page for the root URL |
| src/routes/about/+page.svelte | Page for /about, if you create it |
| src/routes/api/products/+server.ts | Server endpoint for /api/products, created later |
| src/lib | Shared components/helpers |
| node_modules | Downloaded packages, not your source; do not commit |
The plus sign is meaningful. A file called page.svelte instead of +page.svelte will not become a SvelteKit route. A server endpoint is not a visible page component. You will add it in the middleware lesson.
Build one reactive rehearsal
In the generated src/routes/+page.svelte, study this small practice component. Use your own labels and explain each line before adapting it:
<script lang="ts">
let count = $state(0);
function addOne() {
count = count + 1;
}
</script>
<h1>Practice counter</h1>
<p>Count: {count}</p>
<button onclick={addOne}>Add one</button>lang="ts" enables TypeScript inside the script. $state(0) creates reactive state with a starting numeric value of zero. Braces in markup display an expression. onclick={addOne} passes the function to run on click; onclick={addOne()} would call it immediately during setup instead.
First render: count is 0. First click: the function assigns 1 and Svelte updates the paragraph. Second click: count becomes 2. You do not manually select that paragraph or set textContent. Save the file; the development server refreshes the page as you edit. A browser reload normally resets this in-memory state to 0—it is not database persistence.
Extract a component when there is something to reuse
Create src/lib/PracticeCounter.svelte and move the rehearsal markup and script into it. In the root page:
<script lang="ts"> import PracticeCounter from '$lib/PracticeCounter.svelte'; </script> <h1>My practice studio</h1> <PracticeCounter />
$lib points to src/lib. Render a second <PracticeCounter /> temporarily. Click only the first: each instance should keep its own state. This shows what “reusable component” means without a complicated application architecture. Remove the duplicate after the experiment if your product needs only one.
Read a type error instead of suppressing it
TypeScript infers a number from the initial 0. Temporarily try assigning "many" to count in your disposable rehearsal. The editor should report that a string is not assignable to a number. Read the reported file, line and types, then restore a numeric assignment. Do not use any or a type assertion to hide the disagreement.
A type declaration can describe a product:
type Product = { name: string; price: number };
const sample: Product = { name: 'Notebook', price: 12 };price: "12" would fail the type check. But data arriving from an HTTP request is not automatically trustworthy because your code has a Product type. Zod's runtime validation is a separate check taught later.
Run npm run check from the project root to check Svelte/TypeScript diagnostics, and npm run build to compile the production application. Do not assume a visible page or a running dev server means every type is correct. Some tools transpile code while type errors still exist; the explicit check matters.
Guided changes
- Predict the value after three clicks, then test it.
- Add a second small function that resets the counter to zero; connect your own reset control. Explain why assigning a number is valid.
- Change the increment from one to two. Confirm the displayed sequence, then reset and retest.
- Extract the component and confirm it still renders from the page.
- Reload and explain why the count resets. Your next database lesson will add durable storage; state alone does not do that.
Troubleshoot by evidence
| Symptom | Check |
|---|---|
| Scaffold says folder exists | Choose a new folder; do not overwrite a product you need |
| Missing package.json | Terminal is in the wrong folder; cd into the generated app |
| Page doesn't change on click | Check $state, event spelling and function reference |
| Component import fails | Exact path, filename case and .svelte extension |
| Browser cannot connect | Keep dev server running and use its printed URL |
| Type error after changing a value | Compare the assigned value's type with the declared/inferred type |
Ready for activity 4.1
Show the generated SvelteKit dependencies/scripts in package.json, a working reactive control and the terminal check result. Keep the component and lockfile in the synced project and commit the change using your earlier Git workflow. Do not submit node_modules or rely on copying the example without understanding the state trace. You should now be able to build a small reactive component and locate the page where it belongs.
Key terms
- Component
- A reusable piece of UI with its own markup and logic.
- $state
- A reactive value — change it and the UI updates.
- TypeScript
- JavaScript plus type annotations that catch errors early.
- Scaffolding
- Generating a starter project with one command.
Summary — copy into your notes
- Apps are built from reusable components.
- npx sv create scaffolds a SvelteKit app.
- $state makes UI reactive.
- TypeScript catches mistakes before they run.