Performance & native build-config compatibility¶
MageObsidian serves every stylesheet and script through Vite, not Magento's legacy Less/RequireJS pipelines. That changes how the native build-configuration flags behave, and it opens one optional optimization worth understanding: the critical CSS path.
This page covers both: the opt-in critical-CSS feature, and how Magento's dev/js/*, dev/css/* and dev/template/minify_html flags interact with an Obsidian theme.
Critical CSS (optional)¶
On an Obsidian theme the only render-blocking resource left in the head is the Vite stylesheet (style.css). The critical-CSS path inlines the above-the-fold CSS into the <head> and defers that stylesheet, so the first paint no longer waits for it.
It is off by default and opt-in.
Reuses the native flag¶
There is no MageObsidian-specific config. The feature reuses Magento's own switch, dev/css/use_css_critical_path (off by default). When you turn it on, MageObsidian inlines the critical CSS for the current layout handle and defers the stylesheet.
The defer is per-page, not global¶
Magento's native critical-path switch also activates AsyncCssPlugin, which rewrites every <link rel="stylesheet"> in the response to an async (media="print") load β globally. On any page that has no inlined critical CSS that produces a flash of unstyled content (FOUC).
MageObsidian avoids this:
- It neutralizes
AsyncCssPluginfor Obsidian themes only (legacy and admin themes keep the native behaviour). - It defers the stylesheet per page, in the head template, coupled to whether critical CSS exists for the active handle. A page with no critical CSS keeps the stylesheet render-blocking β never deferred without an inline counterpart, so there is never a FOUC.
Generating the critical CSS¶
The critical CSS is extracted from the real rendered page (so it reflects the actual above-the-fold markup) with Beasties, by a console command:
The command renders the URL, extracts the critical subset, rewrites the @font-face url(...) to an absolute (root-relative) static URL so the self-hosted fonts resolve once inlined in <head>, and writes web/generated/critical/<handle>.css in the active theme. Run it after the theme build and setup:static-content:deploy, because it reads the built stylesheet and resolves the deployed static URLs.
| Option | Default | Purpose |
|---|---|---|
--handle |
cms_index_index |
Layout handle the critical CSS is for. |
--url |
store secure base URL | The page to render. |
--store |
default store view | Store to emulate. |
--insecure |
off | Skip TLS verification (self-signed dev certs). |
--resolve |
β | A curl host:port:ip entry, for local setups behind a custom host. |
--node / --bin |
node / shipped bin |
Override the Node binary or the extractor script. |
Which pages to cover β it depends on your traffic¶
Critical CSS is generated per layout handle β one file per handle, and only pages whose handle has a generated file get the inline treatment. It is not a global switch; think of it as a per-entry-page optimization:
- The benefit concentrates on the first page of a visit, with a cold cache. From the second page on,
style.cssis already in the browser cache and the render-blocking request costs close to nothing. - If visitors mostly enter through the home page, the default
cms_index_indexcovers most of the win. - If organic search or ads land visitors directly on products and categories, those are first pages too β generate their handles as well:
One granularity caveat: a handle's critical CSS is extracted from one representative page and applied to every page sharing that handle (all product pages share catalog_product_view). The above-the-fold structure is normally identical across them; anything a specific page needs beyond the extract simply arrives with the deferred stylesheet β correctness is guaranteed, the optimization is partial.
Any handle without a generated file degrades to the render-blocking stylesheet.
Regenerate on every deploy¶
web/generated/critical/ is build output, not shipped source: a composer update of the theme β or any deploy that replaces it β wipes the generated files. Bake the generation into your deploy pipeline as its last step, once the site is already serving the new release (caches flushed, PHP-FPM restarted):
Generating earlier extracts the CSS from the previous release β or fails outright against a half-deployed site. The final cache:clean full_page matters because pages cached before the file existed were rendered with the fallback stub.
Read-only infrastructure (Adobe Commerce Cloud)¶
The generated file is written into the active theme's directory, which is read-only at runtime on Adobe Commerce Cloud and similar immutable deployments β while generation needs the live site, which only exists after the build phase. On those platforms, leave dev/css/use_css_critical_path off for now: pages stay correct with the render-blocking stylesheet. A runtime-writable storage location (so generation can run in a post_deploy hook) is under consideration.
Enabling it¶
The flag is scoped per store view. If the generated file is missing or unreadable, the head falls back to a tiny [v-cloak] stub and the normal render-blocking stylesheet β the page is always correct.
When not to use it¶
Critical CSS is a trade-off: it inlines CSS into every cached page (more HTML) to remove one render-blocking request. If a project does not want it, leave dev/css/use_css_critical_path off β the stylesheet stays render-blocking, which behind Varnish with gzip/brotli and HTTP/2 already loads in tens of milliseconds. Nothing else needs to change.
Native build-config flags¶
JS/CSS merge & minify β inert¶
dev/js/merge_files, dev/js/minify_files, dev/css/merge_css_files, dev/css/minify_files have no effect on an Obsidian theme. Those flags act on Magento's AssetCollection; MageObsidian emits its CSS and JS straight from Vite output (the importmap, the <link>, the <script type="module">), which never enters that collection. You can leave them at any value β minification and bundling are already handled by the Vite build.
HTML minification β disabled per theme¶
dev/template/minify_html is turned off for Obsidian themes (admin and legacy themes still minify). Two reasons:
- In production, with neither
force_html_minificationnor SCD-on-demand set, Magento returns the path to a pre-generated.mintemplate without creating it; that file never exists for the Vite/Twig pipeline, so the include fails with HTTP 500. - The regex minifier can corrupt the inline JSON the runtime emits β island
data-props, the importmap, JSON-LD β which is risky for no real gain (Varnish + gzip/brotli already collapse whitespace; the post-compression delta is ~1β3%).
You can leave the flag on globally; the storefront is unaffected.