All articles
Minifiers & Compression
22 min readBy DevUtilX Team

JavaScript Minification: How It Works and Why It Speeds Up Sites

Learn how JavaScript minifiers parse, mangle and compress code, how minification differs from gzip and bundling, and how to use source maps safely.

JavaScript Minification: How It Works and Why It Speeds Up Sites

Open the source of almost any production website and you will find JavaScript that no human could comfortably read: one enormous line, single-letter variable names, no comments, no spacing. That is minification. It is one of the cheapest and most reliable performance improvements available to a web developer, and it happens automatically in most modern build tools. This guide explains what minification is, how it actually works, how much it saves, how it relates to compression and bundling, and how to use it safely.

What is minification?

Minification is the process of removing everything from source code that the computer does not need in order to run it, without changing what the code does. For JavaScript this means:

  • Removing comments, whitespace and line breaks.
  • Shortening local variable and function names.
  • Simplifying expressions and removing unreachable code.
  • Using shorter equivalent syntax.

The goal is a smaller file, so that fewer bytes travel over the network and less text needs to be parsed. Here is a small example. The original:

// Calculate the total price of the items in a cart
function calculateTotal(cartItems) {
  let totalPrice = 0;
  for (const item of cartItems) {
    totalPrice += item.price * item.quantity;
  }
  return totalPrice;
}

After minification, a typical tool produces something like:

function calculateTotal(t){let e=0;for(const r of t)e+=r.price*r.quantity;return e}

The behaviour is identical. The file is a fraction of the size, but it is no longer pleasant to read, which is why minified code is for browsers and source code is for people.

Why minification matters

JavaScript is often the heaviest part of a web page, and it costs more than its raw size suggests. A browser must download the file, decompress it, parse it, compile it and run it. Smaller files help every step of that chain.

  • Faster downloads. Fewer bytes mean less time on slow mobile connections.
  • Faster parsing. Less text for the engine to scan.
  • Better Core Web Vitals. Quicker loading improves metrics that influence user experience and search ranking.
  • Lower bandwidth costs. Savings add up across millions of requests.

The performance guidance at web.dev lists minification and compression among the first things to do when reducing network payloads.

How minifiers work

A modern minifier is not a text search-and-replace tool. Treating JavaScript as plain text would break strings, regular expressions and template literals. Instead, minifiers follow a pipeline similar to a compiler.

1. Parsing

The source is parsed into an abstract syntax tree, or AST, which represents the structure of the program: functions, statements, expressions and literals. Working on the tree rather than the text is what makes safe transformations possible.

2. Whitespace and comment removal

The simplest saving comes for free: comments and formatting are not part of the tree, so when the code is printed back out, they simply disappear. Even this step typically shrinks a file noticeably.

3. Name mangling

Local variables, parameters and function names only matter inside their scope. A minifier renames them to the shortest possible names, usually single letters, taking care that no two names collide. This is called mangling.

Names that must stay the same are not changed. These include global variables, property names on objects (by default), and anything exposed to the outside. Renaming properties is risky, because other code, or JSON data, may refer to them by name.

4. Compression transforms

This is where the tools get clever. Common transformations include:

  • Constant folding: 60 * 60 * 24 becomes 86400.
  • Dead code elimination: removing branches that can never run, such as if (false) { ... }.
  • Inlining: replacing a variable that is used once with its value.
  • Boolean shortening: true becomes !0 and false becomes !1.
  • Combining statements: joining consecutive var declarations, or turning an if into a ternary.
  • Property access simplification: obj["name"] becomes obj.name.

5. Output

Finally the tree is printed back out as compactly as possible, using the fewest characters, and omitting unnecessary semicolons and brackets where the language allows.

Minification, compression and bundling

Three related ideas are often confused.

Concept What it does When it happens
Minification Rewrites the code to be shorter Build time
Compression (gzip, Brotli) Encodes the bytes more efficiently for transfer Server or CDN, per request or precomputed
Bundling Combines many modules into fewer files Build time

They stack. A minified file compresses better than an unminified one, since shortened names and fewer unique tokens produce more repetition for the compressor to exploit. Bundling reduces the number of requests, though with HTTP/2 and HTTP/3 the penalty for many small files is much lower than it used to be. The MDN article on HTTP compression explains how servers and browsers negotiate gzip and Brotli.

As a rough guide, minification often reduces JavaScript by around 30 to 60 percent, depending on how many comments and long names the code contains. Gzip or Brotli then typically cut the result by a further large margin. The actual numbers vary widely, so measure your own files.

Source maps: debugging minified code

Minified code is almost impossible to debug directly. A source map is a file that maps positions in the minified output back to the original source. With a source map, browser developer tools show your original files, with their real names and line numbers, even though the browser runs the minified version.

Source maps are referenced with a comment at the end of the minified file:

//# sourceMappingURL=app.min.js.map

Best practice is to generate source maps in every production build. You can upload them to your error-tracking service, so stack traces from real users point at your original code, and, if you prefer, avoid serving them publicly.

  • Terser: the most widely used JavaScript minifier, supporting modern ECMAScript syntax. It is the default in many bundlers.
  • esbuild: an extremely fast bundler and minifier written in Go. It trades a small amount of compression for speed.
  • SWC: a Rust-based compiler and minifier used by several frameworks.
  • UglifyJS: the older predecessor to Terser, which mainly targets ES5.
  • Google Closure Compiler: offers an "advanced" mode with whole-program optimisation, but requires code written with its constraints in mind.

Most developers never call these tools directly. Bundlers such as Vite, webpack, Rollup, Parcel and Next.js run a minifier automatically in production builds.

Real-world use cases

Production builds. The standard case: your build tool minifies bundles for deployment.

Quick one-off minification. Shrinking a snippet for an embed, a bookmarklet, an inline script or a code sample, without setting up a build.

Measuring the impact. Checking how much smaller a file becomes helps you decide whether a library is worth its weight.

Third-party scripts and widgets. Anything you distribute to other sites should be small and self-contained.

Email and constrained environments. Places with size limits, such as tag managers or embedded devices, benefit from compact code.

Common mistakes

  • Minifying and then editing. Keep the readable source as the master copy. Never edit minified output by hand.
  • Minifying code that is already minified. Libraries often ship a .min.js file. Minifying it again wastes time and gains nothing.
  • Mangling names that are accessed dynamically. Code that reads a function's name or builds property names from strings can break. Use your tool's reserve or exclude options.
  • Forgetting source maps. Without them, production errors are very hard to trace.
  • Relying on minification instead of removing code. Minification shrinks what you wrote. Tree-shaking and removing unused dependencies save far more.
  • Skipping compression. Minification without gzip or Brotli leaves most of the possible saving on the table.
  • Not testing the minified build. Bugs that appear only after minification are rare but real. Run your tests, or at least a smoke test, against the production bundle.

Step-by-step: minify JavaScript with DevUtilX

For a fast one-off job, with no project setup, use the DevUtilX JavaScript Minifier. It runs in your browser.

  1. Open the JavaScript minifier tool.
  2. Paste your JavaScript or TypeScript into the input editor.
  3. Run the minifier.
  4. Check the output and the size reduction.
  5. Copy the minified code to wherever you need it.

Your code is processed locally and is not uploaded. Keep your original, readable version, since the minified result is difficult to edit. If you ever need to read minified code, paste it into the JavaScript Beautifier, which restores indentation and spacing. It cannot bring back the original variable names, but it makes the structure readable again.

Using minification in a project

In a real project, let the build do the work.

// vite.config.js
export default {
  build: {
    minify: "terser",   // or "esbuild" (the default), which is faster
    sourcemap: true,    // generate source maps
  },
};

Next.js, Create React App, Angular and most frameworks minify production builds without any configuration. Check the output size after each build, and consider using a bundle analyser to find the largest dependencies. Then serve the result with Brotli or gzip enabled on your server or CDN.

Best practices

  • Automate it. Minify in the build pipeline, not by hand.
  • Keep source maps for debugging and error tracking.
  • Combine with compression. Enable Brotli or gzip for text assets.
  • Remove unused code first. Tree-shaking and dependency audits beat any minifier.
  • Do not minify in development. Readable code and fast rebuilds matter more there.
  • Test the production bundle. Make sure minified output behaves the same.
  • Cache with content hashes. File names like app.3f9a1c.js allow long cache lifetimes without stale code.
  • Do not put secrets in client-side JavaScript. Minification is not obfuscation or security. Anyone can read or beautify the code.
  • Measure the result. Use browser developer tools, Lighthouse or WebPageTest to confirm that real load times improved.

Minification is not obfuscation

