Skip to content

Commit

Permalink
Merge pull request #9666 from dimagi/uglify-compressor
Browse files Browse the repository at this point in the history
Use jsUglify and have source maps!
  • Loading branch information
dannyroberts committed Jan 13, 2016
2 parents a057206 + cb6189f commit f3dea51
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 2 deletions.
1 change: 1 addition & 0 deletions .travis/matrix-installs.sh
Expand Up @@ -20,6 +20,7 @@ else
fi

if [ "${BOWER:-no}" = "yes" ]; then
npm install -g uglify-js
npm install -g bower
bower install
fi
1 change: 1 addition & 0 deletions corehq/apps/style/tests/test_compress_command.py
Expand Up @@ -69,6 +69,7 @@ def _is_b3_base_template(self, template):

@attr("slow")
def test_compress_offline(self):
call_command('collectstatic', verbosity=0, interactive=False)
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
call_command('compress', force=True)

Expand Down
99 changes: 99 additions & 0 deletions corehq/apps/style/uglify.py
@@ -0,0 +1,99 @@
import os
import subprocess

from compressor.exceptions import FilterError
from compressor.filters import CompilerFilter
from compressor.js import JsCompressor
from compressor.utils.stringformat import FormattableString as fstr
from django.conf import settings
from django.utils.safestring import mark_safe


# For use with node.js' uglifyjs minifier
# Code taken from: https://roverdotcom.github.io/blog/2014/05/28/javascript-error-reporting-with-source-maps-in-django/
class UglifySourcemapFilter(CompilerFilter):
command = (
"uglifyjs {infiles} -o {outfile} --source-map {mapfile}"
" --source-map-url {mapurl} --source-map-root {maproot} -c -m")

def input(self, **kwargs):
return self.content

def output(self, **kwargs):
options = dict(self.options)
options['outfile'] = kwargs['outfile']

infiles = []
for infile in kwargs['content_meta']:
# type, full_filename, relative_filename
infiles.append(infile[2])

options['infiles'] = ' '.join(f for f in infiles)

options['mapfile'] = kwargs['outfile'].replace('.js', '.map.js')

options['mapurl'] = '{}{}'.format(
settings.STATIC_URL, options['mapfile']
)

options['maproot'] = settings.STATIC_URL

self.cwd = kwargs['root_location']

try:
command = fstr(self.command).format(**options)

proc = subprocess.Popen(
command, shell=True, cwd=self.cwd, stdout=self.stdout,
stdin=self.stdin, stderr=self.stderr)
err = proc.communicate()
except (IOError, OSError), e:
raise FilterError('Unable to apply %s (%r): %s' %
(self.__class__.__name__, self.command, e))
else:
# If the process doesn't return a 0 success code, throw an error
if proc.wait() != 0:
if not err:
err = ('Unable to apply %s (%s)' %
(self.__class__.__name__, self.command))
raise FilterError(err)
if self.verbose:
self.logger.debug(err)


class JsUglifySourcemapCompressor(JsCompressor):

def output(self, mode='file', forced=False):
content = self.filter_input(forced)
if not content:
return ''

concatenated_content = '\n'.join(
c.encode(self.charset) for c in content)

if settings.COMPRESS_ENABLED or forced:
js_compress_dir = os.path.join(
settings.STATIC_ROOT, self.output_dir, self.output_prefix
)
if not os.path.exists(js_compress_dir):
os.makedirs(js_compress_dir, 0775)
filepath = self.get_filepath(concatenated_content, basename=None)

# UglifySourcemapFilter writes the file directly, as it needs to
# output the sourcemap as well
UglifySourcemapFilter(content).output(
outfile=filepath,
content_meta=self.split_content,
root_location=self.storage.base_location)

return self.output_file(mode, filepath)
else:
return concatenated_content

def output_file(self, mode, new_filepath):
"""
The output method that saves the content to a file and renders
the appropriate template with the file's URL.
"""
url = mark_safe(self.storage.url(new_filepath))
return self.render_output(mode, {"url": url})
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -6,8 +6,9 @@
"dependencies": {
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"grunt-mocha": "^0.4.13",
"grunt-contrib-watch": "^0.6.1",
"mocha": "^2.3.3"
"grunt-mocha": "^0.4.13",
"mocha": "^2.3.3",
"uglifyjs": "^2.4.10"
}
}
1 change: 1 addition & 0 deletions settings.py
Expand Up @@ -1614,6 +1614,7 @@
}

COMPRESS_CSS_HASHING_METHOD = 'content'
COMPRESS_JS_COMPRESSOR = 'corehq.apps.style.uglify.JsUglifySourcemapCompressor'


if 'locmem' not in CACHES:
Expand Down

0 comments on commit f3dea51

Please sign in to comment.