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:
- It either loads a
module.cssfile directly or - It scans your template files (
.phtmland.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:
- It checks whether a file named
module.cssexists in the module’sview/frontend/tailwind/directory.- If
module.cssexists: It adds an@importstatement for that CSS file. It does not scan the templates. It assumes you have manually defined all your module’s styles inside the module.css file. - If
module.cssdoes NOT exist: It adds@sourcedirectives for*.phtmland*.xml. This tells the Tailwind engine to scan your template files for utility classes.
- If
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:
- The
.democlass frommodule.cssis compiled. - However, the
px-48class used insidedemo.phtmlmight be missing from the final bundle (unless used elsewhere in the project), because Tailwind was never told to look inside that PHTML file.
.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:
- Run
hyva-sources. - The script sees
module.cssis missing. - The generated
hyva-source.csswill 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.