It is a common mistake to think minified code is protected. Minification shortens code for performance, and its output can be reformatted by any beautifier. Obfuscation deliberately makes code hard to understand, using techniques such as string encoding and control-flow flattening, and it usually makes files larger and slower. Neither protects secrets. API keys, passwords and private logic should never be shipped to the browser.

Where the time goes after the download

Bytes on the wire are only the first cost. Once a script arrives, the browser decompresses it, then the JavaScript engine has to turn the text into something it can run. Engines scan the source into tokens, parse the tokens into a syntax tree, generate bytecode, and later optimise hot functions. Most engines also parse lazily: they do a quick pre-parse of functions that are not called immediately, and only fully parse them when they run.

Minification helps most at the start of that chain. The scanner reads every character, including whitespace and comments, so fewer characters means less scanning. Shorter identifiers also shrink the in-memory strings the engine keeps for names.

It is worth being honest about the limits. Minification does not change what your code does at runtime. A loop that runs a million times still runs a million times. If a page is slow because of heavy execution on the main thread, minifying will not fix it. Code splitting, deferring non-critical scripts and removing work are the tools for that problem.

Think of minification as a fixed discount on the transfer and parse cost of every script you ship, and then look for bigger wins elsewhere.

Mangling in depth

Mangling looks simple, but a good implementation does real analysis before it renames a single variable.

Scope analysis

The minifier builds a map of every scope in the program, and records which names are declared where and which inner scopes use them. A name declared in a function can be renamed freely as long as the new name does not shadow a variable the function still needs from an outer scope. That is why the same letter, such as t, can appear in many unrelated functions in one file: their scopes never overlap.

Frequency-based naming

Short names are a limited resource. There are 52 one-letter names made of ASCII letters, plus _ and $, and then the tool must move on to two-letter names. Many minifiers hand the shortest names to the identifiers that appear most often, which is why the most-used variable in a function is usually e or t, and a rarely-used one gets something longer. Some tools also order the alphabet by how well names compress, so that the output repeats characters the compressor can reuse.

What mangling must leave alone

A safe minifier will not rename:

  • Names visible from outside the file, such as top-level variables in a classic script, because other scripts may use them.
  • Anything referenced through eval, with or new Function, because the engine looks names up at runtime. Most tools simply stop mangling in any scope that contains a direct eval.
  • Property names, unless you opt in. Property mangling is aggressive and only safe when you control every access to those properties.
  • Names listed in your reserved or exclude settings.

A short example shows why dynamic access is the danger zone:

function describe(user) {
  const fields = ["name", "email"];
  return fields.map((key) => user[key]).join(", ");
}

The strings "name" and "email" are data. They are also property names. If a tool mangled the properties name and email on user elsewhere in the program, those strings would no longer match, and the function would silently return undefined values. This is why property mangling is off by default.

Compression options worth knowing

Most tools expose a handful of knobs. Terser, for example, has separate compress and mangle sections plus format for output. A realistic configuration might look like this:

// terser.config.json
{
  "compress": {
    "passes": 2,
    "drop_console": false,
    "pure_funcs": ["debugLog"]
  },
  "mangle": {
    "reserved": ["MyPublicApi"]
  },
  "format": {
    "comments": false
  }
}

