Commit 2af0561d by Simon Lydell

Safely concatenate JavaScript

Most JavaScript packages wrap their code in IIFEs, which is good.

Pipeline used to concatenate JS only with a newline. That can break those IIFES
though:

    (function() {
      // package A
    }()) // No semicolon! Most people put one here, but unfortunately not all!
    (function() {
      // package B
    }());

The above is equivalent to:

    (function() {
      // package A
    }())(function() {
      // package B
    }());

Suddenly we have a function call!

With this commit, JS is concatenated with a newline followed by a semicolon,
which fixes the above issue:

    (function() {
      // package A
    }()) // No semicolon! Most people put one here, but unfortunately not all!
    ;(function() {
      // package B
    }());

There is no need to worry about superfluos semicolons, such as:

    (function() {
      // package A
    }());
    ;;(function() {
      // package B
    }());

That is still valid JavaScript and the extra semicolons will be removed by the
minifier.
parent a12407e5
......@@ -142,7 +142,11 @@ class Compressor(object):
def concatenate(self, paths):
"""Concatenate together a list of files"""
return "\n".join([self.read_text(path) for path in paths])
# Note how a semicolon is added between the two files to make sure that
# their behavior is not changed. '(expression1)\n(expression2)' calls
# `expression1` with `expression2` as an argument! Superfluos semicolons
# are valid in JavaScript and will be removed by the minifier.
return "\n;".join([self.read_text(path) for path in paths])
def construct_asset_path(self, asset_path, css_path, output_filename, variant=None):
"""Return a rewritten asset URL for a stylesheet"""
......
function concat() {
console.log(arguments);
}
(function() {
window.concat = function() {
console.log(arguments);
}
}()) // No semicolon
function cat() {
console.log("hello world");
}
(function() {
window.cat = function() {
console.log("hello world");
}
}());
......@@ -46,7 +46,7 @@ class CompressorTest(TestCase):
_('pipeline/js/first.js'),
_('pipeline/js/second.js')
])
self.assertEqual("""function concat() {\n console.log(arguments);\n}\n\nfunction cat() {\n console.log("hello world");\n}\n""", js)
self.assertEqual("""(function() {\n window.concat = function() {\n console.log(arguments);\n }\n}()) // No semicolon\n\n;(function() {\n window.cat = function() {\n console.log("hello world");\n }\n}());\n""", js)
@patch.object(base64, 'b64encode')
def test_encoded_content(self, mock):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment