Reduce your resource size with CSS and JavaScript Minification
Minification is one of the most common techniques web developers use to reduce the their app's resource sizes.
Minifiers are build tools that statically analyze your JavaScript and CSS resources and apply techniques for reducing their size by:
- Dead Code Elimination: Identifying unused codepaths that can be completely removed.
- Renaming and Reformatting: Of the code that cannot be removed, safely rename variables and remove extraneous whitespace and formatting
It's highly likely you are already using a minifier if you are using popular build tools like Webpack.
Why Minify Resources?
Resource size has a direct impact on both network and CPU utilization. Larger resources generally take longer to transfer over the network and they also take longer to process on your user's CPU once they are transferred.
Since web application performance is particularly sensitive to resource size, a performance-minded web developer should ensure no code being delivered to end users is extraneous or unused.
Tools Available
Some common minification tools include:
- Terser, which is automatically enabled for Webpack's
production
mode. - Closure Compiler which is an aggressive minifier and imposes constraints on how your app is authored to produce highly optimal bundles
- ESBuild minifies both JavaScript and CSS resources
- CSSNano, which is utilized in webpack's CSSMinifierPlugin
Dead Code Elimination
For JavaScript, a minifier will analyze code paths and detect if there are sections that are certainly not executed. This is called dead code elimination.
Here's an example:
const condition = false;
if (condition) {
doSomething();
} else {
doSomethingElse();
}
Dead code elimination can statically determine that condition
will always be false
. As a result, it can save precious bytes in our final payload,
by transforming the above code into simply:
doSomethingElse();
In CSS, a minifier can remove extraneous properties specified in source files. Here's an example:
.class-name {
padding: 50px 50px 50px 50px;
}
Dead code elimination for CSS determines that 3 out of 4 50px
definitions specified are extraneous. As a result, after dead code elimination,
our CSS file would look like this, saving previous bytes in our CSS file:
.class-name {
padding: 50px;
}
Tree Shaking
Tree shaking is a specific form of dead code elimination, and it's specific to the ES6 import
and export
syntax frequently used in modern web apps.
Tree shaking techniques involve statically analyzing the import
and export
graph to determine if unused export
s can be pruned
from the final payload.
Consider the following example files: functions.js
and app.js
:
// File functions.js
export function doSomething() {
console.log('Do Something')
}
export function doSomethingElse() {
console.log('Do Something Else');
}
// ... other functions
// File app.js
import { doSomething } from './functions.js';
doSomething();
In this example, while functions.js
exports many functions, only doSomething()
is actually pulled in via import
. As a result, tree shaking
will ensure only the doSomething()
function is included in the final payload delivered to the user.
In general, ensure the following are turned on for proper tree shaking:
- If using Webpack, ensure
package.json
property"sideEffects": false
is specified - Ensure you are using ES6
import
andexport
instead of CommonJSrequire
andmodule.exports
- If using TypeScript, ensure your
module
is set toes6
or higher
Renaming and Reformatting
For the code that cannot be statically eliminated, minifiers ensure it's as small as possible. This is achieved through Renaming and Reformatting. You may also see this called Mangling or Compression.
There are a variety of opportunities for a minifier to apply this technique.
For example, in this JavaScript code:
// functions.js
export function doSomething() {
const randomValue = Math.random();
return randomValue;
}
// ...
// app.js
import { doSomething } from './functions.js'
doSomething();
The minifier can safely rename and reformat this code to produce the following:
function a(){return Math.random()}a()
In this way, the minifier can save precious bytes by:
- Removing any extraneous whitespace characters we inserted in source code for readability
- Rename the function from
doSomething
toa
sincea
is smaller - Remove the extraneous variable assignment to
randomValue
, as it can be safely removed without affecting the code's logic
Note: The import graph is flattened by the bundler / build tool and is not part of minifier's responsibilities.
For CSS Code:
.class-name {
font-size: 16pt;
}
A minifier would produce:
.class-name{font-size:16pt}
Our byte savings would arise from reformatting of the CSS to eliminate extraneous whitespace.
Conclusion
While most production web applications are likely already using minification, we have covered the why and how of these tools.
If you happen not to be using a minifier, you should turn one on ASAP to take advantage of this easy and effective optimization!
Learn about how functions minify better than ES6 classes next!
That's all for this tip! Thanks for reading! Discover more similar tips matching Beginner and JS Optimization.