Closed jantimon closed 1 month ago
Here is what we would have to do for static css mixins:
SWC Plugin Modifications:
a. Identify static mixin definitions:
css
template literals.b. Process mixin content:
css
template literal.For example:
Before compilation:
// mixins.ts
export const borderMixin = css`
border: 1px solid black;
border-radius: 999px;
`;
After compilation:
// mixins.ts
/*YAK Mixin:
borderMixin:
border: 1px solid black;
border-radius: 999px;
*/
export const borderMixin = null;
d. Process mixin usage:
css
or styled
template literals with a special import syntax.Before compilation:
// Button.ts
import { borderMixin } from './mixins';
const Button = styled.button`
${borderMixin};
color: blue;
`;
After compilation:
// Button.ts
import { borderMixin } from './mixins';
const Button =
/*YAK Extracted CSS:
.Button {
--yak-css-import: url("./mixins:borderMixin");
color: blue;
}
*/
/*#__PURE__*/
styled.button(borderMixin, __styleYak.Button);
CSS Loader Enhancements:
a. Implement mixin resolution:
b. Replace mixin placeholders:
Example:
Extracted CSS from Button.ts:
.Button {
--yak-css-import: url("./mixins:borderMixin");
color: blue;
}
Final processed CSS:
.Button {
border: 1px solid black;
border-radius: 999px;
color: blue;
}
Runtime Changes:
a. We have to modify the runtime styled
function:
null
at runtime).
Summary
Introducing a new
const colorMixin = atom.css`color:red`;
API and redefining the behavior of the existingcss
template literal in next-yak could solve the cross file css mixin complexityBackground
Currently, next-yak treats all
css
template literals as static, reusable atomic classes. While this approach works well for simple cases and promotes CSS reuse, it falls short in more complex scenarios, particularly when used within nested selectors or media queriesFor example:
In this case, the current implementation cannot correctly apply the
borderMixin
within the:hover
selector, as it's treated as a static atomic class@Mad-Kat pointed out that this is a core problem where a lot of automated atomic utility css extraction get very complex
Proposed Solution
Instead of creating atomic css mixins automatically we make it an optional feature, so developers can explicitly create an atom and are aware of the limitations or just use the ordinary css api with a little bit more bundled css code
So we would:
atom.css
API for creating static, atomic CSS mixinscss
template literal to always inline its contents when used1. New
atom.css
APIThe
atom.css
API will behave similarly to the currentcss
implementation, creating a static, reusable atomic class:This will be extracted as a utility atom with a class (e.g.,
border-mixin
) and can be reused across the codebase, reducing bundled CSS size.2. Redefined
css
BehaviorThe
css
template literal will now inline its contents when used, allowing for proper nesting and selector combination:This change allows the
borderMixin
to be correctly applied within the:hover
selector.Cross File behaviour
This could also work for cross file mixins.
Here is an example how the compilation would look like:
Source Code
Compiled Output
The above code would be compiled to:
CSS Loader Processing
The CSS loader would then process the extracted CSS, replacing the special
--yak-css-import
property with the actual content of theborderMixin
. For example, ifborderMixin
was defined as:The final CSS output would be:
As we keep the mixin reference also in the typescript code (
styled.button(borderMixin, __styleYak.Button);
) this approach could also work for dynamic mixins across files