React is awesome but have you tried fresh?
Tags: webdev, javascript, react, tutorial
Published: 2022-06-30 05:11:00

## Why Fresh?

Let me start by asking you a simple question -- "Have you used react?" or have you used any JS framework or library for creating web apps like Vue, Svelte, Lit, NextJS or anything like that. You know what's the one thing that's common in all of them? They are built on top of Nodejs, have lots of boilerplate code and install tons of other libraries and use that evil *node_modules* folder.

What if I said, there's a framework which doesn't have any of these issues, has minimum boilerplate, no *node_modules* and is built on top of [deno](https://deno.dev/). I'm talking about [fresh](https://fresh.deno.dev/) here. It's a web framework built on top of deno, and recently got out of beta and is getting decent amount of attention from the JS ecosystem. The creators of fresh call it *"The next gen web framework"*, sounds cool right!

Some features that make fresh stand out --
- Just-in-time rendering on the edge.
- Island based client hydration for maximum interactivity.
- Zero runtime overhead: no JS is shipped to the client by default.
- No build step.
- No configuration necessary.
- TypeScript support out of the box.

In this blog, I'll walk you through the basics of the framework and we will be building the classic ToDo app as always, so let's start!

Prerequisite: you should have deno installed on your machine you can install it using [this](https://deno.land/#installation).

## Create the App

Let's start by scaffolding our project, to create a new fresh project and run it you need to run these command in your terminal. Make sure you use twind when you are prompted for it by fresh.
```bash
deno run -A -r https://fresh.deno.dev todo-app
cd todo-app
deno task start
```
This will start your app on localhost:8000, with a basic counter app.

![ss1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pbpxhud79ppqeb25804v.png)

Let's understand the basic concepts now, a fresh project has a total of 8 components, I'll be covering only the `routes/` and `islands/` folder in this blog, you can learn about all of them [here](https://fresh.deno.dev/docs/getting-started/create-a-project). 

- `routes/`: This folder contains all of the routes in your project. The names of each file in this folder correspond to the path where that page will be accessed. Code inside of this folder is never directly shipped to the client
- `islands/`: This folder contains all of the interactive islands in your project. The name of each file corresponds to the name of the island defined in that file. Code inside of this folder can be run from both client and server. 

In simpler terms, to add interactivity and reactivity to your project, you need to use `islands` and to create pages/routes you need to use `routes`.

Let's start by creating a new todo route in the app where we will build our todo app. Add a file named `todo.tsx` inside routes folder with the below content. We will be using twind to style the app, so having a basic knowledge of tailwind would be good.
```jsx
// routes/todo.tsx

/** @jsx h */
import { h } from "preact";
import { tw } from "@twind";

export default function Todo() {
    return (
        <div class={tw`w-screen h-screen flex flex-col justify-center items-center`}>
            <h1>hello world</h1>
        </div>
    )
}
```
This syntax is very similar to react as we are using jsx, tw is being used to style the elements using twind, you can learn more about it from twind's site if you want to. Now, if you did everything correctly, going to `localhost:8000/todo` will give you a page which looks like this - 

![ss2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qldgy5paw9jc1ifncflf.png)

Now, let's start by building our todo component inside the `islands/` folder. Create a new file named `TodoComponent.tsx` inside inslands folder and put the following code inside it.
```tsx
// islands/TodoComponent.tsx

/** @jsx h */
import { h } from "preact";
import { useState } from "preact/hooks";
import { IS_BROWSER } from "$fresh/runtime.ts";
import { tw } from "@twind";

export default function TodoComponent() {
  const [todoEl, setTodoEL] = useState("");
  const [todos, setTodos] = useState([]);
  const btn = tw
    `px-2 py-1 border-gray-200 border-2 hover:bg-gray-200 focus:outline-none`;

  return (
    <div class={tw`h-2/3 w-1/2 flex flex-col justify-center ites-center gap-3`}>
      <div class={tw`flex gap-3 h-[10%] w-full`}>
        <input
          type="text"
          class={tw
            `flex-grow-1 outline-none focus:outline-none border-gray-200 border-2 p-2`}
          placeholder="Enter new ToDo"
          onChange={(e: any) => {
            setTodoEL(e.target.value);
          }}
        >
        </input>
        <button
          class={btn}
          onClick={() => {
            if (todoEl) {
              setTodos([...todos, todoEl]);
              setTodoEL("");
            }
          }}
          disabled={!IS_BROWSER}
        >
          ➕
        </button>
      </div>
      <ul class={tw`flex flex-col gap-2 overflow-y-scroll min-h-[90%]`}>
        {todos.map((todo, index) => (
          <li class={tw`flex gap-2`} key={todo}>
            <p class={tw`flex-grow-1`}>{todo}</p>
            <button
              class={btn}
              onClick={() => {
                setTodos(todos.filter((todo, i) => i !== index));
              }}
              disabled={!IS_BROWSER}
            >
              ❌
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

It's a basic todo app code, which you can understand easily. 
We have 2 states one for the current todo element and other for our list of todos, we render a flex container with two containers inside it, the first one has an input box and a button to add todos. We are  using `onChange` on input element to update our `todoEl` state and a `onClick` in the add todo button which adds the `todoEl` to the array after making sure it's not `null`.
The second part has a `ul` element which maps our `todos` array to create `li` elements with `todo` as their text and a button to remove the todo element using the index of todo.

Now we need to add this island to our `todo` route. We can do that like this --
```tsx
routes/todo.tsx

/** @jsx h */
import { h } from "preact";
import { tw } from "@twind";
import TodoComponent from "../islands/TodoComponent.tsx";

export default function Todo() {
  return (
    <div
      class={tw`w-screen h-screen flex flex-col justify-center items-center`}
    >
      <TodoComponent />
    </div>
  );
}
```

Now, if you open `localhost:8000/todo` you'll see something like this if you followed the tutorial correctly-

![ss3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nsw206hl399iw5t1jaq0.png)

You can try playing with the app to see if it works, and it will work! You can also try to add a button for marking the todo as done if you want to as an exercise.

## Conclusion

This was a basic intro about fresh framework, you can learn more about it by reading the [docs](https://fresh.deno.dev/docs).

Thanks for reading, Happy Coding!

[Buy me a pizza 🍕](https://buymeacoffee.com/asheeshh)