diff --git a/.gitignore b/.gitignore index ab9811f..7aa067a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__ /webmake.egg-info /.project /.pydevproject +/.idea /tests/test_project/package-lock.json /webmake/package-lock.json /build diff --git a/setup.py b/setup.py index 0588a9e..9ff0b59 100644 --- a/setup.py +++ b/setup.py @@ -143,6 +143,7 @@ def run(self): # https://packaging.python.org/en/latest/requirements.html install_requires=[ 'watchdog>=0.8', + 'six', ], # List additional groups of dependencies here (e.g. development diff --git a/tests/test_project/webmakefile.py b/tests/test_project/webmakefile.py index 9eb4b42..cf886b6 100644 --- a/tests/test_project/webmakefile.py +++ b/tests/test_project/webmakefile.py @@ -51,6 +51,9 @@ def custom_compiler(input_files, output_file, release): # Minify standalone JS. Concatenates in debug mode, minifies in release mode. api.minify_js(['www-dev/js/standalone.js'], 'www/js/standalone.js'), + # Minify AngularJS 1.x. Concatenates in debug mode, minifies and annotates Angular dependencies in release mode. + api.minify_js(['www-dev/angular-1.x/module.js'], 'www/angular-1.x/module.js', annotate_angular=True), + # Concatenate standalone files with no further processing. api.concatenate(['www-dev/js/standalone.js'] * 2, 'www/js/standalone-x2.js'), diff --git a/tests/test_project/www-dev/angular-1.x/module.js b/tests/test_project/www-dev/angular-1.x/module.js new file mode 100644 index 0000000..5705330 --- /dev/null +++ b/tests/test_project/www-dev/angular-1.x/module.js @@ -0,0 +1,9 @@ +angular.module("WebmakeTest", []) + .factory("TestFactory", function () { + this.foo = function () { + alert("foo") + } + }) + .controller("TestController", function (TestFactory) { + TestFactory.foo() + }); \ No newline at end of file diff --git a/webmake/api.py b/webmake/api.py index 09ebdaf..363ec1c 100644 --- a/webmake/api.py +++ b/webmake/api.py @@ -57,7 +57,7 @@ def copy_files(src_dir, dst_dir, filespec='*', recursive=False): } -def minify_js(input_files, output_file): +def minify_js(input_files, output_file, annotate_angular=False): """ Minifies the input javascript files to the output file. @@ -66,6 +66,7 @@ def minify_js(input_files, output_file): In debug mode this function just concatenates the files without minifying. """ + from functools import partial from .modules import minify, utils if not isinstance(input_files, (list, tuple)): @@ -73,7 +74,7 @@ def minify_js(input_files, output_file): return { 'dependencies_fn': utils.no_dependencies, - 'compiler_fn': minify.minify_js, + 'compiler_fn': partial(minify.minify_js, annotate_angular=annotate_angular), 'input': input_files, 'output': output_file, 'kwargs': {}, diff --git a/webmake/django/middleware.py b/webmake/django/middleware.py index 68aabef..84056d3 100644 --- a/webmake/django/middleware.py +++ b/webmake/django/middleware.py @@ -43,6 +43,10 @@ def pre_process(self, deployment_settings, *args, **kwargs): BINFILE = POSSIBLE_BINFILES[0] if POSSIBLE_BINFILES else WEBMAKE_BIN +class WebmakeRuntimeWarning(RuntimeWarning): + pass + + class WebmakeCompilerMiddleware: def __init__(self, get_response=None): self.get_response = get_response @@ -53,7 +57,7 @@ def __call__(self, request): def process_request(self, request): if not settings.DEBUG: - warnings.warn('WebmakeCompilerMiddleware should not be used in production!', RuntimeWarning) + warnings.warn('WebmakeCompilerMiddleware should not be used in production!', WebmakeRuntimeWarning) cmd = ' '.join([BINFILE, '-m', WEBMAKEFILE]) env = os.environ.copy() diff --git a/webmake/modules/concat.py b/webmake/modules/concat.py index 5938932..ed91217 100644 --- a/webmake/modules/concat.py +++ b/webmake/modules/concat.py @@ -1,6 +1,9 @@ import os +import six from . import utils +FILE_HANDLE_KWARGS = {} if six.PY2 else dict(encoding='utf-8') + def _trimpath(path): comps = [] @@ -24,9 +27,9 @@ def concatenate_input_files(input_files, output_file, release=False): try: utils.logv('>>> concat {} > {}'.format(' '.join(input_files), output_file)) - with open(output_file, 'w') as output: + with open(output_file, 'w', **FILE_HANDLE_KWARGS) as output: for input_file in input_files: - with open(input_file, 'r') as input: + with open(input_file, 'r', **FILE_HANDLE_KWARGS) as input: output.write(input.read()) if not release: diff --git a/webmake/modules/copyfiles.py b/webmake/modules/copyfiles.py index dbdd50e..5b33112 100644 --- a/webmake/modules/copyfiles.py +++ b/webmake/modules/copyfiles.py @@ -1,5 +1,4 @@ import os -import re import shutil from fnmatch import fnmatch from . import utils diff --git a/webmake/modules/less.py b/webmake/modules/less.py index ce52688..4da8b57 100644 --- a/webmake/modules/less.py +++ b/webmake/modules/less.py @@ -8,7 +8,7 @@ def _read_less_imports(file): deps = [] - with open(file) as f: + with open(file, encoding='utf-8') as f: less = f.read() imports = LESS_IMPORT_RE.findall(less) less_dir = os.path.dirname(file) diff --git a/webmake/modules/minify.py b/webmake/modules/minify.py index fcc1299..e39dd47 100644 --- a/webmake/modules/minify.py +++ b/webmake/modules/minify.py @@ -2,20 +2,32 @@ from . import utils, concat -def minify_js(input_files, output_file, release=False): +def minify_js(input_files, output_file, release=False, annotate_angular=False): assert isinstance(input_files, (list, tuple)) if not release: concat.concatenate_input_files(input_files, output_file, release=release) return + if annotate_angular: + # Rather than annotate several individual files (and having to creating temp files as well), it's + # easier to just concatenate the input_files right now, and then perform the annotation upon that + # one file. We must then update the `input_files` value accordingly, so that it gets passed into + # uglify correctly. + concat.concatenate_input_files(input_files, output_file, release=release) + input_files = [output_file] + try: + annotate_angular_injections(output_file, output_file) + except: + utils.ensure_deleted(output_file) + raise + if output_file: utils.ensure_path_exists(os.path.dirname(output_file)) cmdline = [ utils.get_node_bin_path('uglify-es', 'bin', 'uglifyjs'), '--compress', - '--mangle', '-o', output_file, '--', @@ -28,6 +40,20 @@ def minify_js(input_files, output_file, release=False): utils.ensure_deleted(output_file) raise +def annotate_angular_injections(input_file, output_file): + cmdline = [ + os.path.join(utils.get_node_bin_path('ng-annotate'), 'ng-annotate.js'), + '--add', + '-o', + output_file, + ] + cmdline.extend([input_file]) + + try: + utils.run_command(cmdline, 'Failed to annotate Angular injections to "{}"'.format(output_file), with_node=True) + except Exception as e: + utils.ensure_deleted(output_file) + raise def minify_css(input_files, output_file, release=False): assert isinstance(input_files, (list, tuple)) diff --git a/webmake/package.json b/webmake/package.json index 2ffae28..908ad21 100644 --- a/webmake/package.json +++ b/webmake/package.json @@ -10,6 +10,7 @@ "browserify": "^9.0.8", "cssmin": "^0.4.3", "less": "^2.7.3", + "ng-annotate": "1.x", "node-sass": "^4.12.0", "uglify-es": "^3.3.9" }