Replacing Twind with Tailwind in Fresh
Tags: webdev, tutorial, deno, javascript
Published: 2023-05-15 11:19:15

## Update FRESH 1.6

Since the latest release of fresh (1.6), you can actually use the official Tailwind CSS package in NPM and so unless you want a solution that does not include `node_modules/` folder, you can consider this article obsolete.  


## Intro

Greetings, fellow human beings 👋
Today, I would like to share my experience with `fresh` and why you should replace the styling from `twind` -> `taiwlind-cli`.

## What is fresh?

Fresh is "The next-gen web framework", which could be translated to "Hey! I am cool deno-based SSR framework". Fresh, instead of using `react` uses `preact`, which is tiny(3kb) alternative to regular-sized react. Preact, just like react, uses `.jsx / .tsx` files and syntax and is compatible with react-based libraries.

Cool! But what is twind, and why should we care? Well, `twind` is a tiny implementation of `tailwind css` in `javascript`. Awesome, so what is the problem? Why not stick with it? The answer to this is simple. Currently, they don't have extension for vs-codium and their extension for regular vs-code is not working. There are hacky fixes, but why should I care if I can use regular old tailwind? (I know it's against deno's whole purpose, but I guess one exception is fine?)

## Before we continue...

Before we continue any further, it's useful to mention, that I have prepared a template repository for all of you, who are just starting out with fresh and are not looking to replace the `twind`, but rather make a brand-new project.

Without any further a do, here is the [link](https://github.com/Asqit/fresh-project).

## Replacing twind in existing code-base

So you already have a fresh project and looking for a way to replace the `twind`? Well I have a good news, look no further as I will show the way.

### Step 1. Removing it 

First, we need to remove it from your `fresh.json` file as our dependency. 


```json
{
  "lock": false,
  "tasks": {
    "check": "deno fmt --check && deno lint && deno check **/*.ts && deno check **/*.tsx",
    "start": "deno run -A --watch=static/,routes/ dev.ts",
    "build": "deno run -A dev.ts build",
    "preview": "deno run -A main.ts",
    "update": "deno run -A -r https://fresh.deno.dev/update ."
  },
  "lint": {
    "rules": {
      "tags": [
        "fresh",
        "recommended"
      ]
    },
    "exclude": [
      "_fresh"
    ]
  },
  "fmt": {
    "exclude": [
      "_fresh"
    ]
  },
  "imports": {
    "$fresh/": "https://deno.land/x/fresh@1.4.2/",
    "preact": "https://esm.sh/preact@10.15.1",
    "preact/": "https://esm.sh/preact@10.15.1/",
    "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.1",
    "@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
    "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.3",

    -------- REMOVE THESE LINES ---------------
    "twind": "https://esm.sh/twind@0.16.19",
    "twind/": "https://esm.sh/twind@0.16.19/",
    -------------------------------------------
    "$std/": "https://deno.land/std@0.193.0/"
  },
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}
```

Great! Now we got rid of it as dependency. As a next step, you should also remove the `twind.config.js` file, as we won't be using it anymore. 

By removing the config file, we need to update our `main.ts` file to following: 

```typescript
/// <reference no-default-lib="true" />
/// <reference lib="dom" />
/// <reference lib="dom.iterable" />
/// <reference lib="dom.asynciterable" />
/// <reference lib="deno.ns" />

import "$std/dotenv/load.ts";

import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";

// Remove this import statemet
import config from "./fresh.config.ts";

// Replace following line with just: await start(manifest);
await start(manifest, config);
```

Awesome! Next, we need to update the fresh config file of the twind removal. 

```typescript
// original
import { defineConfig } from "$fresh/server.ts";
import twindPlugin from "$fresh/plugins/twind.ts"
import twindConfig from "./twind.config.ts";
export default defineConfig({
  plugins: [twindPlugin(twindConfig)]
});

// ---------------------------------------

// updated
import { defineConfig } from "$fresh/server.ts";

export default defineConfig({
  plugins: [],
});
```

Voilà! Now are got ourselves fresh project without any styling. 


### Step 2. Installing tailwind 

So now we have a fresh project running, but it looks like garbage, or at least as HTML without any CSS. To fix this, we need to install tailwind CSS. 

#### Fetching the binary file
To continue, we need to fetch ourselves a copy of tailwind binary. [Here](https://github.com/tailwindlabs/tailwindcss/releases) is a link to the release page. Download the copy for your platform and rename it to just `tailwindcss`. We will use this binary to transpile our classes into a regular old CSS file. 

Now, we need to update our `start` task in `deno.json > tasks`.

```json
{
  "lock": false,
  "tasks": {
    "start": "tailwindcss -i ./static/styles/input.css -o ./static/styles/tailwind.css --minify --watch & deno run -A --watch=static/,routes/ dev.ts",
   },
...rest of the deno.json code
```

Alright! We are half way done. Now we have to create `tailwind.config.cjs` file with following code: 

```typescript
/** @type {import('https://esm.sh/tailwindcss@3.1.8').Config} */
module.exports = {
  content: [
    "./routes/**/*.{tsx,ts}",
    "./islands/**/*.{tsx,ts}",
    "./components/**/*.{tsx,ts}",
  ],
  theme: {
    extends: {},
  },
  plugins: [],
};
```
Once that is done, we need to create a new file in `/static/styles/input.css` and give it the following code: 

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
}
```

### Linking the styling

Update the `_app.tsx` located at `/routes` of the following component: 

```tsx
import { Head } from "$fresh/runtime.ts";
import { AppProps } from "$fresh/src/server/types.ts";

export default function App(props: AppProps) {
  const { Component } = props;

  return (
    <html>
      <Head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="initial-scale=1.0, width=device-width" />
        <title>Fresh project | starter code</title>
        <link rel="icon" type="image/png" href="../favicon.ico"></link>
        <link rel="stylesheet" href="../styles/tailwind.css" />
      </Head>
      <body className="antialiased">
        <Component />
      </body>
    </html>
  );
}
```

Ta Da! Your application should now be styled by the original Tailwind CSS. If you have any questions, don't be afraid to ask. If you want to see a deployment ready app, check out the template repository in the second paragraph.