Here is what each choice means:

  • passes runs the compress step more than once. A second pass can find savings that the first pass exposed, at the cost of build time.
  • drop_console removes console.* calls. Use it deliberately. It is convenient for production, but it also removes logging you may want for diagnostics.
  • pure_funcs tells the minifier that a call has no side effects, so if its result is unused, the whole call can be deleted.
  • reserved protects names from mangling.
  • format.comments controls whether any comments survive. Licence banners are the usual exception, and many teams keep comments that begin with /*! for legal reasons.

Check your tool's documentation for the exact option names, since they differ between Terser, esbuild and SWC. Treat the unsafe or aggressive options as opt-in, and run your tests after enabling any of them.

A worked example: measuring what you save

Claims about percentages are easy to make and easy to get wrong, so measure. The snippet below uses Node's built-in zlib module to compare raw, gzip and Brotli sizes for any files you pass in:

// measure.js
const zlib = require("node:zlib");
const fs = require("node:fs");

for (const file of process.argv.slice(2)) {
  const buf = fs.readFileSync(file);
  const gzip = zlib.gzipSync(buf, { level: 9 }).length;
  const brotli = zlib.brotliCompressSync(buf).length;
  console.log(file, "raw:", buf.length, "gzip:", gzip, "brotli:", brotli);
}

Run it as node measure.js app.js app.min.js. We ran it on the calculateTotal example from the top of this guide. The commented original was 218 bytes raw, and the minified version was 83 bytes. After gzip, the original was 153 bytes and the minified version was 95 bytes. With Brotli the numbers were 122 and 68.

Two lessons come out of this tiny test. First, minification still wins after compression, because the minified file is smaller in every column. Second, the minified file got larger under gzip (83 bytes became 95), because gzip adds a header and trailer and has too little repetition to exploit in such a small input. The effect disappears quickly on real bundles, but it is a useful reminder that compression is not free on very small payloads, and that you should always compare the numbers for your own files rather than trusting a rule of thumb.

Source maps in practice

The earlier section explained what a source map is. Here is how to use them well.

Choosing a type

Bundlers usually offer several source map styles. They differ in what is embedded and who can see it:

  • A separate .map file with a sourceMappingURL comment, which is the common production choice. Browsers fetch the map only when developer tools are open.
  • An inline map embedded in the JavaScript as a data URI. This makes the bundle much larger, so it suits development only.
  • A hidden map, generated without the sourceMappingURL comment. You upload it to your error tracker and never serve it. Users cannot find it, but your stack traces still resolve.

What is inside a map

A source map is JSON with a few key fields: the version, the list of original sources, the names of original identifiers, and a mappings string that encodes positions compactly. A map can also include sourcesContent, a copy of the original files. If that field is present, anyone who downloads the map can read your source, so decide on purpose whether to include it and whether to serve the file publicly.

Keeping maps in sync

A map only works for the exact file it was built with. Name the map after the content-hashed bundle, deploy them together, and keep old maps for as long as old bundles can still be running in users' browsers. Otherwise a stack trace from an older release will point at the wrong lines.

Choosing a minifier

The right tool depends on what you value. These questions help narrow the choice:

  • Is build speed your main pain? esbuild and SWC are native-code tools and usually build far faster than JavaScript-based tools. The output is slightly larger in most comparisons.
  • Does every kilobyte matter? Terser's deeper optimisations tend to produce smaller output, and running multiple passes can squeeze out a little more.
  • Do you ship a library? Consider publishing unminified ESM and letting the consumer's bundler minify, so they can tree-shake it. Publish a minified build only if people load it directly from a script tag.
  • Do you need whole-program optimisation? Closure Compiler's advanced mode can do more than the others, but only if your code follows its conventions.

Whatever you choose, treat the minifier as a build dependency like any other. Pin its version, read the changelog when you upgrade, and run your test suite against the production build after each upgrade, since new optimisations occasionally expose latent bugs in application code.

Tree-shaking and side effects

Minifiers shorten code. Tree-shaking decides which code ships at all. For most applications the second matters more.

Tree-shaking relies on ES module syntax, because import and export are static and the bundler can see exactly which exports are used. If you import one function from a library, the bundler can drop the rest, as long as it is sure that dropping them changes nothing. That certainty is the hard part. Consider this module:

// analytics.js
window.tracker = createTracker();   // runs on import

export function track(event) {
  window.tracker.send(event);
}

Importing the file runs a statement that changes global state. The bundler cannot delete the file even if you never call track, since doing so might remove a needed side effect.

Package authors can help by declaring "sideEffects": false in package.json when their modules are safe to remove, or by listing the few files that do have side effects. As a consumer, prefer packages that publish ES modules and mark themselves side-effect free, and be wary of importing a whole utility library for one function. Check your bundle analyser after adding a dependency. A single careless import can outweigh every byte that minification saved.

You can also annotate individual calls with a /*#__PURE__*/ comment so the minifier knows the call can be dropped if its result is unused. Bundlers and minifiers generally recognise this convention, and compilers that generate code often emit it for you.

Choosing language targets

Minification interacts with the syntax level you compile to. If you transpile modern code down to ES5, the output grows: classes become helper functions, async functions become state machines, and spread syntax becomes helper calls. A minifier cannot undo that growth.

Set your target to the oldest browsers you genuinely support. Many projects can ship modern syntax to modern browsers and skip most of the transforms. Check your analytics, define a browserslist query or an explicit target in your tool, and revisit it when your support policy changes. A smaller target gap often saves more bytes than switching minifiers.

