Skip to content

File concatenation and minification

By default, if enqueued, an application’s JavaScript and CSS files are concatenated in order to reduce the number of requests that occur on a single page load. CSS files are minified as well as concatenated, which reduces file size by removing unnecessary white space. If JS or CSS files are minified in a theme as part of a build process, include the source files for the purpose of code review.

  • Logic for concatenation is handled by the nginx-http-concat plugin.
  • By default, file concatenation is disabled for page views in the WordPress Admin dashboard.
  • Concatenated assets can be identified in the “Network” tab of a browser inspector by request paths beginning with /_static/??.
  • Concatenated assets are cached by NGINX with a Cache-Control HTTP header set to cache-control: max-age=31536000 (1 year). This cache is busted when resource versions are updated.

The responses that are generated by VIP sites are served from a global network of edge cache server locations. This allows a majority of a site’s traffic, including concatenated scripts and styles, to be served directly from an edge location closest to a site’s visitors without ever hitting a line of PHP. This results in the low-latency and high-performance impact expected from a CDN.

Limitations

  • Files that are enqueued from a third-party resource—or outside of an application’s wpcomvip GitHub repository—will not be minified or concatenated.
  • Some third-party performance scans may not recognize VIP’s CDN as a result of concatenated files being served from the same domain as the VIP site.

Versioning to bust the cache

By default, the VIP Platform concatenates JavaScript and CSS files that are enqueued in an application’s codebase. The concatenated files are cached with a Cache-Control HTTP header set to cache-control: max-age=31536000 (1 year).

To bust the cache on deployment, the $ver value in the enqueue must be incrementally updated when changes are made to enqueued JS and CSS files. An updated $ver value effectively generates a new and unique static URL for the concatenated assets. The $ver value can be updated in functions such as wp_enqueue_script(), wp_enqueue_style(), wp_register_script(), and wp_register_style().

// When changes are made to js/plugin.js the $ver variable should be incrementally updated.
$ver = '1.1';
wp_enqueue_script( 'plugin_script', plugins_url( 'js/plugin.js', __FILE__ ), array(), $ver );

Because file Input/Output (I/O) operations can be expensive, VIP does not recommend using the function filemtime() to populate a value for $ver on production environments.

Script tag attributes filter

Accepted values: defer | async | nomodule | crossorigin | integrity | type | nonce | referrerpolicy

Script attributes such as async or defer can be added to concatenated scripts with the js_concat_script_attributes filter.

In this example, the attributes async and defer are added to all concatenated scripts:

add_filter( 'js_concat_script_attributes', function( $args, $href, $js_array, $jsconcat ) {

    return stristr( $href, '_static' ) !== false ? [ 'async', 'defer' ] : [];

}, 10, 4 );

Disabling concatenation

Available filters can be used to exclude specific JS or CSS files from concatenation bundles. When disabling concatenation for JS or CSS, consider adding logic to specifically disable concatenation in is_admin() or not.

js_do_concat filter

Example code to exclude specific JS files from concatenation with the js_do_concat filter:

add_filter( 'js_do_concat', 'my_vip_js_concat_filter', 10, 2 );

// do not include my-script-handle in concatenated bundles
function my_vip_js_concat_filter( $do_concat, $handle ) {
    if ( 'my-script-handle' === $handle ) {
		return false;
	}
	return $do_concat;
 }

To disable concatenation for all JS files, set the js_do_concat filter to return __return_false:

// disable JS concatenation
add_filter( 'js_do_concat', '__return_false' );

css_do_concat filter

Example code to exclude specific CSS files from concatenation with the css_do_concat filter:

add_filter( 'css_do_concat', 'my_vip_css_concat_filter', 10, 2 );

// do not include my-custom-css-handle in concatenated CSS bundles
function my_vip_css_concat_filter( $do_concat, $handle ) {
    if ( 'my-custom-css-handle' === $handle ) {
		return false;
	}
	return $do_concat;
}

To disable concatenation for all CSS files, set the css_do_concat filter to return __return_false:

// disable CSS concatenation
add_filter( 'css_do_concat', '__return_false' );

Troubleshooting

In-browser debugging methods

Query parameters can be added to a URL in the browser to disable concatenation and help determine if a JS error or CSS issue is related to concatenation.

Adding these parameters to an affected URL in the browser will load the individual JS or CSS files for the request instead of the static concatenated bundle. These query parameters are only meant to be used for testing in a browser and should not be added to code.

  • JS: concat_js=false
  • CSS: concat_css=false

Updated concatenated assets not loading as expected

It is possible for built assets and concatenation to cause short-term brokenness in CSS and/or JS when combined with full page caching.

Because previously concatenated bundles are cached at the edge, newly deployed changes will usually reference a new bundle, while existing cached pages will reference an old one. If either needs to be reconstructed due to a cache miss, the enqueued files must still be available on the server – the URL contains the filenames (usually compressed).

Because of this, avoid deleting older versions of those built files for at least 30 minutes so they can be used as needed. If 404s occur for previously-good bundles, this is a likely cause – one of the component files is missing. When overwriting these files, an old URL may suddenly contain the new assets even though the page was generated before the deploy.

Last updated: February 29, 2024

Relevant to

  • WordPress