@icarusmx/creta 1.5.12 → 1.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1340 @@
1
+ # SvelteKit First Steps - Project Structure Without the Confusion
2
+
3
+ <!-- vim: set foldmethod=marker foldlevel=0: -->
4
+
5
+ ## 📖 LazyVim Reading Guide {{{
6
+
7
+ **Start with:** `zM` (close all folds) → Navigate with `za` (toggle fold under cursor)
8
+
9
+ This document uses fold markers `{{{` and `}}}` for organized reading.
10
+
11
+ }}}
12
+
13
+ ## 🚨 Problem: "Where Does This File Go?" {{{
14
+
15
+ You're building a SvelteKit app and constantly wondering:
16
+ - **"Should this component go in `src/lib` or `src/routes`?"**
17
+ - **"What's the difference between a `.svelte` file and a `+page.svelte` file?"**
18
+ - **"Do I need to write something in `index.js`?"**
19
+ - **"Where do API endpoints go?"**
20
+
21
+ **Common confusion:**
22
+ - Components scattered between routes and lib
23
+ - Not understanding the `$lib` alias
24
+ - Creating `+server.js` files in the wrong place
25
+ - Overengineering with unnecessary barrel exports
26
+
27
+ **The root cause:** SvelteKit has special file naming conventions that aren't immediately obvious.
28
+
29
+ }}}
30
+
31
+ ## ✅ Solution: Understanding SvelteKit's File Structure {{{
32
+
33
+ SvelteKit uses **file-based routing** with special file names that have specific meanings.
34
+
35
+ **Think of it like this:**
36
+ - **`src/routes/`** = Your website's pages and API endpoints (what users can visit)
37
+ - **`src/lib/`** = Your shared toolbox (reusable code that powers your pages)
38
+
39
+ **What SvelteKit gives you:**
40
+ - 📁 **Clear separation** - Routes vs reusable code
41
+ - 🔗 **$lib alias** - Import from anywhere with `$lib/...`
42
+ - 🎯 **Convention over configuration** - Special file names do special things
43
+ - ⚡ **Automatic routing** - File structure = URL structure
44
+
45
+ **Core concept:** The `src/routes/` folder structure directly maps to your URLs, while `src/lib/` is your private code library.
46
+
47
+ }}}
48
+
49
+ ## 🎯 Core Concepts {{{
50
+
51
+ ### src/routes/ - Your Website Structure {{{
52
+
53
+ **What lives here:**
54
+ - Pages users can visit (`+page.svelte`)
55
+ - Layouts that wrap pages (`+layout.svelte`)
56
+ - API endpoints (`+server.js`)
57
+ - Server-side logic (`+page.server.js`, `+layout.server.js`)
58
+
59
+ **File structure = URL structure:**
60
+ ```
61
+ src/routes/
62
+ ├── +page.svelte → /
63
+ ├── about/
64
+ │ └── +page.svelte → /about
65
+ ├── blog/
66
+ │ ├── +page.svelte → /blog
67
+ │ └── [slug]/
68
+ │ └── +page.svelte → /blog/my-post
69
+ └── api/
70
+ ├── contact/
71
+ │ └── +server.js → /api/contact (POST, GET, etc.)
72
+ └── users/
73
+ └── +server.js → /api/users
74
+ ```
75
+
76
+ **Special files in routes:**
77
+ - `+page.svelte` - A page component
78
+ - `+layout.svelte` - Wraps multiple pages
79
+ - `+server.js` - API endpoint (handles HTTP requests)
80
+ - `+page.server.js` - Server-side page logic
81
+ - `+error.svelte` - Error page
82
+
83
+ **Example URL mapping:**
84
+ ```bash
85
+ src/routes/products/+page.svelte → https://yoursite.com/products
86
+ src/routes/products/[id]/+page.svelte → https://yoursite.com/products/123
87
+ src/routes/api/products/+server.js → https://yoursite.com/api/products
88
+ ```
89
+
90
+ }}}
91
+
92
+ ### src/lib/ - Your Code Toolbox {{{
93
+
94
+ **What lives here:**
95
+ - Reusable components (`Footer.svelte`, `Navbar.svelte`)
96
+ - Utility functions (`formatDate.js`, `validation.js`)
97
+ - API client code (functions that CALL external APIs)
98
+ - Shared constants and configs
99
+ - Database query functions
100
+ - Any code used by multiple routes
101
+
102
+ **Common structure:**
103
+ ```
104
+ src/lib/
105
+ ├── components/
106
+ │ ├── Footer.svelte
107
+ │ ├── Navbar.svelte
108
+ │ └── Button.svelte
109
+ ├── utils/
110
+ │ ├── formatDate.js
111
+ │ └── validation.js
112
+ ├── api/
113
+ │ └── emailClient.js # Functions that call external APIs
114
+ ├── db/
115
+ │ └── queries.js # Database helper functions
116
+ └── index.js # Optional barrel exports
117
+ ```
118
+
119
+ **The `$lib` alias:**
120
+ ```javascript
121
+ // Import from anywhere in your app
122
+ import Footer from '$lib/components/Footer.svelte';
123
+ import { formatDate } from '$lib/utils/formatDate.js';
124
+ import { sendEmail } from '$lib/api/emailClient.js';
125
+ ```
126
+
127
+ **Key insight:** `$lib` is just an alias for `src/lib/`. You can import from ANY file inside `src/lib/` directly using this alias.
128
+
129
+ }}}
130
+
131
+ ### The Optional index.js {{{
132
+
133
+ **What it does:**
134
+ `src/lib/index.js` is an **optional convenience file** for barrel exports.
135
+
136
+ **Without index.js (direct imports):**
137
+ ```javascript
138
+ import Footer from '$lib/components/Footer.svelte';
139
+ import Navbar from '$lib/components/Navbar.svelte';
140
+ import { formatDate } from '$lib/utils/formatDate.js';
141
+ ```
142
+
143
+ **With index.js (barrel exports):**
144
+ ```javascript
145
+ // src/lib/index.js
146
+ export { default as Footer } from './components/Footer.svelte';
147
+ export { default as Navbar } from './components/Navbar.svelte';
148
+ export { formatDate } from './utils/formatDate.js';
149
+ ```
150
+
151
+ Then you can do:
152
+ ```javascript
153
+ import { Footer, Navbar, formatDate } from '$lib';
154
+ ```
155
+
156
+ **When to use it:**
157
+ - ✅ **Use barrel exports** if you have many related exports and want a cleaner import
158
+ - ❌ **Skip it** for simple projects where direct imports are clearer (preferred for most cases)
159
+
160
+ **Pro tip:** For simple projects, direct imports are more explicit and easier to trace. Don't overengineer with barrel exports unless you have a real need.
161
+
162
+ }}}
163
+
164
+ ### +server.js - API Endpoints {{{
165
+
166
+ **IMPORTANT:** `+server.js` files **ONLY** go in `src/routes/`
167
+
168
+ **What they do:**
169
+ Create API endpoints your app exposes to the world.
170
+
171
+ **Example - Contact Form API:**
172
+ ```javascript
173
+ // src/routes/api/contact/+server.js
174
+ export async function POST({ request }) {
175
+ const data = await request.json();
176
+
177
+ // Process the contact form
178
+ await sendEmail(data.email, data.message);
179
+
180
+ return new Response(
181
+ JSON.stringify({ success: true }),
182
+ { headers: { 'Content-Type': 'application/json' } }
183
+ );
184
+ }
185
+ ```
186
+
187
+ This creates: `https://yoursite.com/api/contact` (POST)
188
+
189
+ **HTTP methods:**
190
+ ```javascript
191
+ // src/routes/api/users/+server.js
192
+ export async function GET() {
193
+ return new Response(JSON.stringify({ users: [...] }));
194
+ }
195
+
196
+ export async function POST({ request }) {
197
+ // Create new user
198
+ }
199
+
200
+ export async function PUT({ request }) {
201
+ // Update user
202
+ }
203
+
204
+ export async function DELETE({ request }) {
205
+ // Delete user
206
+ }
207
+ ```
208
+
209
+ **Key distinction:**
210
+ - `src/routes/api/**/+server.js` → API endpoints your app **exposes**
211
+ - `src/lib/api/client.js` → Functions that **call** external APIs (helper code)
212
+
213
+ **You NEVER write `+server.js` files in `src/lib/`** - that's not how it works!
214
+
215
+ }}}
216
+
217
+ }}}
218
+
219
+ ## 🏗️ Setting Up Your First SvelteKit Project {{{
220
+
221
+ ### Step 1: Create a New Project {{{
222
+
223
+ **Using create-svelte:**
224
+ ```bash
225
+ # Create new project
226
+ npm create svelte@latest my-app
227
+
228
+ # Choose options:
229
+ # - SvelteKit demo app (for learning) or Skeleton project
230
+ # - No TypeScript (if you prefer JavaScript)
231
+ # - Add ESLint and Prettier
232
+
233
+ # Navigate and install
234
+ cd my-app
235
+ npm install
236
+ ```
237
+
238
+ **Start dev server:**
239
+ ```bash
240
+ npm run dev -- --open
241
+ # Server runs on http://localhost:5173
242
+ ```
243
+
244
+ **Initial structure:**
245
+ ```
246
+ my-app/
247
+ ├── src/
248
+ │ ├── routes/
249
+ │ │ └── +page.svelte # Homepage
250
+ │ ├── lib/
251
+ │ │ └── index.js # Empty initially
252
+ │ └── app.html # HTML template
253
+ ├── static/ # Static assets (favicon, images)
254
+ ├── svelte.config.js # SvelteKit config
255
+ └── package.json
256
+ ```
257
+
258
+ }}}
259
+
260
+ ### Step 2: Create Your First Reusable Component {{{
261
+
262
+ **Create a Navbar component:**
263
+ ```bash
264
+ # Create components directory
265
+ mkdir -p src/lib/components
266
+ ```
267
+
268
+ **src/lib/components/Navbar.svelte:**
269
+ ```svelte
270
+ <script>
271
+ let menuOpen = false;
272
+
273
+ function toggleMenu() {
274
+ menuOpen = !menuOpen;
275
+ }
276
+ </script>
277
+
278
+ <nav>
279
+ <div class="logo">MyApp</div>
280
+ <button on:click={toggleMenu}>Menu</button>
281
+
282
+ {#if menuOpen}
283
+ <ul>
284
+ <li><a href="/">Home</a></li>
285
+ <li><a href="/about">About</a></li>
286
+ <li><a href="/contact">Contact</a></li>
287
+ </ul>
288
+ {/if}
289
+ </nav>
290
+
291
+ <style>
292
+ nav {
293
+ padding: 1rem;
294
+ background: #333;
295
+ color: white;
296
+ }
297
+ </style>
298
+ ```
299
+
300
+ **Use it in your layout:**
301
+ ```svelte
302
+ <!-- src/routes/+layout.svelte -->
303
+ <script>
304
+ import Navbar from '$lib/components/Navbar.svelte';
305
+ </script>
306
+
307
+ <Navbar />
308
+ <main>
309
+ <slot /> <!-- Pages render here -->
310
+ </main>
311
+ ```
312
+
313
+ **What happened:**
314
+ - Created reusable Navbar in `src/lib/components/`
315
+ - Imported using `$lib/` alias
316
+ - Used in layout so it appears on all pages
317
+
318
+ }}}
319
+
320
+ ### Step 3: Create a Page {{{
321
+
322
+ **Create an About page:**
323
+ ```svelte
324
+ <!-- src/routes/about/+page.svelte -->
325
+ <script>
326
+ import { formatDate } from '$lib/utils/formatDate.js';
327
+
328
+ const today = formatDate(new Date());
329
+ </script>
330
+
331
+ <h1>About Us</h1>
332
+ <p>Page last updated: {today}</p>
333
+ ```
334
+
335
+ **Create the utility function:**
336
+ ```javascript
337
+ // src/lib/utils/formatDate.js
338
+ export function formatDate(date) {
339
+ return date.toLocaleDateString('en-US', {
340
+ year: 'numeric',
341
+ month: 'long',
342
+ day: 'numeric'
343
+ });
344
+ }
345
+ ```
346
+
347
+ **URL created:** `http://localhost:5173/about`
348
+
349
+ }}}
350
+
351
+ ### Step 4: Create an API Endpoint {{{
352
+
353
+ **Create a contact form endpoint:**
354
+ ```javascript
355
+ // src/routes/api/contact/+server.js
356
+ import { json } from '@sveltejs/kit';
357
+
358
+ export async function POST({ request }) {
359
+ const { name, email, message } = await request.json();
360
+
361
+ // Validate
362
+ if (!email || !message) {
363
+ return json(
364
+ { error: 'Email and message are required' },
365
+ { status: 400 }
366
+ );
367
+ }
368
+
369
+ // Process (send email, save to DB, etc.)
370
+ console.log('Contact form:', { name, email, message });
371
+
372
+ return json({ success: true });
373
+ }
374
+ ```
375
+
376
+ **Use the endpoint from a page:**
377
+ ```svelte
378
+ <!-- src/routes/contact/+page.svelte -->
379
+ <script>
380
+ let formData = { name: '', email: '', message: '' };
381
+ let status = '';
382
+
383
+ async function handleSubmit(e) {
384
+ e.preventDefault();
385
+
386
+ const response = await fetch('/api/contact', {
387
+ method: 'POST',
388
+ headers: { 'Content-Type': 'application/json' },
389
+ body: JSON.stringify(formData)
390
+ });
391
+
392
+ const result = await response.json();
393
+ status = result.success ? 'Message sent!' : 'Error sending message';
394
+ }
395
+ </script>
396
+
397
+ <form on:submit={handleSubmit}>
398
+ <input bind:value={formData.name} placeholder="Name" />
399
+ <input bind:value={formData.email} placeholder="Email" required />
400
+ <textarea bind:value={formData.message} placeholder="Message" required />
401
+ <button type="submit">Send</button>
402
+ </form>
403
+
404
+ {#if status}
405
+ <p>{status}</p>
406
+ {/if}
407
+ ```
408
+
409
+ **What happened:**
410
+ 1. Created API endpoint at `/api/contact`
411
+ 2. Endpoint handles POST requests
412
+ 3. Contact form page sends data to the endpoint
413
+ 4. All API logic is in `src/routes/api/`
414
+
415
+ }}}
416
+
417
+ }}}
418
+
419
+ ## 🎯 Decision Tree: Where Should This File Go? {{{
420
+
421
+ ### Is it a page users can visit? {{{
422
+
423
+ **YES** → `src/routes/[name]/+page.svelte`
424
+
425
+ **Examples:**
426
+ - Homepage → `src/routes/+page.svelte`
427
+ - About page → `src/routes/about/+page.svelte`
428
+ - Blog post → `src/routes/blog/[slug]/+page.svelte`
429
+ - User profile → `src/routes/users/[id]/+page.svelte`
430
+
431
+ }}}
432
+
433
+ ### Is it an API endpoint? {{{
434
+
435
+ **YES** → `src/routes/api/[name]/+server.js`
436
+
437
+ **Examples:**
438
+ - Contact form → `src/routes/api/contact/+server.js`
439
+ - User CRUD → `src/routes/api/users/+server.js`
440
+ - Webhook handler → `src/routes/webhook/+server.js`
441
+
442
+ **Remember:** `+server.js` files **ONLY** go in `src/routes/`!
443
+
444
+ }}}
445
+
446
+ ### Is it a component used by multiple pages? {{{
447
+
448
+ **YES** → `src/lib/components/[Name].svelte`
449
+
450
+ **Examples:**
451
+ - Navbar → `src/lib/components/Navbar.svelte`
452
+ - Footer → `src/lib/components/Footer.svelte`
453
+ - Button → `src/lib/components/Button.svelte`
454
+ - Card → `src/lib/components/Card.svelte`
455
+
456
+ }}}
457
+
458
+ ### Is it a utility function? {{{
459
+
460
+ **YES** → `src/lib/utils/[name].js`
461
+
462
+ **Examples:**
463
+ - Date formatting → `src/lib/utils/formatDate.js`
464
+ - Validation → `src/lib/utils/validation.js`
465
+ - String helpers → `src/lib/utils/strings.js`
466
+
467
+ }}}
468
+
469
+ ### Does it call external APIs? {{{
470
+
471
+ **YES** → `src/lib/api/[name].js`
472
+
473
+ **Examples:**
474
+ - Email service → `src/lib/api/emailClient.js`
475
+ - Payment processing → `src/lib/api/stripe.js`
476
+ - External API wrapper → `src/lib/api/github.js`
477
+
478
+ }}}
479
+
480
+ ### Is it database-related? {{{
481
+
482
+ **YES** → `src/lib/db/[name].js`
483
+
484
+ **Examples:**
485
+ - Database queries → `src/lib/db/queries.js`
486
+ - Database connection → `src/lib/db/connection.js`
487
+ - ORM models → `src/lib/db/models.js`
488
+
489
+ }}}
490
+
491
+ ### Is it server-only page logic? {{{
492
+
493
+ **YES** → `src/routes/[path]/+page.server.js`
494
+
495
+ **Use case:** Load data on the server before rendering the page
496
+
497
+ **Example:**
498
+ ```javascript
499
+ // src/routes/blog/[slug]/+page.server.js
500
+ export async function load({ params }) {
501
+ const post = await db.getPost(params.slug);
502
+ return { post };
503
+ }
504
+ ```
505
+
506
+ }}}
507
+
508
+ }}}
509
+
510
+ ## 🧪 Practice Exercises {{{
511
+
512
+ ### Exercise 1: Build a Reusable Card Component {{{
513
+
514
+ **Goal:** Create a card component in `src/lib` and use it on multiple pages
515
+
516
+ **Create the component:**
517
+ ```svelte
518
+ <!-- src/lib/components/Card.svelte -->
519
+ <script>
520
+ export let title;
521
+ export let description;
522
+ export let href = null;
523
+ </script>
524
+
525
+ <div class="card">
526
+ <h3>{title}</h3>
527
+ <p>{description}</p>
528
+ {#if href}
529
+ <a {href}>Learn more →</a>
530
+ {/if}
531
+ </div>
532
+
533
+ <style>
534
+ .card {
535
+ border: 1px solid #ddd;
536
+ border-radius: 8px;
537
+ padding: 1.5rem;
538
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
539
+ }
540
+
541
+ h3 {
542
+ margin-top: 0;
543
+ }
544
+ </style>
545
+ ```
546
+
547
+ **Use it on homepage:**
548
+ ```svelte
549
+ <!-- src/routes/+page.svelte -->
550
+ <script>
551
+ import Card from '$lib/components/Card.svelte';
552
+ </script>
553
+
554
+ <h1>Welcome</h1>
555
+
556
+ <div class="grid">
557
+ <Card
558
+ title="Feature 1"
559
+ description="Amazing feature description"
560
+ href="/features/1"
561
+ />
562
+ <Card
563
+ title="Feature 2"
564
+ description="Another cool feature"
565
+ href="/features/2"
566
+ />
567
+ </div>
568
+
569
+ <style>
570
+ .grid {
571
+ display: grid;
572
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
573
+ gap: 1rem;
574
+ }
575
+ </style>
576
+ ```
577
+
578
+ **Key learning:** Components in `src/lib/components/` can be reused anywhere with the `$lib` alias.
579
+
580
+ }}}
581
+
582
+ ### Exercise 2: Create a Todo API {{{
583
+
584
+ **Goal:** Build a simple todo API with GET and POST endpoints
585
+
586
+ **Create the API endpoint:**
587
+ ```javascript
588
+ // src/routes/api/todos/+server.js
589
+ import { json } from '@sveltejs/kit';
590
+
591
+ // In-memory storage (would be a database in production)
592
+ let todos = [
593
+ { id: 1, text: 'Learn SvelteKit', done: false },
594
+ { id: 2, text: 'Build an app', done: false }
595
+ ];
596
+
597
+ let nextId = 3;
598
+
599
+ // GET all todos
600
+ export async function GET() {
601
+ return json(todos);
602
+ }
603
+
604
+ // POST new todo
605
+ export async function POST({ request }) {
606
+ const { text } = await request.json();
607
+
608
+ if (!text) {
609
+ return json({ error: 'Text is required' }, { status: 400 });
610
+ }
611
+
612
+ const newTodo = {
613
+ id: nextId++,
614
+ text,
615
+ done: false
616
+ };
617
+
618
+ todos.push(newTodo);
619
+ return json(newTodo, { status: 201 });
620
+ }
621
+
622
+ // DELETE todo
623
+ export async function DELETE({ request }) {
624
+ const { id } = await request.json();
625
+ todos = todos.filter(todo => todo.id !== id);
626
+ return json({ success: true });
627
+ }
628
+ ```
629
+
630
+ **Create a page to use the API:**
631
+ ```svelte
632
+ <!-- src/routes/todos/+page.svelte -->
633
+ <script>
634
+ import { onMount } from 'svelte';
635
+
636
+ let todos = [];
637
+ let newTodoText = '';
638
+
639
+ onMount(async () => {
640
+ await loadTodos();
641
+ });
642
+
643
+ async function loadTodos() {
644
+ const response = await fetch('/api/todos');
645
+ todos = await response.json();
646
+ }
647
+
648
+ async function addTodo() {
649
+ if (!newTodoText.trim()) return;
650
+
651
+ await fetch('/api/todos', {
652
+ method: 'POST',
653
+ headers: { 'Content-Type': 'application/json' },
654
+ body: JSON.stringify({ text: newTodoText })
655
+ });
656
+
657
+ newTodoText = '';
658
+ await loadTodos();
659
+ }
660
+
661
+ async function deleteTodo(id) {
662
+ await fetch('/api/todos', {
663
+ method: 'DELETE',
664
+ headers: { 'Content-Type': 'application/json' },
665
+ body: JSON.stringify({ id })
666
+ });
667
+
668
+ await loadTodos();
669
+ }
670
+ </script>
671
+
672
+ <h1>My Todos</h1>
673
+
674
+ <form on:submit|preventDefault={addTodo}>
675
+ <input bind:value={newTodoText} placeholder="New todo..." />
676
+ <button type="submit">Add</button>
677
+ </form>
678
+
679
+ <ul>
680
+ {#each todos as todo}
681
+ <li>
682
+ {todo.text}
683
+ <button on:click={() => deleteTodo(todo.id)}>Delete</button>
684
+ </li>
685
+ {/each}
686
+ </ul>
687
+ ```
688
+
689
+ **What you built:**
690
+ - API endpoint at `/api/todos` with GET, POST, DELETE
691
+ - Todo list page at `/todos` that uses the API
692
+ - Full CRUD operations for todos
693
+
694
+ }}}
695
+
696
+ ### Exercise 3: Organize a Full App Structure {{{
697
+
698
+ **Goal:** Build a blog with proper file organization
699
+
700
+ **Structure:**
701
+ ```
702
+ src/
703
+ ├── lib/
704
+ │ ├── components/
705
+ │ │ ├── Navbar.svelte
706
+ │ │ ├── Footer.svelte
707
+ │ │ └── BlogCard.svelte
708
+ │ ├── utils/
709
+ │ │ ├── formatDate.js
710
+ │ │ └── slugify.js
711
+ │ └── db/
712
+ │ └── posts.js # Mock database
713
+ └── routes/
714
+ ├── +layout.svelte # App layout with Navbar/Footer
715
+ ├── +page.svelte # Homepage
716
+ ├── blog/
717
+ │ ├── +page.svelte # Blog list
718
+ │ ├── +page.server.js # Load posts
719
+ │ └── [slug]/
720
+ │ ├── +page.svelte # Single post
721
+ │ └── +page.server.js
722
+ └── api/
723
+ └── posts/
724
+ └── +server.js # Posts API
725
+ ```
726
+
727
+ **Mock database:**
728
+ ```javascript
729
+ // src/lib/db/posts.js
730
+ export const posts = [
731
+ {
732
+ slug: 'svelte-basics',
733
+ title: 'SvelteKit Basics',
734
+ excerpt: 'Learn the fundamentals...',
735
+ content: 'Full post content here...',
736
+ date: new Date('2025-01-01')
737
+ },
738
+ {
739
+ slug: 'routing-guide',
740
+ title: 'Routing in SvelteKit',
741
+ excerpt: 'Understanding file-based routing...',
742
+ content: 'Full routing guide...',
743
+ date: new Date('2025-01-15')
744
+ }
745
+ ];
746
+
747
+ export function getAllPosts() {
748
+ return posts;
749
+ }
750
+
751
+ export function getPostBySlug(slug) {
752
+ return posts.find(post => post.slug === slug);
753
+ }
754
+ ```
755
+
756
+ **Blog list page:**
757
+ ```javascript
758
+ // src/routes/blog/+page.server.js
759
+ import { getAllPosts } from '$lib/db/posts.js';
760
+
761
+ export function load() {
762
+ const posts = getAllPosts();
763
+ return { posts };
764
+ }
765
+ ```
766
+
767
+ ```svelte
768
+ <!-- src/routes/blog/+page.svelte -->
769
+ <script>
770
+ export let data;
771
+ import BlogCard from '$lib/components/BlogCard.svelte';
772
+ </script>
773
+
774
+ <h1>Blog</h1>
775
+
776
+ <div class="posts">
777
+ {#each data.posts as post}
778
+ <BlogCard {post} />
779
+ {/each}
780
+ </div>
781
+ ```
782
+
783
+ **Single post page:**
784
+ ```javascript
785
+ // src/routes/blog/[slug]/+page.server.js
786
+ import { getPostBySlug } from '$lib/db/posts.js';
787
+ import { error } from '@sveltejs/kit';
788
+
789
+ export function load({ params }) {
790
+ const post = getPostBySlug(params.slug);
791
+
792
+ if (!post) {
793
+ throw error(404, 'Post not found');
794
+ }
795
+
796
+ return { post };
797
+ }
798
+ ```
799
+
800
+ ```svelte
801
+ <!-- src/routes/blog/[slug]/+page.svelte -->
802
+ <script>
803
+ export let data;
804
+ import { formatDate } from '$lib/utils/formatDate.js';
805
+ </script>
806
+
807
+ <article>
808
+ <h1>{data.post.title}</h1>
809
+ <time>{formatDate(data.post.date)}</time>
810
+ <div class="content">
811
+ {@html data.post.content}
812
+ </div>
813
+ </article>
814
+ ```
815
+
816
+ **Key learning:** Proper separation of concerns - components in `lib/`, pages in `routes/`, data logic in `lib/db/`.
817
+
818
+ }}}
819
+
820
+ }}}
821
+
822
+ ## 🛡️ Best Practices {{{
823
+
824
+ ### Keep Routes Clean {{{
825
+
826
+ **❌ Bad - Logic in page component:**
827
+ ```svelte
828
+ <!-- src/routes/users/+page.svelte -->
829
+ <script>
830
+ import { onMount } from 'svelte';
831
+
832
+ let users = [];
833
+
834
+ onMount(async () => {
835
+ const response = await fetch('https://api.example.com/users');
836
+ users = await response.json();
837
+ });
838
+ </script>
839
+ ```
840
+
841
+ **✅ Good - Logic in server file:**
842
+ ```javascript
843
+ // src/routes/users/+page.server.js
844
+ export async function load({ fetch }) {
845
+ const response = await fetch('https://api.example.com/users');
846
+ const users = await response.json();
847
+ return { users };
848
+ }
849
+ ```
850
+
851
+ ```svelte
852
+ <!-- src/routes/users/+page.svelte -->
853
+ <script>
854
+ export let data;
855
+ </script>
856
+
857
+ <h1>Users</h1>
858
+ {#each data.users as user}
859
+ <p>{user.name}</p>
860
+ {/each}
861
+ ```
862
+
863
+ **Why:** Server-side loading is faster and more secure (API keys stay on server).
864
+
865
+ }}}
866
+
867
+ ### Extract Reusable Logic to $lib {{{
868
+
869
+ **❌ Bad - Duplicated validation:**
870
+ ```svelte
871
+ <!-- src/routes/contact/+page.svelte -->
872
+ <script>
873
+ function validateEmail(email) {
874
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
875
+ }
876
+ </script>
877
+ ```
878
+
879
+ ```svelte
880
+ <!-- src/routes/signup/+page.svelte -->
881
+ <script>
882
+ function validateEmail(email) {
883
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
884
+ }
885
+ </script>
886
+ ```
887
+
888
+ **✅ Good - Shared utility:**
889
+ ```javascript
890
+ // src/lib/utils/validation.js
891
+ export function validateEmail(email) {
892
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
893
+ }
894
+ ```
895
+
896
+ ```svelte
897
+ <!-- Both pages -->
898
+ <script>
899
+ import { validateEmail } from '$lib/utils/validation.js';
900
+ </script>
901
+ ```
902
+
903
+ }}}
904
+
905
+ ### Use Proper Import Paths {{{
906
+
907
+ **❌ Bad - Relative imports:**
908
+ ```javascript
909
+ import Footer from '../../lib/components/Footer.svelte';
910
+ import { formatDate } from '../../../lib/utils/formatDate.js';
911
+ ```
912
+
913
+ **✅ Good - $lib alias:**
914
+ ```javascript
915
+ import Footer from '$lib/components/Footer.svelte';
916
+ import { formatDate } from '$lib/utils/formatDate.js';
917
+ ```
918
+
919
+ **Why:** Easier to refactor, clearer intent, no need to count `../`.
920
+
921
+ }}}
922
+
923
+ ### Separate API Client from API Routes {{{
924
+
925
+ **Confusion to avoid:**
926
+ ```
927
+ src/routes/api/email/+server.js ← API endpoint you expose
928
+ src/lib/api/email.js ← Helper that calls external email service
929
+ ```
930
+
931
+ **Example:**
932
+ ```javascript
933
+ // src/lib/api/emailClient.js
934
+ // Helper function that calls SendGrid (external API)
935
+ export async function sendEmail(to, subject, body) {
936
+ const response = await fetch('https://api.sendgrid.com/v3/mail/send', {
937
+ method: 'POST',
938
+ headers: {
939
+ 'Authorization': `Bearer ${import.meta.env.VITE_SENDGRID_KEY}`,
940
+ 'Content-Type': 'application/json'
941
+ },
942
+ body: JSON.stringify({ to, subject, body })
943
+ });
944
+ return response.json();
945
+ }
946
+ ```
947
+
948
+ ```javascript
949
+ // src/routes/api/contact/+server.js
950
+ // Your API endpoint that uses the helper
951
+ import { json } from '@sveltejs/kit';
952
+ import { sendEmail } from '$lib/api/emailClient.js';
953
+
954
+ export async function POST({ request }) {
955
+ const { email, message } = await request.json();
956
+ await sendEmail(email, 'Contact Form', message);
957
+ return json({ success: true });
958
+ }
959
+ ```
960
+
961
+ **Remember:**
962
+ - `src/lib/api/` = Functions that CALL external APIs (tools)
963
+ - `src/routes/api/` = Endpoints your app EXPOSES (routes)
964
+
965
+ }}}
966
+
967
+ ### Don't Overengineer with Barrel Exports {{{
968
+
969
+ **❌ Overkill for small projects:**
970
+ ```javascript
971
+ // src/lib/index.js
972
+ export { default as Navbar } from './components/Navbar.svelte';
973
+ export { default as Footer } from './components/Footer.svelte';
974
+ export { default as Button } from './components/Button.svelte';
975
+ export { formatDate } from './utils/formatDate.js';
976
+ export { validateEmail } from './utils/validation.js';
977
+ // ... 50 more exports
978
+ ```
979
+
980
+ **✅ Keep it simple:**
981
+ ```javascript
982
+ // Just import directly
983
+ import Navbar from '$lib/components/Navbar.svelte';
984
+ import { formatDate } from '$lib/utils/formatDate.js';
985
+ ```
986
+
987
+ **When barrel exports make sense:**
988
+ - You have a component library with 20+ components
989
+ - You want consistent import patterns across a large team
990
+ - You're building a published package
991
+
992
+ **For most projects:** Direct imports are clearer and easier to maintain.
993
+
994
+ }}}
995
+
996
+ }}}
997
+
998
+ ## 📚 Quick Reference {{{
999
+
1000
+ ### File Naming Conventions {{{
1001
+
1002
+ ```
1003
+ +page.svelte → Page component (URL endpoint)
1004
+ +page.server.js → Server-side page logic
1005
+ +layout.svelte → Layout wrapping multiple pages
1006
+ +layout.server.js → Server-side layout logic
1007
+ +server.js → API endpoint (GET, POST, etc.)
1008
+ +error.svelte → Error page
1009
+ ```
1010
+
1011
+ }}}
1012
+
1013
+ ### Directory Mapping {{{
1014
+
1015
+ ```
1016
+ src/routes/ → Pages and API endpoints (public URLs)
1017
+ src/lib/ → Reusable code (internal)
1018
+ ├── components/ → Reusable UI components
1019
+ ├── utils/ → Helper functions
1020
+ ├── api/ → External API client functions
1021
+ ├── db/ → Database queries and models
1022
+ └── index.js → Optional barrel exports
1023
+
1024
+ static/ → Static assets (images, fonts)
1025
+ └── favicon.png → Available at /favicon.png
1026
+ ```
1027
+
1028
+ }}}
1029
+
1030
+ ### Import Patterns {{{
1031
+
1032
+ ```javascript
1033
+ // Components
1034
+ import Navbar from '$lib/components/Navbar.svelte';
1035
+ import Footer from '$lib/components/Footer.svelte';
1036
+
1037
+ // Utilities
1038
+ import { formatDate } from '$lib/utils/formatDate.js';
1039
+ import { validateEmail } from '$lib/utils/validation.js';
1040
+
1041
+ // API clients
1042
+ import { sendEmail } from '$lib/api/emailClient.js';
1043
+
1044
+ // Database
1045
+ import { getUsers } from '$lib/db/queries.js';
1046
+
1047
+ // From static folder
1048
+ <img src="/logo.png" alt="Logo">
1049
+ ```
1050
+
1051
+ }}}
1052
+
1053
+ ### Common Patterns {{{
1054
+
1055
+ **Load data server-side:**
1056
+ ```javascript
1057
+ // +page.server.js
1058
+ export async function load() {
1059
+ const data = await fetchData();
1060
+ return { data };
1061
+ }
1062
+ ```
1063
+
1064
+ **Create API endpoint:**
1065
+ ```javascript
1066
+ // +server.js
1067
+ import { json } from '@sveltejs/kit';
1068
+
1069
+ export async function POST({ request }) {
1070
+ const data = await request.json();
1071
+ return json({ success: true });
1072
+ }
1073
+ ```
1074
+
1075
+ **Dynamic routes:**
1076
+ ```
1077
+ src/routes/blog/[slug]/+page.svelte → /blog/anything
1078
+ src/routes/users/[id]/+page.svelte → /users/123
1079
+ src/routes/[...catchall]/+page.svelte → Matches everything
1080
+ ```
1081
+
1082
+ }}}
1083
+
1084
+ }}}
1085
+
1086
+ ## 🐛 Troubleshooting {{{
1087
+
1088
+ ### "$lib not found" Error {{{
1089
+
1090
+ **Symptom:**
1091
+ ```
1092
+ Error: Cannot find module '$lib/components/Navbar.svelte'
1093
+ ```
1094
+
1095
+ **Common causes:**
1096
+ 1. File doesn't exist at that path
1097
+ 2. Wrong file extension (`.svelte` vs `.js`)
1098
+ 3. Typo in path
1099
+
1100
+ **Fix:**
1101
+ ```bash
1102
+ # Verify file exists
1103
+ ls src/lib/components/Navbar.svelte
1104
+
1105
+ # Check import statement matches actual file name (case-sensitive)
1106
+ import Navbar from '$lib/components/Navbar.svelte'; # Correct
1107
+ import Navbar from '$lib/components/navbar.svelte'; # Wrong if file is Navbar.svelte
1108
+ ```
1109
+
1110
+ }}}
1111
+
1112
+ ### "Cannot read property of undefined" in Component {{{
1113
+
1114
+ **Symptom:**
1115
+ ```javascript
1116
+ <!-- BlogCard.svelte -->
1117
+ <h2>{post.title}</h2> <!-- Error: post is undefined -->
1118
+ ```
1119
+
1120
+ **Common cause:** Forgot to export the prop
1121
+
1122
+ **Fix:**
1123
+ ```svelte
1124
+ <script>
1125
+ export let post; // Must export props!
1126
+ </script>
1127
+
1128
+ <h2>{post.title}</h2>
1129
+ ```
1130
+
1131
+ }}}
1132
+
1133
+ ### API Endpoint Not Working {{{
1134
+
1135
+ **Symptom:**
1136
+ ```
1137
+ 404 Not Found when calling /api/contact
1138
+ ```
1139
+
1140
+ **Checklist:**
1141
+ ```bash
1142
+ # 1. Verify file exists at correct location
1143
+ ls src/routes/api/contact/+server.js
1144
+
1145
+ # 2. Check file exports HTTP methods
1146
+ # File must export: GET, POST, PUT, DELETE, etc.
1147
+
1148
+ # 3. Restart dev server
1149
+ # Sometimes needed after creating new +server.js files
1150
+ Ctrl+C
1151
+ npm run dev
1152
+ ```
1153
+
1154
+ **Common mistake:**
1155
+ ```javascript
1156
+ // ❌ Wrong - not exporting
1157
+ async function POST() { ... }
1158
+
1159
+ // ✅ Correct
1160
+ export async function POST() { ... }
1161
+ ```
1162
+
1163
+ }}}
1164
+
1165
+ ### Layout Not Applying to Page {{{
1166
+
1167
+ **Symptom:** Navbar/Footer not showing on a page
1168
+
1169
+ **Cause:** Layout must be in parent directory
1170
+
1171
+ **Structure:**
1172
+ ```
1173
+ src/routes/
1174
+ ├── +layout.svelte ← Applies to ALL pages
1175
+ ├── +page.svelte ← Homepage (has layout)
1176
+ └── blog/
1177
+ ├── +layout.svelte ← Applies only to /blog routes
1178
+ └── +page.svelte ← Blog page (has both layouts)
1179
+ ```
1180
+
1181
+ **Layout must have `<slot />`:**
1182
+ ```svelte
1183
+ <!-- +layout.svelte -->
1184
+ <Navbar />
1185
+ <slot /> <!-- Pages render here -->
1186
+ <Footer />
1187
+ ```
1188
+
1189
+ }}}
1190
+
1191
+ ### Component Not Re-rendering {{{
1192
+
1193
+ **Symptom:** Component doesn't update when data changes
1194
+
1195
+ **Common cause:** Not using reactive statements
1196
+
1197
+ **Fix with Svelte 5 runes:**
1198
+ ```svelte
1199
+ <script>
1200
+ // Old way (Svelte 4)
1201
+ let count = 0;
1202
+ $: doubled = count * 2; // Reactive statement
1203
+
1204
+ // New way (Svelte 5)
1205
+ let count = $state(0);
1206
+ let doubled = $derived(count * 2); // Derived state
1207
+ </script>
1208
+ ```
1209
+
1210
+ }}}
1211
+
1212
+ }}}
1213
+
1214
+ ## 💡 Pro Tips {{{
1215
+
1216
+ 1. **Use +page.server.js for data fetching:**
1217
+ - Keeps API keys secure
1218
+ - Faster initial load
1219
+ - Better SEO
1220
+
1221
+ 2. **Colocate related route files:**
1222
+ ```
1223
+ src/routes/blog/[slug]/
1224
+ ├── +page.svelte
1225
+ ├── +page.server.js
1226
+ └── BlogComments.svelte ← Component only used by this page
1227
+ ```
1228
+
1229
+ 3. **Use +layout.svelte for shared UI:**
1230
+ ```svelte
1231
+ <!-- src/routes/+layout.svelte -->
1232
+ <script>
1233
+ import Navbar from '$lib/components/Navbar.svelte';
1234
+ import Footer from '$lib/components/Footer.svelte';
1235
+ </script>
1236
+
1237
+ <Navbar />
1238
+ <main>
1239
+ <slot /> <!-- All pages render here -->
1240
+ </main>
1241
+ <Footer />
1242
+ ```
1243
+
1244
+ 4. **Organize by feature, not file type:**
1245
+ ```
1246
+ ✅ Good:
1247
+ src/lib/
1248
+ ├── auth/
1249
+ │ ├── Login.svelte
1250
+ │ ├── Signup.svelte
1251
+ │ └── auth.js
1252
+ └── blog/
1253
+ ├── BlogCard.svelte
1254
+ └── blogUtils.js
1255
+
1256
+ ❌ Less maintainable:
1257
+ src/lib/
1258
+ ├── components/
1259
+ │ ├── Login.svelte
1260
+ │ ├── Signup.svelte
1261
+ │ └── BlogCard.svelte
1262
+ └── utils/
1263
+ ├── auth.js
1264
+ └── blogUtils.js
1265
+ ```
1266
+
1267
+ 5. **Use TypeScript JSDoc for better autocomplete (without TypeScript):**
1268
+ ```javascript
1269
+ // src/lib/utils/formatDate.js
1270
+ /**
1271
+ * Format a date for display
1272
+ * @param {Date} date - The date to format
1273
+ * @returns {string} Formatted date string
1274
+ */
1275
+ export function formatDate(date) {
1276
+ return date.toLocaleDateString();
1277
+ }
1278
+ ```
1279
+
1280
+ 6. **Create a $lib/config.js for constants:**
1281
+ ```javascript
1282
+ // src/lib/config.js
1283
+ export const SITE_NAME = 'My Awesome App';
1284
+ export const MAX_UPLOAD_SIZE = 5 * 1024 * 1024; // 5MB
1285
+ export const API_URL = import.meta.env.VITE_API_URL;
1286
+ ```
1287
+
1288
+ 7. **Use the static/ folder for public assets:**
1289
+ ```
1290
+ static/
1291
+ ├── favicon.png → /favicon.png
1292
+ ├── logo.svg → /logo.svg
1293
+ └── images/
1294
+ └── hero.jpg → /images/hero.jpg
1295
+ ```
1296
+
1297
+ ```svelte
1298
+ <img src="/images/hero.jpg" alt="Hero">
1299
+ ```
1300
+
1301
+ 8. **Create error pages:**
1302
+ ```svelte
1303
+ <!-- src/routes/+error.svelte -->
1304
+ <script>
1305
+ import { page } from '$app/stores';
1306
+ </script>
1307
+
1308
+ <h1>{$page.status}: {$page.error.message}</h1>
1309
+ ```
1310
+
1311
+ }}}
1312
+
1313
+ ## 🚀 Next Steps {{{
1314
+
1315
+ **Master these progressively:**
1316
+
1317
+ 1. ✅ **Level 1:** Understand `src/routes` vs `src/lib`
1318
+ 2. ✅ **Level 2:** Create reusable components with `$lib`
1319
+ 3. ✅ **Level 3:** Build API endpoints with `+server.js`
1320
+ 4. 🎯 **Level 4:** Server-side data loading with `+page.server.js`
1321
+ 5. 🎯 **Level 5:** Advanced routing (layouts, groups, optional params)
1322
+ 6. 🎯 **Level 6:** Form actions and progressive enhancement
1323
+
1324
+ **Related concepts:**
1325
+ - **SvelteKit routing** - Nested layouts, dynamic routes, route groups
1326
+ - **Form actions** - Handle form submissions without JavaScript
1327
+ - **Stores** - Global state management with `$app/stores`
1328
+ - **Hooks** - Intercept requests with `hooks.server.js`
1329
+ - **Adapters** - Deploy to Vercel, Netlify, Node.js, etc.
1330
+
1331
+ **Resources:**
1332
+ - SvelteKit Docs: https://svelte.dev/docs/kit
1333
+ - Svelte Tutorial: https://svelte.dev/tutorial
1334
+ - SvelteKit LLM Docs: https://svelte.dev/docs/kit/llms-small.txt
1335
+
1336
+ }}}
1337
+
1338
+ ---
1339
+
1340
+ **Remember:** File structure in SvelteKit is intuitive once you understand the core principle: `src/routes/` is for URLs (pages and APIs), `src/lib/` is for your code toolbox. When in doubt, ask: "Do users visit this directly?" If yes → routes. If no → lib. 🚀