diff --git a/gluon/globals.py b/gluon/globals.py index c47c596c..f9f5013b 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -473,45 +473,67 @@ class Response(Storage): response.cache_includes = (cache_method, time_expire). Example: (cache.disk, 60) # caches to disk for 1 minute. """ + app = current.request.application + + # We start by building a files list in which adjacent files internal to + # the application are placed in a list inside the files list. + # + # We will only minify and concat adjacent internal files as there's + # no way to know if changing the order with which the files are apppended + # will break things since the order matters in both CSS and JS and + # internal files may be interleaved with external ones. files = [] - ext_files = [] - has_js = has_css = False + # For the adjacent list we're going to use storage List to both distinguish + # from the regular list and so we can add attributes + internal = List() + internal.has_js = False + internal.has_css = False + done = set() # to remove duplicates for item in self.files: - if isinstance(item, (list, tuple)): - ext_files.append(item) + if not isinstance(item, list): + if item in done: + continue + done.add(item) + if isinstance(item, (list, tuple)) or not item.startswith('/' + app): # also consider items in other web2py applications to be external + if internal: + files.append(internal) + internal = List() + internal.has_js = False + internal.has_css = False + files.append(item) continue if extensions and not item.rpartition('.')[2] in extensions: continue - if item in files: - continue + internal.append(item) if item.endswith('.js'): - has_js = True + internal.has_js = True if item.endswith('.css'): - has_css = True - files.append(item) + internal.has_css = True + if internal: + files.append(internal) - if have_minify and ((self.optimize_css and has_css) or (self.optimize_js and has_js)): - # cache for 5 minutes by default - key = hashlib_md5(repr(files)).hexdigest() - cache = self.cache_includes or (current.cache.ram, 60 * 5) - - def call_minify(files=files): - return minify.minify(files, - URL('static', 'temp'), - current.request.folder, - self.optimize_css, - self.optimize_js) - if cache: - cache_model, time_expire = cache - files = cache_model('response.files.minified/' + key, - call_minify, - time_expire) - else: - files = call_minify() - - files.extend(ext_files) - s = [] - for item in files: + # We're done we can now minify + if have_minify: + for i, f in enumerate(files): + if isinstance(f, List) and ((self.optimize_css and f.has_css) or (self.optimize_js and f.has_js)): + # cache for 5 minutes by default + key = hashlib_md5(repr(f)).hexdigest() + cache = self.cache_includes or (current.cache.ram, 60 * 5) + def call_minify(files=f): + return List(minify.minify(files, + URL('static', 'temp'), + current.request.folder, + self.optimize_css, + self.optimize_js)) + if cache: + cache_model, time_expire = cache + files[i] = cache_model('response.files.minified/' + key, + call_minify, + time_expire) + else: + files[i] = call_minify() + + def static_map(s, item): if isinstance(item, str): f = item.lower().split('?')[0] ext = f.rpartition('.')[2] @@ -531,6 +553,13 @@ class Response(Storage): if tmpl: s.append(tmpl % item[1]) + s = [] + for item in files: + if isinstance(item, List): + for f in item: + static_map(s, f) + else: + static_map(s, item) self.write(''.join(s), escape=False) def stream(self,