diff --git a/examples/_data.ts b/examples/_data.ts index ea66466ca..0613861f7 100644 --- a/examples/_data.ts +++ b/examples/_data.ts @@ -219,6 +219,11 @@ export const sidebar = [ href: "https://fresh.deno.dev/docs/getting-started/create-a-project/", type: "tutorial", }, + { + title: "Build a Svelte app", + href: "/examples/svelte_tutorial/", + type: "tutorial", + }, { title: "Build a Vue app", href: "/examples/vue_tutorial/", diff --git a/examples/tutorials/svelte.md b/examples/tutorials/svelte.md new file mode 100644 index 000000000..c16a0ccf4 --- /dev/null +++ b/examples/tutorials/svelte.md @@ -0,0 +1,323 @@ +--- +title: "Build a SvelteKit App" +description: "A tutorial on building SvelteKit applications with Deno. Learn how to set up a SvelteKit project, implement file-based routing, manage state with load functions, and create a full-stack TypeScript application." +url: /examples/svelte_tutorial/ +oldUrl: + - /runtime/manual/examples/how_to_with_npm/svelte/ + - /runtime/tutorials/how_to_with_npm/svelte/ +--- + +[SvelteKit](https://kit.svelte.dev/) is a web framework built on top of +[Svelte](https://svelte.dev/), a modern front-end compiler that builds highly +optimized vanilla JavaScript. SvelteKit provides features like file-based +routing, server-side rendering, and full-stack capabilities. + +In this tutorial we'll build a simple SvelteKit app with Deno. The app will +display a list of dinosaurs. When you click on one, it'll take you to a dinosaur +page with more details. You can see the +[finished app on GitHub](https://github.com/denoland/tutorial-with-svelte). + +You can see a live version of the app on +[Deno Deploy](https://tutorial-with-svelte.deno.deno.net/). + +:::info Deploy your own + +You can deploy your own version of this svelte app to Deno Deploy immediately. +Just click the button! + +[![Deploy on Deno](https://deno.com/button)](https://app.deno.com/new?clone=https://github.com/denoland/tutorial-with-svelte) + +::: + +## Create a SvelteKit app with Deno + +We'll use [SvelteKit](https://kit.svelte.dev/) to create a new SvelteKit app. In +your terminal, run the following command to create a new SvelteKit app: + +```shell +deno run -A npm:create-svelte +``` + +When prompted, give your app a name and select the "Skeleton project" template. +Choose "Yes, using TypeScript syntax" when asked about TypeScript. + +Once created, `cd` into your new project and run the following command to +install dependencies: + +```shell +deno install +``` + +Then, run the following command to serve your new SvelteKit app: + +```shell +deno task dev +``` + +Deno will run the `dev` task from the `package.json` file which will start the +Vite development server. Click the output link to localhost to see your app in +the browser. + +## Configure the formatter + +`deno fmt` supports Svelte files with the +[`--unstable-component`](https://docs.deno.com/runtime/reference/cli/fmt/#formatting-options-unstable-component) +flag. To use it, run this command: + +```sh +deno fmt --unstable-component +``` + +To configure `deno fmt` to always format your Svelte files, add this at the top +level of your `deno.json` file: + +```json +"unstable": ["fmt-component"] +``` + +## Add a backend API + +We'll build API routes using SvelteKit's built-in API capabilities. SvelteKit +allows you to create API endpoints by creating `+server.js` or `+server.ts` +files in your routes directory. + +In the `src/routes` directory, create an `api` folder. In that folder, create a +`data.json`, which will contain the hard coded dinosaur data. + +Copy and paste +[this json file](https://github.com/denoland/tutorial-with-svelte/blob/main/src/routes/api/data.json) +into the `src/routes/api/data.json` file. (If you were building a real app, you +would probably fetch this data from a database or an external API.) + +We're going to build out some API routes that return dinosaur information. +SvelteKit provides a simple way to create API endpoints using server files. + +Create `src/routes/api/dinosaurs/+server.ts` to handle the `/api/dinosaurs` +endpoint. This will return all dinosaurs: + +```js title="src/routes/api/dinosaurs/+server.ts" +import { json } from "@sveltejs/kit"; +import data from "../data.json" with { type: "json" }; + +export function GET() { + return json(data); +} +``` + +Then create `src/routes/api/dinosaurs/[id]/+server.ts` to handle individual +dinosaur requests at `/api/dinosaurs/:id`: + +```ts title="src/routes/api/dinosaurs/[id]/+server.ts" +import { json } from "@sveltejs/kit"; +import type { RequestHandler } from "./$types"; +import data from "../../data.json" with { type: "json" }; + +export const GET: RequestHandler = ({ params }) => { + const dinosaur = data.find((item) => { + return item.name.toLowerCase() === params.id.toLowerCase(); + }); + + if (dinosaur) { + return json(dinosaur); + } + + return json({ error: "Not found" }, { status: 404 }); +}; +``` + +SvelteKit automatically handles routing based on the file structure. The +`+server.ts` files define API endpoints, and the `[id]` folder creates a dynamic +route parameter. + +## Build the frontend + +### File-based routing and data loading + +SvelteKit uses file-based routing, where the structure of your `src/routes` +directory determines your app's routes. Unlike Vue Router, you don't need to +configure routes manually - SvelteKit automatically creates routes based on your +file structure. + +In SvelteKit, `+page.svelte` files define page components, and `+page.ts` files +define data loading functions that run before the page loads. This provides +built-in server-side rendering and data fetching capabilities. + +### The pages and components + +SvelteKit organizes the frontend into pages and components. Pages are defined by +`+page.svelte` files in the routes directory, while components can be reusable +pieces of code stored anywhere in your project. + +Each Svelte component file contains three optional sections: ` + +
+

🦕 Dinosaur app

+

Click on a dinosaur below to learn more.

+ {#each dinosaurs as dinosaur (dinosaur.name)} + + {dinosaur.name} + + {/each} +
+``` + +This code uses Svelte's [each block](https://svelte.dev/docs/logic-blocks#each) +to iterate over the `dinosaurs` array and render each dinosaur as a link. The +`{#each}` block is Svelte's way of rendering lists, and the `(dinosaur.name)` +provides a unique key for each item. + +#### The Dinosaur detail page + +The dinosaur detail page will display information about a specific dinosaur. +SvelteKit uses folder names in square brackets to create dynamic routes. The +`[dinosaur]` folder creates a route that captures the dinosaur name from the +URL. + +First, create `src/routes/[dinosaur]/+page.ts` to load individual dinosaur data: + +```ts title="src/routes/[dinosaur]/+page.ts" +import type { PageLoad } from "./$types"; +import { error } from "@sveltejs/kit"; + +export const load: PageLoad = async ({ fetch, params }) => { + const res = await fetch(`/api/dinosaurs/${params.dinosaur}`); + const dinosaur = await res.json() as { name: string; description: string }; + + if (res.status === 404) { + return error(404, "No dinosaur found"); + } + + return { dinosaur }; +}; +``` + +This load function uses the `params` object to access the `dinosaur` parameter +from the URL. If the API returns a 404, we use SvelteKit's `error` function to +throw a 404 error. + +Next, create `src/routes/[dinosaur]/+page.svelte` to display the dinosaur +details: + +```html title="src/routes/[dinosaur]/+page.svelte" + + +
+

{dinosaur.name}

+

{dinosaur.description}

+ 🠠 Back to all dinosaurs +
+``` + +This page displays the dinosaur's name and description, along with a link back +to the home page. The data comes from the load function and is automatically +available in the component. + +## Run the app + +Now that we've set up the frontend and backend API routes, we can run the app. +In your terminal, run the following command: + +```shell +deno task dev +``` + +This will start the SvelteKit development server with Vite. SvelteKit +automatically handles both the frontend pages and the API routes we created, so +you don't need to run separate servers. + +Visit `http://localhost:5173` in your browser to see the app. Click on a +dinosaur to see more details! + +You can see a live version of the app on +[Deno Deploy](https://tutorial-with-svelte.deno.deno.net/). + +## Build and deploy + +SvelteKit comes with built-in build capabilities. We configured it to use the +Deno adapter, which optimizes the build for deployment on Deno-compatible +platforms. Run the following command to build the app in production mode: + +```sh +deno task build +``` + +This will: + +1. Build the SvelteKit app using Vite +2. Generate optimized production assets +3. Create server-side code compatible with Deno + +The built app will be ready for deployment on platforms that support Deno, such +as Deno Deploy. + +You can deploy this app to your favorite cloud provider. We recommend using +[Deno Deploy](https://deno.com/deploy) for a simple and easy deployment +experience. You can deploy your app directly from GitHub, simply create a GitHub +repository and push your code there, then connect it to Deno Deploy. + +### Create a GitHub repository + +[Create a new GitHub repository](https://github.com/new), then initialize and +push your app to GitHub: + +```sh +git init -b main +git remote add origin https://github.com//.git +git add . +git commit -am 'my svelte app' +git push -u origin main +``` + +### Deploy to Deno Deploy + +Once your app is on GitHub, you can deploy it on the Deno DeployEA +dashboard. +Deploy +my app + +For a walkthrough of deploying your app, check out the +[Deno Deploy tutorial](/examples/deno_deploy_tutorial/). + +🦕 Now that you can run a SvelteKit app in Deno with the Deno adapter you're +ready to build real world applications!