Skip to content
Piyush Dankhra
Go back

Understanding the styles priority and How Hyvä handles module CSS

Last updated:

When building styles in the Hyvä theme, it’s important to understand how Tailwind finds your CSS classes.

When the build script processes a Magento module, it takes one of two approaches:

  1. It either loads a module.css file directly or
  2. It scans your template files (.phtml and .xml) for Tailwind classes

— but it usually does not do both at the same time.

Let’s look at the logic inside the command responsible for generating the source map for Tailwind.

Table of contents

Open Table of contents

The Logic

The file responsible for gathering all valid Tailwind sources from your Magento modules is located at node_modules/@hyva-themes/hyva-modules/bin/generate-sources.js. Here is the critical logic:

const { importStatements, sourceStatements, moduleStatements } =
    hyvaModules?.reduce(
        (acc, theme) => {
            if (!theme.src) return acc;

            if (theme.src.startsWith("./") || theme.src.startsWith("../")) {
                consoleWarn(
                    [
                        `Warning: Do not use relative paths (e.g., "./" or "../") in the "src" configuration for ${theme.src}`,
                        '"hyva-sources" automatically resolves all paths from the Magento 2 project root.',
                    ].join("\n")
                );
            }

            const themePath = getRelativePath(theme.src);
            const themeCSSPath = getRelativePath(theme.src, "generated");

            const tailwindCSSPath = path.join(
                themePath,
                "view/frontend/tailwind/module.css"
            );
            const tailwindSourceCSSPath = path.join(
                themePath,
                "view/frontend/tailwind/tailwind-source.css"
            );

            const importPath = (cssPath) =>
                `@import "${themeCSSPath}/view/frontend/tailwind/${cssPath}";\n`;

            if (existsSync(tailwindCSSPath)) { 
                acc.moduleStatements += importPath("module.css");
            } else {
                acc.sourceStatements += `@source "${themeCSSPath}/**/*.phtml";\n`;
                acc.sourceStatements += `@source "${themeCSSPath}/**/*.xml";\n`;
                if (existsSync(tailwindSourceCSSPath)) {
                    acc.importStatements += importPath("tailwind-source.css");
                }
            }
            return acc;
        },
        { importStatements: "", sourceStatements: "", moduleStatements: "" }
    ) ?? { importStatements: "", sourceStatements: "", moduleStatements: "" };Hyvä-child-theme::web/tailwind/node_modules/@hyva-themes/hyva-modules/bin/generate-sources.js

What this code does:

Real-world example

Let’s visualize this with a module named MyCompany_HyvaStyle.

Imagine we have a template using a standard Tailwind utility class:

<div class="px-48"></div>MyCompany_HyvaStyle::view/frontend/templates/demo.phtml

Scenario A: The module.css exists

Suppose we also have a CSS file that applies styles using @apply:

.demo {
    @apply px-48;
}MyCompany_HyvaStyle::view/frontend/tailwind/module.css

If we run hyva-sources, the script imports module.css but will omit the *.phtml and *.xml sources.

@import "../../../../../../../code/MyCompany/HyvaStyle/view/frontend/tailwind/module.css";Hyvä-child-theme::web/tailwind/generated/hyva-source.css

When you run npm run build:

.demo {
  padding-inline: calc(var(--spacing) * 48);
}Hyvä-child-theme::web/css/styles.css

Scenario B: The module.css does not exist

If we delete MyCompany_HyvaStyle::view/frontend/tailwind/module.css,

Then:

  1. Run hyva-sources.
  2. The script sees module.css is missing.
  3. The generated hyva-source.css will now contain:
@source "../../../../../../../code/MyCompany/HyvaStyle/**/*.phtml";
@source "../../../../../../../code/MyCompany/HyvaStyle/**/*.xml";Hyvä-child-theme::web/tailwind/generated/hyva-source.css

Now, when Tailwind runs, it scans demo.phtml. It detects <div class="px-48"> and ensures the px-48 utility class is generated in the final styles.css output.

  .px-48 {
    padding-inline: calc(var(--spacing) * 48);
  }Hyvä-child-theme::web/css/styles.css

Conclusion

If you rely on auto-scanning of utility classes in your PHTML or XML files, ensure you do not have a legacy module.css file preventing Tailwind from scanning those templates. If you want to use custom CSS and your templates do not use tailwind utility classes directly, the modules.css file is the correct approach.

In our next post, we will look at safelisting dynamic classes in the Tailwind configuration.


Share this post on:

Next Post
Understanding the Hyvä Tailwind build process for custom modules