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

[@sheet] [AtSheet] solving the duplicate sheet issue. #933

Open
trusktr opened this issue Jan 19, 2025 · 1 comment
Open

[@sheet] [AtSheet] solving the duplicate sheet issue. #933

trusktr opened this issue Jan 19, 2025 · 1 comment

Comments

@trusktr
Copy link

trusktr commented Jan 19, 2025

Problem

With this new @sheet feature, can we please see if we can solve the duplicate sheet issue? The issue is described here:

The TLDR is that when @importing a sheet into other sheets for code modularity and keeping code DRY, what ends up happening is that every @import of a sheet ends up duplicating the sheet (separate CSSStyleSheet instances) which causes each successive duplicate sheet to override any previous customizations in the cascade. The duplicate sheets are visible in document.styleSheets.

This is undesirable because it is unlike EcmaScript modules: unlike with JavaScript import syntax, with CSS @import syntax we cannot rely on multiple imports creating a single instance of a module to share with all dependents that import the module.

To describe it another way, if every time a JS module was imported it made a new instance of the module, it would be highly undesirable and would render ESM highly unusable for specifying dependencies in a manner in which dependencies are localized to the files that need the dependencies. This is the problem that CSS @import has. CSS @import is more like a macro, placing and duplicating the imported style.sheet at that source location.

So, if this will work for JavaScript,

// a.js
import {foo} from './some-sheet.css' with {type: 'css'}
globalThis.foo1 = foo
// b.js
import {foo} from './some-sheet.css' with {type: 'css'}
globalThis.foo2 = foo
// test.js
import './a.js'
import './b.js'

// Expect the sheet to exist once, not duplicated
console.assert(globalThis.foo1 === globalThis.foo2)

then we should ensure that we also have a way to do that with CSS @import syntax for the sake of not only consistency, but for code organizational ability. Without this, we must avoid @import in CSS and instead give end users if a list of all imports they need to write at the head of their app rather than localized in their code files), greatly reducing the DX of authoring CSS.

Solution?

Either it can be fixed with @import sheet(), or a new import syntax is needed for CSS. In hind sight it would have been nice if @import was called @include and that a new @import would have been more modular.

Or is it possible to add a key word like once to @import to opt in? F.e. @import sheet(...) once;. However it seems once (or more accurately ES module) behavior needs to be a default option (or better-yet the only option, see "final thoughts" below as to why).

Example

What do you want this to do?

/* some-sheet.css */
@sheet foo {
  div {
    --some-color: pink;
    color: red;
    background: var(--some-color);
  }
}
/* a.css */
@import sheet('./some-sheet.css#foo');

div {
  color: blue;
}
/* b.css */
@import sheet('./some-sheet.css#foo');

div {
  border: 1px solid var(--some-color);
}
<link rel="stylesheet" href="./a.css">
<link rel="stylesheet" href="./b.css">

<div>hello</div>

<!-- Now is the `color` of the div here blue? Or red? -->

After this series of a.css and b.css files are loaded, the div will be red, not blue.

The solution (whether here or in a separate spec) will result in the div color still being blue, as desired.

The reason this would be good is because now someone can import a.css, b.css, or both, without having to worry about what import dependencies they have (just as with JavaScript modules).

Note, the new feature would also want to ensure that CSS modules (i.e. single non-duplicated sheets) are hoisted above all sheet in a module graph. This is the only sane way to ensure sheet ordering is not a problem depending on ordering of dependents in a graph. I.e. the module graph order should be king.

final thoughts

I think it is important to solve this problem in CSS for code modularity, otherwise the disparity between JS modules and CSS modules will grow, leading to more and more failed expectations as CSS Modules come out in all browsers.

To that end, perhaps we also need @export for the convenience of being able to write CSS Module libs that can re-export from multiple files (with the same semantics as JS modules and non-duplication).

Having an optional once feature may work against a future if well-organized JS and CSS modules. Making the behavior match with JS modules will be very good for a consistent future with CSS modules: it will be easy to reason about, intuitive.

@trusktr
Copy link
Author

trusktr commented Jan 19, 2025

Another way to think about it is that we shouldn't give CSS authors a solution to this problem only in JavaScript, but also in CSS.

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

1 participant