maizzle / framework

Quickly build HTML emails with Tailwind CSS.
https://maizzle.com
MIT License
1.24k stars 49 forks source link

Duplicate style block when using multiple ´<push>´ in multiple components #1151

Closed evrpress closed 9 months ago

evrpress commented 9 months ago

I have a weird issue where I don't know if it's intended a bug or I do something wrong.

I'Ve added these files to the default installation (npx degit maizzle/maizzle my-project)

I try to add custom CSS rules which apply to a component. For maintainability I like to keep them in the head of the component file. I use a stack to push them to tailwindcss

To repeat this I've created a layout, a template and two components

For simplification I removed a lot of stuff:

layout

<!DOCTYPE html>
<html>
<head>
  <stack name="head" />
</head>
<body>  
    <content />
</body>
</html>

template

---
title: "Test"
---

<x-test-layout>
  <x-test-comp-a />
  <x-test-comp-b />
</x-test-layout>

component 1

<push name="head" once>
  <style tailwindcss>
    .comp-a {
      @apply sm:bg-black
    }
  </style>
</push>
<a class="comp-a">TEST COMP A</a>

component 2

<push name="head" once>
  <style tailwindcss>
    .comp-a {
      @apply sm:bg-white
    }
  </style>
</push>
<a class="comp-b">TEST COMP B</a>

Now here's the output after npm run build

<!doctype html>
<html>
  <head>
    <style>
      img {
        max-width: 100%;
        vertical-align: middle;
        line-height: 1;
      }
      @media (max-width: 600px) {
        .comp-a {
          background-color: #000 !important;
        }
      }
    </style>
    <style>
      img {
        max-width: 100%;
        vertical-align: middle;
        line-height: 1;
      }
      @media (max-width: 600px) {
        .comp-b {
          background-color: #fff !important;
        }
      }
    </style>
  </head>
  <body>
    <a class="comp-a">TEST COMP A</a>
    <a class="comp-b">TEST COMP B</a>
  </body>
</html>

As you can see the declarations are there twice (and also three times if I had a third component) What I would like to have is only a single <style> block without repeated declarations.

I've upload the file structure here.

cossssmin commented 9 months ago

Yes, it's expected behavior for each component to push its own content.

The once attribute is for pushing content only once per rendering cycle, for example if you had the stack in a loop then it would render only once in that loop. It's not meant to prevent other components from pushing to the same named stack.

<!-- the pushed `<style>` tag would only render once here -->
<each loop="item in [1,2,3]">
  <stack name="head" />
</each>

For this particular example I'd just use the classes on those components directly, i.e.:

<x-test-comp-a class="sm:bg-white" />

If you actually need those custom class names for some reason, the alternative is to either define them in a CSS file (example below) or to keep using what you have now and, after all transformers have run, use an event hook to combine the <style> tags into a single one. You may use afterTransformers for that, which gives you access to the compiled html which you can parse as you need.

By the way, keep in mind that using <style tailwindcss> in every component is inefficient, as Tailwind will need to run/compile for every such tag. Not sure exactly what your use-case is, but if you really need them present in your HTML I'd recommend just writing the classes out in something like a src/css/components.css instead and removing the <push> from components:

@layer components {
  .comp-a {
    @apply sm:bg-black;
  }
  .comp-b {
    @apply sm:bg-white;
  }
}
evrpress commented 9 months ago

Thanks for the explanation!

What I like to have is a solid base where I only alter (tailwind) styles so I get a new look in the end. The "starter" should be only a foundation and a thought about working on new templates from that.

I guess I need a different approach than.