Some teams ship two bundles, a modern one loaded with <script type="module"> and a legacy one for the rest. This works, but adds complexity, so only do it if your audience requires it.

Automating checks in CI and before commit

Because minification is a build step, the best protection is a pipeline that makes regressions visible.

Run the production build in CI. Do not rely on the development server. A failure that appears only in the minified build should fail the pull request, not a Friday release.

Run tests against the built output. At least one smoke test, loading the production bundle in a headless browser and checking that the page renders, catches the class of bugs that only minification exposes.

Set a size budget. Most bundlers and CI tools can fail a build when a bundle grows past a threshold. Pick a number slightly above your current size and lower it when you win savings. A budget turns "the bundle crept up" into a review conversation.

Keep minified files out of version control. Commit sources, and let CI build and publish the output. Committing .min.js files creates noisy diffs and merge conflicts. If you must review a change to minified output, run both versions through a beautifier first, or use a diff tool on the formatted text, as described in our guide to comparing files.

Format before you commit. A formatter such as Prettier or a linter keeps the readable source consistent, so the minifier always starts from clean input. Our guide to JavaScript code formatting covers the setup.

Troubleshooting minified builds

When something works in development and breaks in production, work through symptoms like these.

Symptom: ReferenceError or x is not defined only in production.
Likely cause: a global that the minifier renamed or removed, or code that relies on a variable existing in the global scope. Fix: attach intentional globals explicitly to window or globalThis, or add them to the reserved list.

Symptom: a class or function name is wrong, so a registry or logger shows t instead of UserService.
Likely cause: code reads fn.name or constructor.name, and mangling shortened it. Fix: stop relying on those names, pass an explicit string identifier, or use your tool's option to keep class and function names.

Symptom: a framework that uses dependency injection by parameter name fails.
Likely cause: older injection styles inspected parameter names as text, and mangling replaced them. Fix: use the explicit array or annotation form the framework provides, or reserve those names.

Symptom: an object property is undefined after a property-mangling option was enabled.
Likely cause: some code accesses the property through a string, or the data came from JSON, whose keys were not renamed. Fix: turn property mangling off, or restrict it to a clearly private prefix such as _internal.

Symptom: the minifier crashes with a syntax error on a file you can run.
Likely cause: the file uses syntax newer than the parser's configured ECMAScript level, or it is TypeScript or JSX that was not compiled first. Fix: compile TypeScript and JSX before minifying, and update the tool so it understands the syntax.

Symptom: source map lines are off by a few lines or point at the wrong file.
Likely cause: another tool changed the file after the map was generated, or the wrong map was deployed. Fix: generate the map in the last step that touches the code, and keep each map paired with its bundle.

Symptom: behaviour differs because a console.log or debugger line disappeared.
Likely cause: a drop option removed it. Fix: that is usually intended. If you need the logs, remove the option or use a logger function and list it in pure_funcs only when you really want it deleted.

Symptom: the bundle did not shrink after enabling minification.
Likely cause: the minifier is not running because of a mode flag, or the bundle is dominated by already-minified dependencies and data. Fix: confirm the production mode is on, then use a bundle analyser to see what the bytes actually are.

When you cannot find the cause, bisect. Disable one minifier feature at a time, starting with the most aggressive, until the bug disappears. The last thing you switched off is your culprit, and the bug report for the tool, or a fix in your own code, follows from that.

Security and privacy considerations

Minified code is public code. Alongside the earlier points about secrets, keep these habits in mind.

  • Never ship sourcesContent or public maps for code you consider private. If your source is confidential, keep maps behind authentication or upload them only to your error tracker.
  • Use Subresource Integrity for third-party scripts. The integrity attribute on a script tag lets the browser verify that a file has not been altered. If you serve your own minified files from a CDN, generating the hash at build time is straightforward. See the MDN guide to Subresource Integrity.
  • Be careful with inline scripts and CSP. A strict Content Security Policy can block inline scripts, so a minified snippet you paste into a page may need a nonce or hash. Prefer external files where you can.
  • Review dependency updates. A minified file in node_modules is hard to audit. Pin versions, use lockfiles, and prefer packages that ship readable sources alongside the minified build.

Migrating an old project to a modern pipeline

