Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple output files / omitting tokens from output in specific plugins #250

Open
torstendaeges opened this issue Apr 14, 2024 · 3 comments

Comments

@torstendaeges
Copy link

This may be related to #212...

We're currently using Cobalt with plugin-css and plugin-sass in CSS variable mode, resulting in one css and one scss file with everything we need.

However, our developers brought up that they currently manually split the one css file into multiple files/folders - so as to better organize the token types and levels and make it more maintainable/readable. As for the SCSS, it so happens that they only really need the token functions and typography mixins, so to minimize the code, they manually get rid of the rest of the SCSS output.

My goal is to automate the design token stack as much as possible, so I'm not the biggest fan of them manually intervening. However I do unterstand where they are coming from and have been wondering if Cobalt could provide such functionality in a future version.

One way to solve this would be to provide information in each tokens $extensions on where and if to output the resulting CSS, SCSS or JS. But I'm not sure that would be the smartest approach, since you'd have to specify such information for each plugin... And it would also be problematic if alias targets are specified to be ignored while being pointed to elsewhere.

So this is more an invitation for discussion than a suggestion I guess. :) Any thoughts? Thank you!

@drwpow
Copy link
Collaborator

drwpow commented Apr 16, 2024

Yeah there are a few layers going on here! Appreciate you explaining the whole situation. Usually, yes, it is an antipattern to manually-edit generated files. However, if the tokens/output don’t change often it can be workable enough. I’ll start by explaining some assumptions Cobalt makes (that may or may not hold true), and then suggest some possible solutions.

Cobalt assumes you have design token documentation and that it lists the global IDs for those tokens. That’s why the Sass API and JS API look the same with token("color.blue.500")—so one central documentation source can work for multiple languages. Of course, Cobalt doesn’t provide tools to help you make this documentation (which is something I’m working on now). CSS is odd because it has to use different IDs: var(--color-blue-500) (can’t contain .s). So even with token docs, it won’t know what those names will be until it’s generated. So wanting those to be more readable is a little bit of a pain point that I understand.

But rather than just treating the generated .css files as “documentation” (if that’s what’s happening here), there are other ways to improve this DX such as:

  • VS Code’s CSS Variables Plugin that can scan your project for CSS vars and autocomplete them in the right places (was talking with an engineer at Netlify not too long ago that uses this for their CSS vars)
  • Adding @property definitions to CSS (planned in 2.0)
  • Adding CSS variable names to the token docs (worth noting whatever “formula” you use to name the CSS vars, you could apply to both Cobalt and your docs; also Cobalt exposes its default namer so you could conversely just use Cobalt’s for your docs and keep the two in sync). Example (a design system I worked on last year)

So all that said, I am hesitant to split the output into multiple files, because as you pointed out the difficulty of using $extensions to provide output-specific settings can be fraught with complexity. And this is enough of a unique usecase I haven’t heard of other teams running into the issue of needing to read generated files better. But if I’m hitting close to the underlying issue of just needing better documentation, then that is something I’d like to provide easier-to-scaffold tools for.

And also I agree solving #212 is worthwhile—it seems useful to otherwise “ignore” certain tokens from output based on the plugin (granted that many tools can remove unused stuff in the end). Which could also help.

@maxkuhlmay
Copy link

Hey Drew,
we have different color modes (e.g. light and dark). Both modes have their tokens within a media query inside one css file.

It would be really nice, if we can describe, in which file those tokens are being saved.

e.g.

modeSelectors: [
    { 
        mode: 'light', 
        selectors: ['[data-theme="light"]'],
        filename: "light.css"
    },
]
{
    "cs": {
        "button": {
            "bg": {
                "color": {
                    "primary": {
                        "default": {
                            "$type": "color",
                            "$value": "{d.color.fg.brand}",
                            "$filename": "component.css",
                            "$extensions": {
                                "mode": {
                                    "hover": "{d.color.fg.brand}"
                                }
                            }
                        },

I've added filename: "light.css" and "$filename": "component.css",

If something like this would be possible, it would be awesome :)

@drwpow
Copy link
Collaborator

drwpow commented May 19, 2024

It would be really nice, if we can describe, in which file those tokens are being saved.

Short answer: This is something Cobalt 2.0 (“Terrazzo”) will make easier to do, even if that means writing partial plugins to accomplish this. There may not be an explicit option/docs for this, but it’ll be way easier to pull off than the “hack” of loading the CSS plugin multiple times.

Longer answer

This is something I don’t think we’ll support an official option / docs for because it can impose a few difficulties. While I do agree with your proposal of this living in the config file, not tokens.json (it’s a tool-level decision), adding a specific option to in the CSS plugin is something I’d like to avoid because:

It could break some modes. The way the CSS cascade works, order of appearance is the “tiebreaker” for specificity. In the scenario you’re “bundling” or loading multiple files, it becomes more difficult to guarantee they’re loaded in a specific order (not unless you’re manually writing the HTML yourself). Even if your tokens don’t have this issue, there could be a scenario where some tokens expect one mode to load before the other, and now there’s a brittle requirement their tooling has to load files in a specific order (which may be beyond their ability to control). So this could introduce some bugs whereas a single file will always load CSS predictably, for all possible setups, 100% of the time.

It encourages a bit of an anti-pattern in editing generated code. Cobalt is categorized as a codegen tool that generates code that shouldn’t be modified directly (it’s why there are “do not edit” notices at the top of each file). Imposing organizational restrictions on generated code often creates unnecessary work for unknown benefit—why require the tool to organize code in a certain way if the final result is the same? Of course, as the arbiter of your stack it’s your decision to do this! But also just as OSS this can expand the support surface area / introduce bugs into a project that make it more difficult for maintainers to manage when this doesn’t solve a common problem many users have and is more of an opinionated thing.

Hope that makes sense! Again, not a “Cobalt won’t support this” answer; just more of a nuanced “there are ways to accomplish this in Cobalt but not using encouraged happy paths” (and there probably won’t be docs on this)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants