I'm going to give Snowpack a try now ️📦
Tags: webdev, javascript, node, operations
Published: 2021-04-05 14:44:38

Last week, I didn't have much to write about, so I tried to learn about Brunch and documented my journey. I'll link this journey at the end of this post. User [YJDoc2](https://dev.to/yjdoc2) suggested to also have a look at Snowpack. I heard a bit about Snowpack before (mainly a tweet or two telling how awesome it was), but haven't used it myself. Time to change exactly that!

# Let's have a look

Ok, so the website says that Snowpack is the "faster frontend build tool":

![Screenshot of the official Snowpack website](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/id4p4xu2akvpgt7052ss.png)

Brunch managed to start between 70 and 100ms. I suspect Snowpack to be in that ball park as well, I mean, this thing has to execute _something_, right? Brunch already had its problems when Tailwind was added to the build and suddenly we were talking about 70 and 100hms (err, hecto-milli-seconds, basically seconds divided by ten... I should've just written 7-10s. Or deciseconds? ds? Whatever.). But that was mostly PostCSS. I actually suspect the same thing to happen here: A lot of tools (like TypeScript, JSX, CSS, etc.) supposedly work out of the box, but PostCSS needs a plugin. TypeScript is also supported at "build only" and extra type checking would need an extra plugin. Fair enough, I don't expect my build tool to handle everything from the start. But that TypeScript stuff does sound interesting.

(The attentive reader might've caught that I was referencing the docs. I'm not gonna do the same mistake again and just get going without knowing how!)

# Boilerplating

Same setup as last time: Tailwind + Alpine. Maybe I should change that to a more complex setup to really see where the tool starts to work against me and find possible pit falls, but those two things should do the trick for now.

I'm actually starting to wonder if there's an Alpine-like framework written in TypeScript. Alpine is written in plain ol' JS, so with the stack above I can't really test the TS capabilities of the build tool without having to write custom stuff. Just thinking aloud here... But maybe I'll just write a show/hide component in TS to use with Alpine and see if that plays out nice.

Anyways, I'm eager to try Snowpack now. `npm init` and lot's of hitting enter it is. I'm really curious about the supposed speed of this tool. So instead of installing a lot of things, I just install Snowpack itself, add the "start" and "build" commands to package.json and add an index.html containing a Hello World:

```html
<!DOCTYPE html>
<html>
<head></head>
<body>
  <h1>Hello, World!</h1>
</body>
</html>
```

And now I type `npm run start` and slooowly hit the enter button...

# Woah

Seriously, woah. That dev server is basically instant. Gimme a sec, that caught me off guard...

It _did_ log _something_ to the CLI, that much I can tell, but I wasn't even able to read a single word before my browser jumped _right_ in my face, eager to greet the planet like an over-motivated hamster on its first day at its dream job.

I want to know what snowpack wanted to tell me before the browser interrupted it, though, so let's have a look:

```
> snowpack dev

[snowpack] Hint: run "snowpack init" to create a project config file. Using defaults...
[snowpack] Welcome to Snowpack! Because this is your first time running
this project, Snowpack needs to prepare your dependencies. This is a one-time step
and the results will be cached for the lifetime of your project. Please wait...
[snowpack] No dependencies detected. Ready!
[snowpack] Server started in 8ms.
[snowpack] Local: http://localhost:8080
[snowpack] Network: http://192.168.1.50:8080
```

Well, hello Snowpack. The browser was faster.

Wait - 8ms? Are you kidding me? How does it _do_ that? It does feel right, though. (As if I could tell the difference between 8 and 80ms...)

Snowpack apparently used its built-in defaults here. I don't think adding a basic config file would slow it down much. I'm amazed that it just works as a plain server, too. Usually I use `serve` to quickly look at some built stuff, but this thing feels way faster. I think I'll get rid of serve on my system and just use Snowpack instead.

Back to business. Snowpack tells me to create a project config file with `snowpack init`, so I'm doing just that and do a re-run to see if that has any impact.

Nope, no impact. That thing stays super fast.

# Let's get back to boilerplating

The Snowpack documentation [has a guide on how to set up PostCSS](https://www.snowpack.dev/guides/postcss). I'll follow just that and alter the package.json, add a postcss.config.js and an index.css.

Snowpack config:

```javascript
// Snowpack Configuration File
// See all supported options: https://www.snowpack.dev/reference/configuration

/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
  mount: {},
  plugins: [
    "@snowpack/plugin-postcss"
  ],
  packageOptions: {},
  devOptions: {},
  buildOptions: {},
}
```

The package.json:

```json
{
  "name": "snowpack-tryout",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "snowpack dev",
    "build": "snowpack build"
  },
  "author": "",
  "license": "",
  "devDependencies": {
    "@snowpack/plugin-postcss": "^1.2.2",
    "autoprefixer": "^10.2.5",
    "snowpack": "^3.1.2"
  },
  "dependencies": {
    "tailwindcss": "^2.0.4"
  }
}
```

Postcss config:

```
// postcss.config.js
// Taken from: https://tailwindcss.com/docs/installation#using-tailwind-with-postcss
module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
  ],
}
```

And index.css:

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

Nothing out of the ordinary, right? Right. Let's try this again:

![Server the starting is fast, loading stuff is slow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upnia35hlimejfpd8qab.gif)

As you can see, the server still starts in around 10ms, which is awesome, but the entire Tailwind thing needs its 10s. Instead of waiting for the browser window to open, I wait for stuff to load instead. Fair enough, it has to execute the entire Tailwind stuff _somewhen_. But the hot reloading is blazing fast:

![Blazing fast hot reloading](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dynevrd8njkupgg333uv.gif)

Not too bad at all! Now I wanna get some TypeScript and Alpine in there.

# TypeScript + Alpine

I install Alpine by executing `npm i alpinejs` and create a simple index.ts:

```typescript
import 'alpinejs'
```

(Yup, that's all so far)

And I adjust index.html a little:

```html
<!-- ... -->
  <h1 
      class="text-4xl text-red-600" 
      x-data="{ text: 'Hello, World' }" 
      x-text="text"
  ></h1>

  <script type="module" src="index.js"></script>
<!-- ... -->
```

No server restart, no nothing, it just works™. Hot reloading is fast as always, so the entire thing apparently didn't slow down Snowpack at all. I'm still amazed.

Next up, a little Alpine component:

```typescript
interface TabNav {
  init: () => void
  show: (selector: string) => void
}

export default (): TabNav => ({
  init (): void {
    console.log(this.$el)
  },

  show (selector: string): void {
    this.$el
      .querySelectorAll(`.content:not(${selector})`)
      .forEach((el: HTMLElement) => {
        el.classList.add('hidden')
      })
    this.$el.querySelector(selector).classList.remove('hidden')
  }
})
```

This I can import in my index.ts:

```typescript
import 'alpinejs'
import tabNav from './tabNav'

// @ts-ignore
window.tabNav = tabNav
```

And then it can be used with some DOM:

```html
<!-- ... -->
  <div x-data="tabNav()" x-init="init">
    <ul class="flex">
      <li class="p-4 cursor-pointer" @click="show('#a')">Show A</li>
      <li class="p-4 cursor-pointer" @click="show('#b')">Show B</li>
      <li class="p-4 cursor-pointer" @click="show('#c')">Show C</li>
    </ul>

    <div id="a" class="content">
      Content A
    </div>
    <div id="b" class="content hidden">
      Content B
    </div>
    <div id="c" class="content hidden">
      Content C
    </div>
  </div>
<!-- ... -->
```

Instant. It really actually positively just works. Amazing. I'm convinced.

# Summary

I haven't tried the native Svelte integration yet, but if it works like the rest of it, this will probably blow my mind even more. The TypeScript support works with no additional config or even an extra package. If your IDE does the extra type checking Snowpack mentions, you don't even need that.

Zero-config, blasting off at what feels like near light-speed, TypeScript out of the box. I mean, what's not to love?

# About Brunch

Here's the article I mentioned above:

{% post thormeier/something-new-every-now-and-then-trying-brunch-109 %}

---

*I hope you enjoyed reading this article as much as I enjoyed writing it! If so, leave a* ❤️ *or a* 🦄*! I write tech articles in my free time and like to drink coffee every once in a while.*

*If you want to support my efforts,* [*buy me a coffee* ☕](http://buymeacoffee.com/pthormeier) *or* [*follow me on Twitter* 🐦](https://twitter.com/pthormeier)*!* *You can also support me directly via [Paypal](https://www.paypal.me/pthormeier)!*

[![Buy me a coffee button](https://dev-to-uploads.s3.amazonaws.com/i/x55hp6jopwyy161d8e2u.png)](http://buymeacoffee.com/pthormeier)

I want to thank **Martina** who supported me two weeks ago!