Plenty of sites still concatenate scripts by hand or run an old minifier from a script. Moving to a bundler-driven build is a gradual job, and you can do it in small, safe steps.

  1. Record a baseline. Note the current transfer size and load timing for your key pages, so you can prove the migration helped.
  2. Move to modules gradually. Convert one file at a time to import and export. Tree-shaking only works on the parts that use module syntax.
  3. Replace globals with imports. Scripts that communicate through window properties are the main source of mangling bugs. Each global you turn into an import removes one risk.
  4. Switch the minifier last. Once the code is modular, change the tool and compare output sizes. If a regression appears, you know the minifier is the only variable that changed.
  5. Add the safety net. Introduce the production smoke test and the size budget before the team starts relying on the new pipeline.

Resist the urge to do everything in one pull request. A migration that mixes module conversion, a new bundler and a new minifier makes every failure hard to attribute.

A team checklist

Use this as a review list when you set up or audit a project:

  1. Production builds minify by default, and development builds do not.
  2. Source maps are generated, paired with their bundles and either hidden or access-controlled.
  3. Text assets are served with Brotli or gzip.
  4. A size budget fails the build when bundles grow past an agreed number.
  5. Dependencies are imported in a tree-shakeable way, and a bundle analyser is checked when they change.
  6. The language target matches the browsers you actually support.
  7. The minified build is tested, not just the development build.
  8. No secrets, tokens or private endpoints appear in client code.
  9. The minifier version is pinned and upgrades go through the same tests as any other dependency.

FAQ

Does minification change how my code behaves?
It should not. Minifiers are designed to preserve behaviour. Problems are rare and typically involve code that depends on function names, eval, or dynamically built property names.

How much smaller will my file be?
It varies. Code with many comments and long names shrinks the most. Savings of 30 to 60 percent before compression are common, and compression then reduces the transfer size further.

Is minification still useful with HTTP/2 and Brotli?
Yes. Compression reduces transfer size, but the browser still has to parse the decompressed text, and minified code is smaller to store and parse. The two techniques complement each other.

What is the difference between Terser and esbuild?
Terser usually produces slightly smaller output but is slower. esbuild is dramatically faster with slightly larger output. For many projects the difference is small, so choose based on build speed.

Can I reverse minification?
Partly. A beautifier restores formatting, but the original local variable names and comments are gone. A source map is the only way to recover the original source.

Should I minify JSON, CSS and HTML too?
Yes, where it makes sense. The same principle applies, and we cover CSS and HTML in other guides.

Is it safe to paste code into an online minifier?
Only if it runs in your browser. DevUtilX processes your input locally, but do not paste secrets or credentials into any tool.

Does minification make code run faster?
It makes the code arrive and parse faster. Once running, the engine executes the same logic, so heavy computation takes about the same time. Improving runtime speed means changing the algorithm or the amount of work.

Should I minify code that runs on the server with Node.js?
Usually not. Server code is read from local disk, so size matters little, and readable stack traces help debugging. Exceptions include serverless platforms with strict package size limits, where bundling and minifying can reduce cold-start work.

Why is my minified file bigger than expected?
Check for large dependencies, embedded data such as images encoded as strings, and syntax transpiled down to old targets. A bundle analyser shows where the bytes come from.

Can minification introduce security vulnerabilities?
Minifiers do not add vulnerabilities by design, but a bug in a tool or an aggressive option could change behaviour. That is a good reason to test the production build and keep the tool updated.

Do I need to minify inline scripts in my HTML?
For a small inline snippet, a minifier helps a little, and every byte of inline script sits on the critical path of the page. For larger scripts, move them into external files that the browser can cache.

What is the difference between minified and uglified code?
In everyday speech the terms overlap, since UglifyJS was a popular minifier. Strictly, minification preserves behaviour while shrinking, and obfuscation aims to hinder understanding. See the section on obfuscation above.

Can I minify TypeScript directly?
A minifier works on JavaScript, so TypeScript must first be compiled, which removes the type annotations. Many bundlers do both steps for you, but the two are separate transformations.

Conclusion

Minification is a simple idea with a real payoff: the same behaviour in fewer bytes. Let your build tool do it automatically, generate source maps, pair it with Brotli or gzip, and remove unused code before you reach for clever tricks. For a quick one-off job, the JavaScript Minifier gets you a compact result in seconds. To keep going, read our guide on JavaScript code formatting for the readable side of the same coin, and compare versions with our guide to the code diff tool.

Further reading

Try the tools

Further reading

Related articles