Douglas Crockford

Blog

Books

Videos

2023 Appearances

JavaScript

Misty

JSLint

JSON

Github

Electric Communities

Mastodon/Layer8

Flickr Photo Album

ResearchGate

LinkedIn

Pronouns: pe/per

About

JSMin

JSMin [2001] is a minification tool that removes comments and unnecessary whitespace from JavaScript files. It typically reduces filesize by half, resulting in faster downloads. It also encourages a more expressive programming style because it eliminates the download cost of clean, literate self-documentation.

What JSMin Does

JSMin is a filter that omits or modifies some characters. This does not change the behavior of the program that it is minifying. The result may be harder to debug. It will definitely be harder to read.

JSMin first replaces carriage returns ('\r') with linefeeds ('\n'). It replaces all other control characters (including tab) with spaces. It replaces comments in the // form with linefeeds. It replaces comments in the /* */ form with spaces. All runs of spaces are replaced with a single space. All runs of linefeeds are replaced with a single linefeed.

It omits spaces except when a space is preceded and followed by a non-ASCII character or by an ASCII letter or digit, or by one of these characters:

\ $ _

It is more conservative in omitting linefeeds, because JavaScript sometimes treats linefeeds as semicolons. A linefeed is not omitted if it precedes a non-ASCII character or an ASCII letter or digit or one of these characters:

\ $ _ { [ ( + -

and if it follows a non-ASCII character or an ASCII letter or digit or one of these characters:

\ $ _ } ] ) + - " '

No other characters are omitted or modified.

JSMin knows to not modify quoted strings and regular expression literals.

JSMin does not obfuscate, but it does uglify.

Before:

function deconstruct(number) {

// This function deconstructs a number, reducing it to its components:
// a sign, an integer coefficient, and an exponent, such that

//            number = sign * coefficient * (2 ** exponent)

    let sign = 1;
    let coefficient = number;
    let exponent = 0;

// Remove the sign from the coefficient.

    if (coefficient < 0) {
        coefficient = -coefficient;
        sign = -1;
    }

    if (Number.isFinite(number) && number !== 0) {

// Reduce the coefficient: We can obtain the exponent by dividing the number by
// two until it goes to zero. We add the number of divisions to -1128, which is
// the exponent of 'Number.MIN_VALUE' minus the number of bits in the
// significand minus the bonus bit.

        exponent = -1128;
        let reduction = coefficient;
        while (reduction !== 0) {

// This loop is guaranteed to reach zero. Each division will decrement the
// exponent of the reduction. When the exponent is so small that it can not
// be decremented, then the internal subnormal significand will be shifted
// right instead. Ultimately, all of the bits will be shifted out.

            exponent += 1;
            reduction /= 2;
        }

// Reduce the exponent: When the exponent is zero, the number can be viewed
// as an integer. If the exponent is not zero, then adjust to correct the
// coefficient.

        reduction = exponent;
        while (reduction > 0) {
            coefficient /= 2;
            reduction -= 1;
        }
        while (reduction < 0) {
            coefficient *= 2;
            reduction += 1;
        }
    }

// Return an object containing the three components and the original number.

    return {
        sign,
        coefficient,
        exponent,
        number
    };
}

After:

function deconstruct(number){let sign=1;let coefficient=number;let exponent=0;if(coefficient<0){coefficient=-coefficient;sign=-1;}
if(Number.isFinite(number)&&number!==0){exponent=-1128;let reduction=coefficient;while(reduction!==0){exponent+=1;reduction/=2;}
reduction=exponent;while(reduction>0){coefficient/=2;reduction-=1;}
while(reduction<0){coefficient*=2;reduction+=1;}}
return{sign,coefficient,exponent,number};}

Character Set

JSMin requires, but does not verify, that the character set encoding of the input program is either ASCII or UTF-8. It might not work correctly with other encodings.

Caution

Be sure to retain your original source file. JSMin is a one-way trip: Once done, it cannot be undone.

Do not put raw control characters inside a quoted string. That is an extremely bad practice. Use \u00hh notation instead. JSMin will replace control characters with spaces or linefeeds.

Use parens with confusing sequences of + or -. For example, minification changes

a + ++b

into

a+++b

which is interpreted as

a++ + b

which is wrong. You can avoid this by using parens:

a + (++b)

If you are smart, you avoid ++ entirely.

JSLint checks for all of these problems. You should be using JSLint.

Command Line Options

Optional parameters will be listed at the beginning of the output as comments. This is a convenient way of replacing copyright messages and other documentation.

Example:

jsmin <jslint.js >min/jslint.js "©2002 Douglas Crockford"

Errors

JSMin can produce four error messages to stderr:

Error: JSMIN unterminated comment.

Error: JSMIN unterminated string literal.

Error: JSMIN unterminated Regular Expression literal.

Error: JSMIN unterminated set in Regular Expression literal.

It preserves all other errors that may be present in your source program.

Minification v Obfuscation

JavaScript is a load-and-go language. Programs are delivered to the execution site as text (not as executable or semi-compiled class files) where it is compiled and executed. JavaScript works well with the Web, which is a text delivery system, because it is delivered as text.

There are two downsides of textual delivery of programs. The first is code size. The source can contain material (such as whitespace and comments) which aids in the human interpretability of the program, but which is not needed for its execution. Transmitting superfluous material can significantly delay the download process, which keeps people waiting. If we could first strip out the whitespace and comments, our pages would load faster.

The second downside is code privacy. There might be a concern that someone could read the program and learn our techniques, and worse, compromise our security by learning the secrets that are embedded in the code.

There are two classes of tools which deal with these problems: minifiers and obfuscators.

A minifier removes the comments and unnecessary whitespace from a program. Depending on how the program is written, this can reduce the size by about half. An obfuscator also minifies, but it will also make modifications to the program, changing the names of variables, functions, and members, making the program much harder to understand, and further reducing its size in the bargain. Some obfuscators are quite aggressive in their transformations. Some require special annotations in the source program to indicate what changes might or might not be safe.

Every transformation carries the risk of introducing a bug. Even if the obfuscator didn't cause the bug, the fact that it might have is a distraction which will slow down the debugging process. The modifications to the program also add significantly to the difficulty of debugging.

After minifying, you should GZIP. GZIP can further reduce the size of the program. GZIP is so effective that the difference in the efficiency between minification and obfuscation becomes insignificant. So I prefer minification with GZIP because I don't have time for programming tools that can inject bugs into good programs.

The following table shows the results of using JSMin and gzip on a 78K source file. The result of using the two techniques together produced a result that is only 14% the size of the original source file.

  Full Source Minified
Uncompressed 78151 38051
Compressed with gzip 15207 10799

Then finally, there is that question of code privacy. This is a lost cause. There is no transformation that will keep a determined hacker from understanding your program. This turns out to be true for all programs in all languages, it is just more obviously true with JavaScript because it is delivered in source form. The privacy benefit provided by obfuscation is an illusion. Slowing the attackers down is not an effective strategy. If you don't want people to see your programs, unplug your server.

JSON Comments

JSON does not allow comments. That is not a problem for JSON's original purpose, but for some applications, comments are desirable. JSMin can help. JSMin can minify JSON as effectively as it minifies JavaScript. Keep comments in the human readable files, and pipe them through JSMin just before handing them to a JSON parser.

See