Overview

Parent issue #3499919: [Meta] Plan for in-browser code components
Related / Blocked by

As part of authoring code components, global CSS needs to be managed: stored and exposed via an HTTP API.
This will also serve as Tailwind CSS v4 configuration, which XB will support for code components.

Proposed resolution

UI is not in the scope of this issue, that will be added in #3499988: Editing code components.

Consider how this may reuse the work done in #3499927: Config entity for storing code components and #3499931: HTTP API for code component config entities. It may not be feasible as the only useful property of that config entity would be source_code_css. Also the global CSS is more of a singleton use case.

Implement a subset of what https://www.drupal.org/project/component_library already has, but in a more strictly validated and tested manner:

  1. New AssetLibrary config entity type (human-readable name: in-browser code library) per @balintbrews' #18:
    /**
     * @ConfigEntityType(
     *    id = "xb_asset_library",
     *    label = @Translation("In-browser code library"),
     *    label_singular = @Translation("in-browser code library"),
     *    label_plural = @Translation("in-browser code libraries"),
     *    label_collection = @Translation("In-browser code libraries"),
     *    admin_permission = "…",
     *    handlers = {
     *      …
     *    },
     *    entity_keys = {
     *      "id" = "id",
     *      "label" = "label",
     *      "status" = "status",
     *    },
     *    links = {
     *      …
     *    },
     *    config_export = {
     *      "label",
     *      "id",
     *      "css",
     *      "js",
     *    }
     *  )
     */
    
  2. This is the config-defined (and hence importable/exportable) equivalent of asset library definitions in *.libraries.yml.
  3. Its config schema explains initial limitations and the impact + potential values of each key-value pair in the config entity:
    experience_builder.asset_library.*:
      type: config_entity
      constraints:
        FullyValidatable: ~
      mapping:
        id:
          type: machine_name
          label: 'Asset library ID'
          constraints:
            Choice:
              # ℹ️ Initially, only one such config entity is allowed. Later, one per theme. Later still, additional ones. Details TBD.
              - global
        label:
          type: required_label
          label: 'Human-readable label'
        # If not `null`:
        # - css will be stored on the filesystem at public://xb/asset_libraries/global/global.css
        # - will be taken into account for generating an opaque version identifier, to ensure aggregated CSS is never stale
        css:
          type: mapping
          label: 'CSS'
          # The asset library may contain only JS, no CSS.
          nullable: true      
          mapping:
            source:
              type: text
              label: 'Source CSS as entered by the human author'
            compiled:
              type: text
              label: 'Compiled CSS code, compiled from the source'
        # If not `null`:
        # - will be stored on the filesystem at public://xb/asset_libraries/global/global.js
        # - will be taken into account for generating an opaque version identifier, to ensure aggregated JS is never stale
        js:
          type: mapping
          label: 'JS'
          # The asset library may contain only CSS, no JS.
          nullable: true
          mapping:
            source:
              type: text
              label: 'Source JS as entered by the human author'
            compiled:
              type: text
              label: 'Compiled JS code, compiled from the source'
    
  4. XB would expose them using hook_library_info_build(). (⚠️ There's a risk that other code starts explicitly depending on them. Which could lead to BC breaks when an in-browser code component changes. This is a low risk, and cannot be triggered when using XB, only by writing and deploying PHP code. So the risk is low.)
  5. Generate those CSS and JS assets on disk, regardless of whether config is saved through user interaction or through config deployment — similar to https://git.drupalcode.org/project/component_library/-/commit/a78f3af960...
  6. Ideally: do so in a workspaces-compatible way — learn from https://git.drupalcode.org/project/component_library/-/commit/06c4827a8c...
  7. For the scope of this issue, only one such AssetLibrary config entity would be allowed, with the ID global. We can then bikeshed how to lift that restriction in future issues, where we have more information about what should be solved. (⚠️ This means that whenever in-browser code components from site A that uses site A's global CSS would be exported and imported into site B, where there already is other global CSS, that it'll be up to the person doing that export+import to manually copy over the global CSS. Because Drupal's config management system does not support resolving conflicts.)
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

balintbrews created an issue. See original summary.

balintbrews’s picture

balintbrews’s picture

Issue summary: View changes
Related issues: +#3499988: Editing code components
effulgentsia’s picture

Also the global CSS is more of a singleton use case

Is it? Or perhaps someone might want multiple, each representing a different look? For example, perhaps a university site where each department has its own branding?

I think our initial implementation can be based on having just one, but I think conceptually having a config entity type for this that could in principle allow multiple config entities of that type would be good.

We need to come up with a name for this config entity type.

Also, would it make sense for the same entity to have any other property besides the CSS? For example, another global or semi-global thing might be a javascript import map (mapping bare package names of dependencies that the JS components might want to use, like perhaps components from Radix UI, to CDN assets, for example perhaps generated with https://jspm.org/). But I wonder if that belongs in the same entity as the global CSS (are the two each aspects of the same higher level concept like a theme or design system) or if global CSS and import maps belong in different entities / entity types (are they aspects of different concepts such as global CSS being an aspect of a theme whereas import map is an aspect of a component library)?

longwave’s picture

Should this be part of the page template entity, given we currently have one of those per theme?

wim leers’s picture

Assigned: Unassigned » effulgentsia

#5++

That addresses this concern by @effulgentsia:

I think our initial implementation can be based on having just one, but I think conceptually having a config entity type for this that could in principle allow multiple config entities of that type would be good.

But

Also, would it make sense for the same entity to have any other property besides the CSS? For example, another global or semi-global thing might be a javascript import map (mapping bare package names of dependencies that the JS components might want to use, […]

is a very different beast. I'd rather keep the scope restricted to just CSS.

If we can do that, then I think @longwave's idea works.

lauriii’s picture

Singleton would be fine for the 0.3.0 release but I agree that we may want to put some consideration to the long term need. We may want multiple global stylesheets in future but I'm not sure how much we need to account for that now. If we start with a singleton (i.e. one stylesheet per theme), wouldn't it be pretty straightforward to migrate to whatever format we decide in future?

I'm not sure that the page template is the right config to tie this with. In future, I'd imagine we would tie the global CSS to the style guide once that becomes available. Given that the style guide is not fully defined yet, it might be hard to take everything into account now.

wim leers’s picture

Component: Data model » Config management

#7 doesn't really answer my "different beast" remark. 😅 @lauriii told me in DM that we definitely need that eventually. Fine!

I don't know enough about JS import maps yet, nor why we need them (presumably for JS components, i.e. many JS components might all need the same import map?). And perhaps we don't know enough about it in general yet, given Given that the style guide is not fully defined yet, it might be hard to take everything into account now.?

Global CSS is comparatively simpler, so let's restrict this to just that. 🙏

wouldn't it be pretty straightforward to migrate to whatever format we decide in future?

Absolutely! :) Not even migrate, but update :D (Update path tests for config entities are a solved problem 😃)

effulgentsia’s picture

Issue tags: +sprint

Up until now, the XB team has been following a pseudo-scrum/pseudo-kanban process, but we're now shifting into more conventional scrum. We started a new 2-week sprint last Thursday (Jan 16). I'm tagging our current sprint's issues for visibility.

effulgentsia’s picture

Assigned: effulgentsia » Unassigned

Having thought about the import map problem space a bit more, I don't think it makes sense for import map config to be either global, per-theme, or per-style-guide, but rather it's something that should get merged dynamically based on information that's in each code component. I opened #3500761: Allow code components to import from npm packages with more detail about that, but the point is, it means there's no other configuration that we currently know of that would be "per style guide" (see #7) other than the global CSS.

Meanwhile, #7 says we probably don't want to combine global CSS with the page template entity. I'm not completely clear on why we would or wouldn't want to do that, so I'll defer to @lauriii's intuition on this.

Which means, we're talking about a new config entity type whose only property is the global CSS. So for naming, I guess we should go with *.global_css.yml? Possibly in the future we might figure out the details of a *.style_guide.yml and would need to update from the former to the latter, but #8 indicates that that's okay?

longwave’s picture

> We may want multiple global stylesheets in future

I don't get why we are saying this here, but previously we stated that we would only ever have one page template per theme. To me a global stylesheet ties in with a global page template. Back then I could see that I might want multiple page templates - some "special" pages might want to opt in to an entirely different template via some mechanism - but we ruled that out, so why aren't we doing the same for global CSS?

Until the way ahead and the future requirements are clearer, I still think the simplest option is to add this as an additional property to the page template config entity. As stated in #8 we can always migrate CSS from the page template to somewhere else. It's easier to add a single property to an existing config entity and move it later, than it is to define a whole new config entity and refactor/remove the whole thing later.

lauriii’s picture

I don't get why we are saying this here, but previously we stated that we would only ever have one page template per theme.

I don't think this assumption is true – at least it's not an assumption we should rely on. What might change this in future is having to implement support for variants. I don't know how we'd implement these technically, but one possible option may be to allow multiple page templates in a theme with some negotiation on which page template should be resolved to a given route. I don't know how fundamental this assumption is currently but if it is, maybe we need to try to design the system for the variants soon so that we can plan for what needs to change.

To me a global stylesheet ties in with a global page template. Back then I could see that I might want multiple page templates - some "special" pages might want to opt in to an entirely different template via some mechanism - but we ruled that out, so why aren't we doing the same for global CSS?

Global CSS in it's most basic form is different from this though. There needs to be some place where it is possible to store design tokens that are true across the whole system. On top of that, we may need a separate stylesheet in future that is tied into a page template as an additional form of customization but it doesn't seem like a mutually exclusive concept.

wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

@effulgentsia at #10: great, I inferred the same ~8 hours ago at #3500761-7: Allow code components to import from npm packages (i.e. that this metadata/dependency information belongs in the config entity that #3499927: Config entity for storing code components is introducing).


I wholeheartedly agree with @longwave in #11.


@lauriii in #12: there's not a single word in the 64 XB product requirements about variants for page templates. Only for content type templates, the concept of "variants" is stated. Route-specific choices should be achieved using requirement 41. Conditional display of components per the requirements. If your thinking has evolved, can you please add a new requirement there? 🙏 I don't see how any one of us could possibly have known your intent to support "page template variants".

(Not that I think that supporting PageTemplate variants would be complicated: it'd only require changing \Drupal\experience_builder\EventSubscriber\RenderEventsSubscriber::onSelectPageDisplayVariant(). But whether variants for some subset of routes should be completely independent alternatives to the "master variant" for a theme (completely different component trees for all regions and/or completely different global CSS), or whether it'd just be targeted overrides (completely different component trees for some regions and/or additional global CSS, on top of what the "master variant" contains) impacts everything here a lot. We need to deliver #3499919: [Meta] Plan for in-browser code components by the end of February, this issue is not the time nor place to start exploring potential future things.

There needs to be some place where it is possible to store design tokens that are true across the whole system.

Global CSS is an orthogonal concern to design tokens. Design tokens is not being worked on for #3455753: Milestone 0.2.0: Early preview. Design tokens may be exposed through CSS, but that's an implementation detail for later. Very little is known/defined for how "design tokens" will appear in the UI and how they impact other XB functionality. Let's stay focused on the task at hand 🙏 The issue summary here is about the ability to store (not even load!) CSS rulesets that apply to >=1 in-browser code components.

I mean, it's very interesting and tempting to think about how to make Design Tokens a reality in XB! 😄 But here, it costs us valuable time to deliver what we're supposed to deliver in 39 days, for something that isn't well-defined yet.


AFAICT the only question that truly needs answering here for this issue's scope is: Are in-browser code components supposed to be theme-agnostic or should they only be available within a particular theme? If the answer is:

  • "theme-agnostic": then we cannot store the global CSS for in-browser code components in the PageTemplate config entity, because a PageTemplate config entity is necessarily theme-specific.
  • "theme-coupled": then we can store the global CSS for in-browser code components in the PageTemplate config entity.
effulgentsia’s picture

Status: Postponed (maintainer needs more info) » Active

Are in-browser code components supposed to be theme-agnostic or should they only be available within a particular theme?

I don't even think that that's relevant. CSS for a code component will live in the code component's config entity. So the question in this issue is just whether the global CSS should be per-theme or not, and I think that's independent of whether code components are per-theme or not. @lauriii in #7 already said that global CSS is per-theme, which makes sense to me.

One problem with tying the global CSS to the page template, is then does that mean that someone who doesn't check the Use-XB-for-regions checkbox also doesn't get global CSS? Or is that not an issue anymore with #3498248: PageTemplate: allow configuring which regions are exposed, since now we can change our logic to always create the page template and just not opt it into any regions until the user opts those regions in?

Also, in the future we may well want to have >1 page template for the same theme sharing the same global CSS, but if we don't mind moving the global CSS to a different config entity type at that point in time, when hopefully we'll have more clarity about which config entity type to move it into, then I think it's fine to put it in the page template for now as long as the paragraph above has an answer.

longwave’s picture

@wim leers I discussed this a bit on standup with @lauriii. We came to the conclusion that "global CSS" (which perhaps needs a different name) should be stored separately from page templates. Initially there will be a 1:1 mapping of global CSS to themes, the same as page templates, but perhaps in the future you might want multiple CSS files, in which case we would need to extend that out. Also, to the site owner, editing global CSS will be done separately from editing the page templates, so it seems to make sense to keep the concepts separate on the back end as well. As #14 states you might want to use global CSS without enabling page templates for the current theme; the global CSS will be applied whether or not a page template is currently in use.

effulgentsia’s picture

"global CSS" (which perhaps needs a different name)

Yep, naming is hard. "global" here refers to "not tied to a single component". I think "global CSS" is a common term in front-end development, but "global" here isn't meant to imply back-end globality (like there only being one for the entire site, regardless of theme, etc.).

One possibility is we name the new config entity type "style_guide"? Even though we don't know exactly what this concept will entail yet, but we can start it off with a css property and find out later what other properties to add to it? And we start off with one Style Guide entity per theme, and perhaps later there'll be a product requirement to allow >1 style guide per theme?

wim leers’s picture

Title: Storage for global CSS » Storage for CSS shared across in-browser code components (and PageTemplate config entities in the distant future)
Issue tags: +Needs issue summary update, +Needs title update

@longwave in #15:

editing global CSS will be done separately from editing the page templates, so it seems to make sense to keep the concepts separate on the back end as well.

This is the strongest argument to make it separate.

the global CSS will be applied whether or not a page template is currently in use.

That actually answers my question from #13: it should be theme-agnostic.

But it contradicts @effulgentsia's

@lauriii in #7 already said that global CSS is per-theme, which makes sense to me.

(I do not read that in #7, by the way. AFAICT "one stylesheet per theme" was merely in response to what @longwave was proposing in #5.


@effulgentsia in #14:

So the question in this issue is just whether the global CSS should be per-theme or not, and I think that's independent of whether code components are per-theme or not.

That's not independent though: a JavascriptComponent config entity needs to have all global CSS it relies upon to be loaded. That means it must depend on the config entity storing/providing that global CSS.

So if the global CSS is stored in the PageTemplate config entity, then necessarily the JavascriptComponent must depend on that page template's theme.

If the global CSS is not stored in the PageTemplate config entity, then it must live in another config entity, and then the JavaScriptComponent config entity must explicitly depend on that.


AFAICT that means this issue must introduce a new SharedCss config entity type (because "global" is a misnomer as @longwave points out in #15). But … how should it be identified? Perhaps we start with a "singleton" and default to default as the ID of the sole GlobalCss config entity?

Do we agree? If so, we should overhaul the issue summary to reflect the actually intended scope rather than the original scope. I already updated the title to match my current understanding — feel free to change it again if I misunderstood! 😅

Future questions this raises, which are all out-of-scope for this issue:

  • How does a JavascriptComponent specify which SharedCss it relies upon, and how do we expose that in the UI?
  • How do we guarantee that it works correctly across all themes? (AFAICT we don't/we can't/it's up to the JS component author?)
  • If/when the PageTemplate needs some CSS in the future, it too could just start depending on a SharedCss config entity.
balintbrews’s picture

I'm gravitating towards a more abstract name, and I keep thinking how the concept is similar to what Drupal already calls libraries, and have been wondering if I should propose naming the config entity in-browser code library.

It would store JS/CSS source + compiled. (Similar to #3499927: Config entity for storing code components, but without props and slots, and without #3498889: ComponentSource plugin for code components being concerned about it.)

Then the "style guide" (#16) / "shared CSS" (#17) would be one way of consuming the capability of creating in-browser code libraries, but we might come across others. Thoughts?

wim leers’s picture

#16 And we start off with one Style Guide entity per theme, […] — but @lauriii and @longwave in #15 concluded the global CSS will be applied whether or not a page template is currently in use., which implies theme-agnosticness?

#16 + #18: I want to keep 'style guide' out of this conversation. 🙏Nowhere near enough is known about it. We shouldn't risk missing #3455753: Milestone 0.2.0: Early preview for something we don't know what it'll look like exactly yet, plus which we can easily refactor towards in the future.

#18:

  1. What would "compiled CSS" be?
  2. Can you provide an example of how two "code component" config entities depend on the same JS?
  3. I see no plans in the GIFs/designs at #3499919: [Meta] Plan for in-browser code components for JS that is shared across code components?
balintbrews’s picture

#16 And we start off with one Style Guide entity per theme, […] — but @lauriii and @longwave in #15 concluded the global CSS will be applied whether or not a page template is currently in use., which implies theme-agnosticness?

I feel like we can go back and forth whether the global CSS is meant to be theme agnostic. If we want to architect the perfect system, the answer will be yes and no. 🙂 That's why I'm proposing to work out a more generic storage mechanism, then we can do a simple layer on top with a simple use case as a start, i.e. the 1:1 mapping that was already mentioned.

#16 + #18: I want to keep 'style guide' out of this conversation. 🙏Nowhere near enough is known about it. We shouldn't risk missing #3455753: Milestone 0.3.0: Early preview for something we don't know what it'll look like exactly yet, plus which we can easily refactor towards in the future.

I think #16 proposed it merely as a name, nothing more, and I simply mentioned the already proposed names in #18.

#19:

  1. In the case of our Tailwind CSS v4 support, it would be the Tailwind-generated CSS resets + the transpiled version of the source CSS. In other (potential, future) cases it would simply be the transpiled version of the source CSS (think of autoprefixing and syntax lowering).
  2. In case of implementing global CSS, it would be assumed that it's added on all pages. We don't need to define explicit dependencies.
  3. No use case so far. But we may need it after we have #3500761: Allow code components to import from npm packages.
lauriii’s picture

there's not a single word in the 64 XB product requirements about variants for page templates. Only for content type templates, the concept of "variants" is stated. Route-specific choices should be achieved using requirement 41. Conditional display of components per the requirements. If your thinking has evolved, can you please add a new requirement there?

Clarified this in the requirements 👍 I'm glad this doesn't something that would be particularly complicated for us to introduce later. I'm also glad that we discussed about the requirement now that we were about to introduce something new that potentially may have impacted implementing this in future. 😊

#16 And we start off with one Style Guide entity per theme, […] — but @lauriii and @longwave in #15 concluded the global CSS will be applied whether or not a page template is currently in use., which implies theme-agnosticness?

The CSS should be tied to a specific theme. This would be used essentially for the same purposes as what the libraries key in themes .*.info.yml is used (as mentioned by @balintbrews in #18). If someone wants to reuse the same CSS in another theme, depending on their requirements, they could either set up a base theme with the common CSS or they could just copy the CSS to the other theme.

How does a JavascriptComponent specify which SharedCss it relies upon, and how do we expose that in the UI?

There's no explicit dependency to the global CSS in Drupal today. This assumption introduces many problems but I think we should keep it that way going forward because otherwise we'd be essentially introducing a 1:1 coupling of the theme and its components.

How do we guarantee that it works correctly across all themes? (AFAICT we don't/we can't/it's up to the JS component author?)

This needs to be taken into account in the way that components are build. E.g. they need to avoid hard dependency on the global CSS (e.g. providing default values for CSS variables when they do not exist). This is a hard problem that for example Tailwind tries to solve.

Not everyone cares about this. Many frontend developers are fine with introducing explicit dependencies from their components to their global CSS via CSS variables and rules. We should make it clear in documentation that doing this will make it harder for them to adopt external components. Unless you aim to repurpose your components or import external components, there's nothing wrong in that.

lauriii’s picture

I feel like we can go back and forth whether the global CSS is meant to be theme agnostic. If we want to architect the perfect system, the answer will be yes and no. 🙂 That's why I'm proposing to work out a more generic storage mechanism, then we can do a simple layer on top with a simple use case as a start, i.e. the 1:1 mapping that was already mentioned.

Had a brief conversation with @balintbrews to make sure we're aligned on the solution. We're aligned that having a single CSS file per theme for shared CSS within that theme is enough to capture most of the value and enable the Preact + Tailwind v4 solution that the team has been architecting. 👍

wim leers’s picture

@balintbrews in #20: Thanks!

simple use case as a start++

  1. 👍
  2. 👎 Because of 2 reasons:
    1. @lauriii states pretty definitively in #21 states again that it's theme-specific global CSS — so at minimum it'd require a dependency on a theme then. More about that below.
    2. That won't work for requirement 14. config management, because I could create code component A that assumes some global CSS on one site, and code component B in another environment that assumes other global CSS. When creating new config entities for XB, we must always do so in a way that requirement 14 is supported. That requires explicit dependencies. It almost makes me think that the global CSS should be stored as
  3. 👍

@lauriii in #21:
Thanks for adding requirement 45.1 Page template variants 😊

The CSS should be tied to a specific theme.

If the "global CSS" is tied to a specific theme, then that means that the code component being built (using component-specific JS, component-specific CSS and theme-specific "global CSS") itself depends on that theme. This appears to be confirmed by:

If someone wants to reuse the same CSS in another theme, depending on their requirements, they could either set up a base theme with the common CSS or they could just copy the CSS to the other theme.

Great! This is an important clarification! 🥳 And it actually means that @longwave's original proposal from #5 ("just store global CSS in the PageTemplate config entity for a theme") is relevant again, and the lowest level of effort. But, it'd result in an auto-save entry that looks weird — at least until #3500390: The pending changes API endpoint should list individual regions for global template changes allows seeing not "the (theme's) page template" as a unit of change to review/publish, but "a region in the theme's page template". From that POV, it'd then also make sense to expose "the theme's page template's global CSS" as its own line item in the "Review changes" UI.

However, the "theme-specific global CSS" should be prepared to support the new 45.1 Page template variants, and the global CSS is per theme, NOT per theme's page template variant. Given that, it follows that we should introduce a new config entity. Or … we just choose to accept that we'll have to lift it out of the PageTemplate config entity at the future point where we work on 45.1.

There's no explicit dependency to the global CSS in Drupal today. This assumption introduces many problems but I think we should keep it that way going forward because otherwise we'd be essentially introducing a 1:1 coupling of the theme and its components.

(Emphasis mine.)
Exactly, that coupling is a dependency which config entities must describe to not violate requirement 14. config management, but which you're stating we must somehow not do while still keeping things working reliably! 😬

How does this not conflict with your paragraph just before it? 🤔

💡 We could default to the JavascriptComponent config entity having an explicit dependency on the theme's global/shared CSS. That'd prevent problems for 14. config management. We could then still make it possible to sever those ties by providing an explicit Export code components for inclusion in another theme or Download code components or Export code components as package button, which would literally just omit that one explicit dependency. That AFAICT gets you everything you want:

  • maximum reliability (the default: dependency present)
  • maximum reuse (an explicit action that omits the dependency, which it must be anyway, because transplanting components from one site to another requires a subset of site A's config to be imported into site B — and this is all very close to requirement 1.2 Design system (foundations)'s "shipped as a package" statement!)

they need to avoid hard dependency on the global CSS

Will the in-browser code component creation UX toggling the preview having the global CSS applied vs not, to make it possible to verify the fallback nature?

wim leers’s picture

Title: Storage for CSS shared across in-browser code components (and PageTemplate config entities in the distant future) » Storage for CSS shared across in-browser code components (and other use cases in the future)
Issue summary: View changes
Status: Active » Needs review
Issue tags: -Needs issue summary update, -Needs title update

I updated the issue summary + title based on my current understanding.

In doing so, I tried to unify hard requirements (e.g. 14. config management support) with future intentions and ambitions (45.1 page template variants, 26. Styleguide, #3500761: Allow code components to import from npm packages …).

From that POV, I think @balintbrews' proposal at #18 for the concept of an in-browser code library makes sense. That'd be conceptually similar to https://git.drupalcode.org/project/component_library/-/blob/1.0.x/src/En....

Any final thoughts before I begin implementing this? :)

wim leers’s picture

Issue summary: View changes
wim leers’s picture

Issue summary: View changes

@balintbrews' feedback about "compiled CSS/JS" has been incorporated.

balintbrews’s picture

Thank you, Wim, for distilling all those comments into this solid proposal. 👏🏻

I think this will achieve what we need for #3499919: [Meta] Plan for in-browser code components. While I'm quite comfortable with what's being proposed, it definitely wouldn't hurt to get others to review it as well.

wim leers’s picture

Thinking this through on a run, I realized there's 3 things we've missed:

  1. major: sibling internal HTTP API issue for this new config entity, similar to #3499931: HTTP API for code component config entities — see #3499931-6: HTTP API for code component config entities.

    (EDIT: I see that this was already somewhat accounted for by Consider how this may reuse the work done in #3499927: Config entity for storing code components and #3499931: HTTP API for code component config entities. — but it would likely be simpler to first tackle just the config entity here and then tackle all internal HTTP API needs for both config entity types in #3500042: Auto-save code components)

  2. major: sibling issue for this new config entity, similar to #3500042: Auto-save code components (see point 1)
  3. minor: dependencies — asset libraries may need to depend on other asset libraries: not a problem for the scope of this issue; but we'll likely need that later
balintbrews’s picture

#28:

  1. My only suggestion/request would be to prioritize landing #3499931: HTTP API for code component config entities. If adding support for the config entity defined in this issue in #3499931: HTTP API for code component config entities would delay its completion, I suggest splitting that part into a separate issue — or perhaps expanding the scope of this one to handle it. This way, we won't hold up other issues.
  2. It might be worth waiting until the solutioning work is completed for #3500042: Auto-save code components, as it will then be easier to create the sibling issue.
  3. Yes, let's do that later, I'm not sure this will be needed for #3499919: [Meta] Plan for in-browser code components. 🙂
larowlan’s picture

Just chiming in here to note that our 'compiled JS' configuration will likely need to maintain a set of externals that are common with the built code of XB

i.e. we know XB imports react and react-dom. If any of these code components also need them, then we need to make sure that neither the XB built code OR the compiled_js in this asset library includes the react or react-dom code base. Otherwise they will be referencing _different_ instances of React and we will end up with all sorts of edge cases.

Both of them will need to use the external rollup option in the vite config AND we'll need to make use of an import map.

Alex's comments indicate he's already across this, but I just want to make it explicit.

wim leers’s picture

#29: ACK.

#30: I'm aware — see #3500761-14: Allow code components to import from npm packages — which I see you chimed in on since then. AFAICT @balintbrews' intent is to start without imports.

wim leers’s picture

Assigned: Unassigned » tedbow
Status: Needs review » Active

Ready to be implemented!

tedbow made their first commit to this issue’s fork.

tedbow’s picture

Starting looking at the issue. I am not clear why the schema in the summary using a mapping for CS and JS with sub elements for source and compiled

js:
      type: mapping
      label: 'JS'
      # The asset library may contain only CSS, no JS.
      nullable: true
      mapping:
        original:
          type: text
          label: 'Original JS as entered by the human author'
        compiled:
          type: text
          label: 'Compiled JS code, compiled from the original'

where as in the just finished #3499927: Config entity for storing code components we use

    source_code_js:
      type: string
      label: 'JavaScript Source code'
    source_code_css:
      type: string
      label: 'CSS Source code'
    compiled_js:
      type: string
      label: 'Compiled JavaScript'
    compiled_css:
      type: string
      label: 'Compiled CSS'

My guess is there is not particular reason for the difference. The mapping might make more sense but I think consistency is important, so I am going to go with what we used for experience_builder.js_component.* unless someone lets me know why these should behave differently

wim leers’s picture

#34: the answer is in the schema:

    # If not `null`:
    # - css will be stored on the filesystem at public://xb/asset_libraries/global/global.css
    # - will be taken into account for generating an opaque version identifier, to ensure aggregated CSS is never stale

Rationale:

  • It's totally reasonable to have an asset library without CSS or without JS. Plenty of examples of that in Drupal core.
  • It's impossible to have a "code component" without JS.
  • It's not reasonable to have a "code component" without CSS — there'll always be something to style. In the super rare case that there wouldn't be anything, storing the empty string in the config entity is fine.
wim leers’s picture

Issue summary: View changes

I did do s/original/source/ just now, to more closely match the final terminology used in #3499927: Config entity for storing code components. 👍

effulgentsia’s picture

I think the two should be consistent, so if we like the structure in this issue, let's open a followup to change the js_component one to match at least as far as the nesting goes, but it's okay if that one has different rules for what's required or not.

It's not reasonable to have a "code component" without CSS

When using Tailwind to style, I think most code components won't have source CSS. They'll still typically have compiled CSS though, generated from the Tailwind classes that are in the source JS.

wim leers’s picture

most code components won't have source CSS.

I know that, but the end result is still CSS, as you say. I was merely making a high-level comparison between "code component" and "generic asset library" in #35.

tedbow’s picture

Status: Active » Needs work
wim leers’s picture

Issue tags: +openapi
wim leers’s picture

Assigned: tedbow » Unassigned

FYI #3499931: HTTP API for code component config entities is in, merged that into this MR.

wim leers’s picture

Assigned: Unassigned » longwave
Status: Needs work » Needs review

@tedbow is still sleeping (hopefully).

The most critical remaining MR feedback was @longwave's remark about inconsistent CSS/JS representation between HEAD's JavaScriptComponent config entity and this MR's AssetLibrary config entity.

I agree with @tedbow that it makes more sense to adopt this issue's pattern for representing that consistently.

So implemented that: https://git.drupalcode.org/project/experience_builder/-/merge_requests/5....

I'd like @longwave to review that, and ideally also address his remaining remarks. 🤞

longwave’s picture

Assigned: longwave » Unassigned

This is ready for review now. The global asset library is attached to all pages, with a basic test to prove it (we could add more cases I guess, but this is a start).

wim leers’s picture

Assigned: Unassigned » wim leers
wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs review » Reviewed & tested by the community

  • wim leers committed f8128bb1 on 0.x authored by tedbow
    Issue #3499933 by tedbow, longwave, wim leers, balintbrews, effulgentsia...
wim leers’s picture

Status: Reviewed & tested by the community » Fixed
effulgentsia’s picture

Issue tags: -sprint

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.