Getting started with Alpine.js and TypeScript
Tags: typescript, webdev, vite, alpinejs
Published: 2022-01-20 12:21:58

Have you heard about Alpine.js? It feels like Vue, but lightweight. Yes, even more lightweight.

It is not pre-compiled, it uses HTML with custom (technically invalid) attributes and brings the webpage to live on load. Sounds basic? It might be, but it is also super simple.

```html
<div x-data="{ open: false }">
    <button @click="open = true">Expand</button>
 
    <span x-show="open">
      Content...
    </span>
</div>
```

I like to use it for small projects where I would have used JQuery if I was in 2010. It offers several simple ways of managing state, directly in html (see example above) or in a central store. It offers several directives, such as `x-for`, but also has an API to add your own directives. Checkout [the docs](https://alpinejs.dev/) for more information.

## A whole new project
I cannot (or better: I do not want to) work on projects without TypeScript anymore. Let's see how we can setup a new project powered by **Alpine.ts**. We use Vite to quickly setup a new project with Hot Module Replacement and bundling capabilities:
```bash
npm init vite@latest
? Project name: › alpine-ts
? Select a framework: › vanilla
? Select a variant: › vanilla-ts

cd alpine-ts
npm install -S alpinejs
npm install -D @types/alpinejs

npm run dev
```

Let's use Alpine in our `src/main.ts`:
```ts
import './style.css'

import Alpine from 'alpinejs'

// suggested in the Alpine docs:
// make Alpine on window available for better DX
window.Alpine = Alpine
 
Alpine.start()
```

Here we already encounter the first problem: `Alpine` is not defined on `window`. Let's fix that with a declaration file `src/global.d.ts`:
```ts
import { Alpine as AlpineType } from 'alpinejs'

declare global {
  var Alpine: AlpineType
}
```

Now we can code our app in TypeScript while using Alpine.js.

Let's use add some data and use it in the HTML:
```ts
// main.ts
import './style.css'
import Alpine from 'alpinejs'

window.Alpine = Alpine

Alpine.store('shop', {
  name: 'Alpine-Shop',
  products: ['Swiss Alp Chocolate', 'Car Alpine A110'],
})

Alpine.start()
```

```html
  <body>
    <div x-data>
      <h1>
        Welcome to the
        <span x-text="$store.shop.name">shop-name</span>
      </h1>
      <div>
        Here you can buy:
        <ul>
          <template x-for="product in $store.shop.products">
            <li x-text="product"></li>
          </template>
        </ul>
      </div>
    </div>
    <script type="module" src="/src/main.ts"></script>
  </body>
```

Note: There is no Intellisense (yet) for the HTML like we are used to in other frameworks, but getting started with TypeScript is a first step in the right direction.

## Bonus round: Tailwindcss
```bash
npm install -D tailwindcss @types/tailwindcss autoprefixer postcss
npx tailwindcss init
```
Additionally, add to the main CSS file:
```css
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
```
And create a `postcss.config.js` in your project root:
```js
module.exports = {
  plugins: [require('tailwindcss'), require('autoprefixer')],
}
```
Now you can add your tailwind styles to your website. Thanks to tailwind's JIT mode, it will only bundle whichever classes you are actually using.

## Wrapping up
That was pretty quick! If you have not started your next Micro-Project yet, I highly recommend giving Alpine.js a try.