👩‍💻 chrismanbrown.gitlab.io

Try the TAP stack if you hate HTML, CSS, and Javascript!

the most unmaintainable frontend code

2024-03-14

Contents🔗

  1. Look At This Todo App
  2. Introducing the TAP Stack
  3. What Does It Look Like?
  4. Seriously Though
  5. Conclusion

Look At This Todo App🔗

Look at this Todo app:

https://chrismanbrown.gitlab.io/todo/

Pretty nice, right?

Wrong. It is not nice. It is awful. And it is awful on purpose. I wanted to try to build something using as few best practices and web standards as possible. You know. “For fun.”

Introducing the TAP Stack🔗

This is the TAP Stack:

Tailwind

Instead of CSS, write hundreds of inline utility classes!

https://tailwindcss.com/
Alpine

Instead of Javascript, write minimal, inline directives! It is the tailwind of JS.

https://alpinejs.dev/
Pug

Instead of HTML, write whitespace-significant markup with no closing tags!

https://pugjs.org/api/getting-started.html

That’s right! With the TAP Stack, you can now write applications without any HTML, CSS, or Javascript at all!

Separations of concerns? Separate files? Forget about it! Don’t repeat yourself? How about repeat yourself! Modules? Components? Classes? Eh, maybe!1

What Does It Look Like?🔗

That’s the best part! It looks like an indecipherable ball of gnarled twine! It looks like cognative decline made manifest. It looks like that one time I saw some kid vomit spaghetti into the bathroom sink. Just a real mess.

It looks like this:

  body.bg-gray-100.font-sans.min-h-screen.flex.items-center.justify-center
    .bg-white.p-6.rounded-lg.shadow-lg.w-max(class="min-w-[600px]" x-data="todoApp()")
      h1.text-2xl.font-semibold.mb-4.text-center todo
      template(x-if="func === 'new'")
        .flex.justify-end.items-center.relative.border-solid.border-slate-300.border-2.rounded-md.w-full
          input(x-model="input" @keydown.enter="addTodo").py-2.px-3.w-full
          i.material-icons add
      template(x-if="func === 'search'")
        .flex.justify-end.items-center.relative.border-solid.border-slate-300.border-2.rounded-md.w-full
          input(x-model="input" @keydown.enter="view = model.filter(({ text }) => text.includes(input))").py-2.px-3.w-full
          i.material-icons search
      .flex.justify-end.gap-2
        a(@click="func = 'search'" :class="(func === 'search') && 'active' || 'inactive'").cursor-pointer Search
        a(@click="func = 'new'" :class="(func === 'new') && 'active' || 'inactive'").underline.cursor-pointer New
      .flex.mt-4.justify-between.gap-16
        span
          span(x-text="view.length")
          |  
          span(x-text="(filter === 'all') ? 'total' : (filter === 'complete') ? 'completed' : 'active'")
        span.flex.gap-1
          a(@click="filter = 'all'; updateView()" :class="filter === 'all' && 'active' || 'inactive'").cursor-pointer All
          a(@click="filter = 'active'; updateView()" :class="filter === 'active' && 'active' || 'inactive'").cursor-pointer Active
          a(@click="filter = 'complete'; updateView()" :class="filter === 'complete' && 'active' || 'inactive'").cursor-pointer Completed
        a(@click="model = model.filter(({ isComplete }) => !isComplete ); updateView()").underline.cursor-pointer Clear Completed
      ul.mt-4
        template(x-for="({ text, isComplete }, idx) in view")
          li.flex.justify-between.items-center.py-2(x-transition)
            input(type="checkbox" :checked="isComplete").scale-150.outline-1
            input.grow.text-left.cursor-pointer.px-2(x-model="text" @change="Object.assign(model.at(idx), {text}); saveChanges();")
            button(@click="model.splice(idx, 1); updateView(); saveChanges();") 
              i.material-icons close
src: https://gitlab.com/chrismanbrown/todo/-/blob/main/src/index.pug

Thanks to pug’s implicit divs, you barely need to write any actual tags! You can just start chaining tailwind utility classes. That’s synergy, baby.

Sprinkle a little x-for, x-if, and x-model in there, add a little :bind, and top it off with a couple @events and you’ve got a whole dang old application!

Inline styles! Inline scripts! It’s web dev from the 1990s! This site is under construction! Sign my guestbook!

Seriously Though🔗

Here are some pros and cons of working the TAP Stack.

Pros:

Cons:

Conclusion🔗

I mean. I wouldn’t write anything like this that needed to be maintained long term. But I might actually consider using the TAP Stack for quickly prototyping a minimal viable product. Guarantees that your first draft gets thrown away, so that you can do it right on your second attempt.

So what are you waiting for! Try the TAP Stack today!


  1. pug actually has great support for mixins. check out this pen I made forever ago: https://codepen.io/dozens/pen/dRJZKa↩︎