Skip to content

fix: pin cascade-layer order and classify workspace symlinks#247

Merged
arbrandes merged 1 commit intoopenedx:mainfrom
arbrandes:fix-layer-order
Apr 24, 2026
Merged

fix: pin cascade-layer order and classify workspace symlinks#247
arbrandes merged 1 commit intoopenedx:mainfrom
arbrandes:fix-layer-order

Conversation

@arbrandes
Copy link
Copy Markdown
Contributor

@arbrandes arbrandes commented Apr 23, 2026

Description

The @layer paragon, shell, app, site, brand; declaration used to live at the top of shell/style.scss. Because CSS cascade-layer priority is locked in by the first mention of each layer name, this only worked when that file was the first CSS the browser parsed; other shell SCSS reached earlier via webpack's import traversal was emitting @layer shell { ... } blocks first and inverting the intended order. Moved the declaration to its own shell/layer-order.scss, registered as a dedicated webpack entry, and pinned its <link> to the top of <head> via HtmlWebpackPlugin's chunksSortMode: 'manual'.

Also fixed a related misclassification in npm-workspace / bind-mount dev setups. Paragon, shell, and brand rules now classify by the name field in each package's package.json (via webpack's descriptionData), which is independent of filesystem layout. The site/app split remains path-based, broadened to cover /packages/ as well as /node_modules/.

Fixes #246.

pr247

LLM usage notice

Built with assistance from Claude.

@arbrandes arbrandes force-pushed the fix-layer-order branch 2 times, most recently from 5166a1e to c9e5eed Compare April 23, 2026 17:29
@arbrandes arbrandes force-pushed the fix-layer-order branch 2 times, most recently from 70761c6 to 71a508f Compare April 24, 2026 10:30
Copy link
Copy Markdown
Contributor

@brian-smith-tcril brian-smith-tcril left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

One naming nit and one out-of-scope comment.

inject: true,
template: path.resolve(process.cwd(), 'public/index.html'),
chunks: ['app'],
chunks: ['layerOrder', 'app'],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it might be nice to specifically mention stylesheets in the chunk name, so something like stylesheetLayerOrder or styleLayerOrder or cssLayerOrder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going with cssLayerOrder.

const NODE_MODULES = /[\\/]node_modules[\\/]/;
export const PARAGON_PACKAGE = { name: '@openedx/paragon' };
export const SHELL_PACKAGE = { name: '@openedx/frontend-base' };
export const BRAND_PACKAGE = { name: /^@(open)?edx\/brand(-.+)?$/ };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking, and out-of-scope for this PR, but the more I think about it the more I feel using a regex to match brand packages is a bit odd.

With the npm aliasing method used by MFEs, there were no restrictions on what site operators could name their brand packages.

I'm not sure how many site operators are using brand packages that don't match the regex, so it's possible this is a non-issue, but I figured it's worth flagging to at least think about.

Copy link
Copy Markdown
Contributor Author

@arbrandes arbrandes Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative is to do what Atlas does, which is to require metadata in the package.json. I don't dislike that idea, not only for brand but for apps: that would give us a way to have an app layer literally just for apps, not as a catch-all. (And to put the node_modules stuff in its own layer before anything else).

But we can do this in a subsequent series of PRs.

CSS cascade-layer priority is locked in by the first mention of each
layer name. With the order statement living at the top of
`shell/style.scss`, other shell SCSS files reached earlier by webpack's
import traversal were registering `shell` before `paragon` and inverting
the intended order. Move the declaration to its own
`shell/layer-order.scss`, loaded first via a dedicated webpack entry.

Also classify named packages by package.json name, where possible.
This makes it more flexible (so that it applies to workspaces, for
instance).

Fixes openedx#246.

Co-Authored-By: Claude <noreply@anthropic.com>
@arbrandes arbrandes enabled auto-merge (rebase) April 24, 2026 14:08
@arbrandes arbrandes merged commit 9795efa into openedx:main Apr 24, 2026
5 checks passed
@arbrandes arbrandes deleted the fix-layer-order branch April 24, 2026 14:11
@openedx-semantic-release-bot
Copy link
Copy Markdown

🎉 This PR is included in version 1.0.0-alpha.40 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Layer ordering incorrect (shell coming in above paragon)

3 participants