👩‍💻 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.”

All Active Completed
item
x
item
x
x
completed item
x
x items left
Clear Completed
Search New
Look, I even mocked up a wireframe for this monstrosity

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!