Front-End Performance

Image sizes, JS bundling, critical CSS and third-party tags, and what the bundled Luma theme costs before you write anything.

Syntaxbin/magento config:set dev/js/enable_js_bundling 1

Luma, the theme bundled with Magento, carries a large JavaScript dependency graph. A Luma category page loads RequireJS, jQuery, Knockout and the UI component library before it finishes rendering. That cost exists before you write a line, and tuning does not remove it. Knowing this changes what is worth your time.

What is worth doing

Image dimensions come from the theme's etc/view.xml, one entry per place an image appears. Getting them right is usually the largest single win, because the storefront then serves a resized copy instead of the uploaded original. Apply a change with bin/magento cache:flush, then build the new sizes with bin/magento catalog:images:resize.

Bundling concatenates RequireJS modules into fewer files. Turn it on with bin/magento config:set dev/js/enable_js_bundling 1, add dev/js/minify_files 1, then rebuild with bin/magento setup:static-content:deploy and bin/magento cache:clean config. Magento's own bundler groups every module into bundles per theme, which helps a first visit and wastes bytes on later ones. Measure both.

Critical CSS is off by default. Setting dev/css/use_css_critical_path to 1 inlines your theme's web/css/critical.css into the head and loads the remaining stylesheets asynchronously. You write that file; Magento does not generate it.

What trips people up

Third-party tags are usually the biggest cost and the one you control least. Measure the page with them blocked before optimising anything of your own, or you will spend a week recovering 80ms that a tag manager spends twice over.

Example

Example · xml
<!-- app/design/frontend/Vendor/theme/etc/view.xml -->
<view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/view.xsd">
    <media>
        <images module="Magento_Catalog">
            <image id="category_page_grid" type="small_image">
                <width>240</width>
                <height>300</height>
            </image>
            <image id="category_page_list" type="small_image">
                <width>240</width>
                <height>300</height>
            </image>
            <image id="product_page_image_medium" type="image">
                <width>700</width>
                <height>700</height>
            </image>
            <image id="cart_page_product_thumbnail" type="small_image">
                <width>165</width>
                <height>165</height>
            </image>
        </images>
    </media>
</view>

When to use it

  • Cut a category page's image payload without re-uploading any product photos.
  • Decide whether bundling helps a storefront whose visitors land once and leave.
  • Give a marketing team a measured number for what their tag manager costs.
  • Set a realistic page-speed target for a Luma-based build before quoting the work.

More examples

Turning on bundling and minification

config:set writes into core_config_data, which is the same place the admin writes when you change Stores > Configuration > Advanced > Developer. That section is hidden in production mode, which is why the CLI is the normal route. The settings alone change nothing on disk: setup:static-content:deploy is what produces the bundled and minified files under pub/static, and the config cache clean is what makes the storefront link to them. Deploy every locale the store serves, or the ones you omit have no static files at all.

Example · bash
bin/magento config:set dev/js/enable_js_bundling 1
bin/magento config:set dev/js/minify_files 1
bin/magento config:set dev/css/minify_files 1
bin/magento config:set dev/template/minify_html 1
bin/magento config:set dev/static/sign 1

# Rebuild and publish the static files, then let the config cache see the change
bin/magento setup:static-content:deploy en_GB en_US -f
bin/magento cache:clean config

# Value was saved in app/etc/env.php and locked. Use app:config:import to apply.
# ... or, in a normal install:
# Value was saved.

Two forms of the same JavaScript initialisation

These two are the same call: both ask RequireJS to load Vendor_Perf/js/slider and apply it to that element with that configuration. data-mage-init is shorter and keeps the configuration next to the markup. x-magento-init is what you need when the element is rendered by someone else's template, when one script configures several selectors, or when the target is "*" for a component with no element of its own. Recognising both matters because core templates use whichever suited them. Neither form blocks rendering; a plain inline script tag does.

Example · html
<!-- Shorthand: data-mage-init on the element the component binds to -->
<div class="vendor-slider"
     data-mage-init='{"Vendor_Perf/js/slider": {"interval": 5000}}'>
</div>

<!-- Longhand: x-magento-init, with the element named by a CSS selector -->
<div class="vendor-slider"></div>
<script type="text/x-magento-init">
{
    ".vendor-slider": {
        "Vendor_Perf/js/slider": {"interval": 5000}
    }
}
</script>

Loading a third-party script through RequireJS

A remote path is left alone by bundling and minification, which is the point: the file stays on the vendor's CDN but is fetched asynchronously by RequireJS rather than by a blocking script tag in the head. The shim entry is for a script that does not call define() itself; exports names the global it leaves behind so other modules can depend on it. Omit the .js extension, because RequireJS appends it. Run bin/magento setup:static-content:deploy and bin/magento cache:flush after adding the file, since requirejs-config.js files are merged at deploy time.

Example · javascript
// app/design/frontend/Vendor/theme/requirejs-config.js
var config = {
    paths: {
        vendorWidget: 'https://cdn.example.com/widget/3.2/widget.min'
    },
    shim: {
        vendorWidget: {
            exports: 'VendorWidget'
        }
    }
};

Discussion

  • Be the first to comment on this lesson.