DaisyUI + Alpine.js + Codehooks.io - the simple web app trio
Tags: serverless, frontend, tutorial, codehooks
Published: 2024-01-13 15:23:32

Hello and welcome to this hands-on tutorial where we'll create a simple and interactive web app using DaisyUi, Alpine.js and Codehooks.io. 

This guide is tailored for front-end developers looking to explore the smooth integration of [DaisyUI's](https://daisyui.com) stylish components, [Alpine.js's](https://alpine.js) minimalist reactive framework, and the straightforward back-end capabilities of [Codehooks.io](https://codehooks.io). 

Whether you're an experienced developer or just starting out, this tutorial will walk you through the essential steps of web app development and deployment.

The finished result of this Web App is shown in the screen shot below.


![Buzzword generator screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lduk8ewumjgbm8hzqsrk.png)
_Check out a [live example here](https://bsgenerator-kge3.api.codehooks.io/dev)_

## What you will learn from this tutorial

### DaisyUI
DaisyUI is a component library for Tailwind CSS, offering a range of pre-styled components for rapid UI development. It's perfect for developers who want to create elegant interfaces quickly without sacrificing the customizability that Tailwind provides.

### Alpine.js
Alpine.js is a minimalist JavaScript framework for adding interactive elements to your HTML. It's ideal for developers who need a lightweight, straightforward tool to enhance their website's UI with dynamic features and reactive data binding.

### Codehooks.io
Codehooks.io is a serverless platform that simplifies backend development. It allows you to easily deploy serverless functions and APIs, focusing on your code while it handles the infrastructure, scaling, and maintenance.


OK, let's learn how to build the Web App.

## Project Setup
We need to create a project directory for the source code files and initialize npm.

```bash
mkdir myproject && cd myproject
mkdir webapp
npm init -y
npm install codehooks-js
```
_Later we'll edit the package.json and add the deployment command for codehooks.io._


Now, create the Web App source files. In the root directory create the two files `index.js`and `buzzwords.js` for the server side code. 

In the 'webapp' directory, create the two files for the client side code `index.html` and `script.js`. The `touch` command is a handy helper.
```bash
touch index.js buzzwords.js webapp/index.html webapp/main.js
```

## Codehooks.io Account Setup

Next you'll need to connect the local project directory to your Codehooks.io project space.

[Sign up for an account](https://account.codehooks.io/login?signup) at Codehooks.io, and create a new project, e.g. mywebapp. 

Install the Codehooks.io CLI.
```bash
npm install -g codehooks
``` 

Login to your account.
```bash
coho login
```

Connect your local web app project with your account/project.
```bash
coho init --empty
```

Use the up/down keys to pick your project and database environment (default `dev`) from the list. The example project list from my personal account is shown below, where i pick `mywebapp-okuc` as the active project to host my Web App.

```bash
coho init
? Select project 
  customers-chsb 
  myapi-4hvc 
❯ mywebapp-okuc 
  mongomirror-g4g9
```

Select your particular project and press enter, this will create a `config.json` file in your project directory with the unique project name.

Finally, your project directory should look like this after running the above commands successfully.

```
.
├── buzzwords.js
├── config-dev.json
├── index.js
├── package-lock.json
├── package.json
└── webapp
    ├── index.html
    └── main.js
```
This concludes the (boring) tasks we must do to setup our project, let's move on with the fun stuff of developing the frontend and the backend.

## Developing the Frontend (index.html)
The web app frontend is a really simple HTML page that uses DaisyUI for the looks and Alpine.js for the reactive dynamics. 

In the `<head>` we include CDN links for Tailwind CSS, DaisyUI, and Alpine.js.

```html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- Tailwind CSS and DaisyUI CDN -->
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@^2.2.19/dist/tailwind.min.css" rel="stylesheet">
  <link href="https://cdn.jsdelivr.net/npm/daisyui@^1.3.6/dist/full.css" rel="stylesheet">
  <!-- Alpine.js CDN -->
  <script src="//unpkg.com/alpinejs" defer></script>
  <!-- use /dev/index.html environment for development and test, for production remove and serve at root domain e.g. example.com/index.html -->
  <base href="/dev/" />
</head>

<body>
  <div class="container mx-auto p-8">
    <h1 class="text-4xl font-bold text-center">Buzzword generator!</h1>
    <!-- bind x-data to messageStore -->
    <div x-data="messageStore" class="flex justify-center">
      <div class="card w-96 bg-base-100 shadow-xl">
        <div class="card-body">
          <h2 class="card-title">Buzz count <div class="badge badge-lg" x-text="bsCount"></div>
          </h2>
          <div class="toast toast-top toast-center">
            <div class="alert alert-info">
              <span x-text="message"></span>
            </div>            
          </div>
          <div class="card-actions justify-end">
            <!-- call method to fetch new data and update page -->
            <button @click="getMessage()" class="btn btn-primary">Get Buzzwords</button>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script src="main.js"></script>
</body>

</html>
```

## Backend API Integration (main.js)

We'll use the Alpine.js powerful [x-data](https://alpinejs.dev/directives/data) directive to handle dynamic content and reactive binding. The client calls the Codehooks.io server REST API `/api/message`, and the REST API returns a dynamic JSON object as a response to the client request.

The client side code `webapp/main.js` is shown below.
```js

document.addEventListener('alpine:init', () => {
  Alpine.data('messageStore', () => ({
    message: 'Click the button to fetch a message ...',
    bsCount: 0,
    // init is called when document is ready
    init() {      
      this.getMessage()
    },
    // fetch json from the server public api
    async getMessage() {
      try {
        const response = await fetch('api/message', {
          headers: {
            'Content-Type': 'application/json'
          }
        });
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        // destruct json from server
        const { message, bsCount } = await response.json();
        // update local Alpine.data model
        this.message = message;
        this.bsCount = bsCount;
      } catch (error) {
        console.error('Error:', error);
      }
    }
  }));
});

```
The next section shows how to create the server side for the REST API.

## Backend Server Setup (index.js)
The server code is a simple Codehooks.io backend that exposes one single public route `GET /api/message` and serve the webapp files from the webapp sub directory. The random "buzzwords" is generated by combining 3 arrays of random words imported from the `buzzword.js` file. 

Note that we also use the build in [Key Value datastore](https://codehooks.io/docs/key-value-database-api) to increment the total count of generated buzzwords.

The complete server code is shown below.

```javascript

/*
* Codehooks.io backend example app
*/
import {app, datastore} from 'codehooks-js'
import { buzzwords1, buzzwords2, buzzwords3 } from './buzzwords';


function generateBS() {
  const word1 = buzzwords1[Math.floor(Math.random() * buzzwords1.length)];
  const word2 = buzzwords2[Math.floor(Math.random() * buzzwords2.length)];
  const word3 = buzzwords3[Math.floor(Math.random() * buzzwords3.length)];

  return `${word1} ${word2} ${word3}`;
}

// allow api access without api token
app.auth('/api/message*', (req, res, next) => {
  if (req.method === 'GET') {
    next();
  } else {
    next('Only GET is allow public access');
  }
})

// api route for generating a buzzword message and a count
app.get('/api/message', async (req, res) => {
  const db = await datastore.open();
  const bsCount = await db.incr('bsCount', 1)
  console.log('Count', bsCount)
  res.json({bsCount, message: generateBS()})
})

// serve the webapp directory on the / route
app.static({route: "/", directory: "/webapp"})

// bind to serverless runtime
export default app.init();
```

In this simple example we combine the arrays of words from the `buzzwords.js` file shown below.

```js
export const buzzwords1 = [
    "Blockchain", "Quantum", "Synergistic", "Big Data", ...
];

export const buzzwords2 = [
    "driven", "enhanced", "optimized", "integrated", ...
];

export const buzzwords3 = [
    "solutions", "platforms", "paradigms", "algorithms", ...
];
```

## Deployment Using Codehooks CLI
We'll use the [Codehooks CLI](https://codehooks.io/docs/cli) for deployment. And to automate things we create script deploy commands in our `package.json` as shown below.

```json
{
  "name": "mywebapp",
  "version": "1.0.0",
  "description": "My awesome webapp",
  "main": "index.js",
  "scripts": {
    "predeploy": "codehooks upload ./webapp",
    "deploy": "codehooks deploy"
  },
  "dependencies": {
    "codehooks-js": "^1.1.10"
  }
}
```
_The 'deploy' command will upload all files in the webapp directory to the server and then deploy your backend server (index.js) to the serverless cloud._

To deploy the complete web app and the backend API run:
```bash
npm run deploy
```

## Testing and Domain Configuration
You can access your deployed app and verify its functionality in several ways.

* Run the `coho info` command to find your project URL, in my example project the URL is: `https://bsgenerator-kge3.api.codehooks.io/dev`, copy this into your browser and test the Web App
* You can also add a custom domain (e.g. `example.com`) that you control by adding an A-Record or C-Record and point it to Codehooks. This generates a free SSL certificate with auto renew. (Check how to setup this in your admin settings in the Codehooks Studio App)
* Test the server REST API with Postman or cUrl by calling the canonical URL for the API, e.g. `curl --location 'https://bsgenerator-kge3.api.codehooks.io/dev/api/message'`
* Coming soon! _Use the built in random domain for development, in my example app the public domain is: `mighty-frog-f100.codehooks.io`_.


## Concluding Thoughts
The tutorial aims to demonstrate the simplicity and efficiency of combining DaisyUI, Alpine.js, and Codehooks.io in web development, guiding through each stage from setup to deployment. The final product is a dynamic web application capable of generating random messages, showcasing the power of these tools in creating responsive and interactive web applications.

## Links
* [Complete code at GitHub](https://github.com/RestDB/codehooks-io-examples/tree/main/bsgenerator)
* [DaisyUi](https://daisyui.com/)
* [Alpine.js](https://alpine.js/)
* [Tailwin CSS](https://tailwindcss.com/)
* [Codehooks.io](https://codehooks.io/)