Filter source maps from bundled assets

At least for now. Might be re-evaluated in the future. URL rewrite
filter for such a case already in place.
This commit is contained in:
Gina Häußge 2017-05-19 12:28:20 +02:00
parent 59d78ba893
commit 832c27ed18
3 changed files with 153 additions and 37 deletions

View file

@ -1115,75 +1115,61 @@ class Server(object):
less_core = list(dynamic_core_assets["less"]) + list(dynamic_plugin_assets["bundled"]["less"])
less_plugins = list(dynamic_plugin_assets["external"]["less"])
from webassets.filter import register_filter, Filter
from webassets.filter.cssrewrite.base import PatternRewriter
import re
class LessImportRewrite(PatternRewriter):
name = "less_importrewrite"
patterns = {
"import_rewrite": re.compile("(@import(\s+\(.*\))?\s+)\"(.*)\";")
}
def import_rewrite(self, m):
import_with_options = m.group(1)
import_url = m.group(3)
if not import_url.startswith("http:") and not import_url.startswith("https:") and not import_url.startswith("/"):
import_url = "../less/" + import_url
return "{import_with_options}\"{import_url}\";".format(**locals())
class JsDelimiterBundler(Filter):
name = "js_delimiter_bundler"
options = {}
def input(self, _in, out, **kwargs):
out.write(_in.read())
out.write("\n;\n")
# a couple of custom filters
from octoprint.server.util.webassets import LessImportRewrite, JsDelimiterBundler, SourceMapRewrite, SourceMapRemove
from webassets.filter import register_filter
register_filter(LessImportRewrite)
register_filter(SourceMapRewrite)
register_filter(SourceMapRemove)
register_filter(JsDelimiterBundler)
# JS
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js", filters="js_delimiter_bundler")
js_filters = ["sourcemap_remove", "js_delimiter_bundler"]
js_client_bundle = Bundle(*js_client, output="webassets/packed_client.js", filters="js_delimiter_bundler")
js_core_bundle = Bundle(*js_core, output="webassets/packed_core.js", filters="js_delimiter_bundler")
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js", filters=",".join(js_filters))
js_client_bundle = Bundle(*js_client, output="webassets/packed_client.js", filters=",".join(js_filters))
js_core_bundle = Bundle(*js_core, output="webassets/packed_core.js", filters=",".join(js_filters))
if len(js_plugins) == 0:
js_plugins_bundle = Bundle(*[])
else:
js_plugins_bundle = Bundle(*js_plugins, output="webassets/packed_plugins.js", filters="js_delimiter_bundler")
js_plugins_bundle = Bundle(*js_plugins, output="webassets/packed_plugins.js", filters=",".join(js_filters))
js_app_bundle = Bundle(js_plugins_bundle, js_core_bundle, output="webassets/packed_app.js", filters="js_delimiter_bundler")
js_app_bundle = Bundle(js_plugins_bundle, js_core_bundle, output="webassets/packed_app.js", filters=",".join(js_filters))
# CSS
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css", filters="cssrewrite")
css_filters = ["cssrewrite"]
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css", filters=",".join(css_filters))
if len(css_core) == 0:
css_core_bundle = Bundle(*[])
else:
css_core_bundle = Bundle(*css_core, output="webassets/packed_core.css", filters="cssrewrite")
css_core_bundle = Bundle(*css_core, output="webassets/packed_core.css", filters=",".join(css_filters))
if len(css_plugins) == 0:
css_plugins_bundle = Bundle(*[])
else:
css_plugins_bundle = Bundle(*css_plugins, output="webassets/packed_plugins.css", filters="cssrewrite")
css_plugins_bundle = Bundle(*css_plugins, output="webassets/packed_plugins.css", filters=",".join(css_filters))
css_app_bundle = Bundle(css_core, css_plugins, output="webassets/packed_app.css", filters="cssrewrite")
css_app_bundle = Bundle(css_core, css_plugins, output="webassets/packed_app.css", filters=",".join(css_filters))
# LESS
less_filters = ["cssrewrite", "less_importrewrite"]
if len(less_core) == 0:
less_core_bundle = Bundle(*[])
else:
less_core_bundle = Bundle(*less_core, output="webassets/packed_core.less", filters="cssrewrite, less_importrewrite")
less_core_bundle = Bundle(*less_core, output="webassets/packed_core.less", filters=",".join(less_filters))
if len(less_plugins) == 0:
less_plugins_bundle = Bundle(*[])
else:
less_plugins_bundle = Bundle(*less_plugins, output="webassets/packed_plugins.less", filters="cssrewrite, less_importrewrite")
less_plugins_bundle = Bundle(*less_plugins, output="webassets/packed_plugins.less", filters=",".join(less_filters))
less_app_bundle = Bundle(less_core, less_plugins, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite")
less_app_bundle = Bundle(less_core, less_plugins, output="webassets/packed_app.less", filters=",".join(less_filters))
# asset registration
assets.register("js_libs", js_libs_bundle)

View file

@ -0,0 +1,100 @@
# coding=utf-8
from __future__ import absolute_import, division, print_function
__author__ = "Gina Häußge <gina@octoprint.org>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License"
import re
try:
from urllib import parse as urlparse
except:
import urlparse
from webassets.filter import Filter
from webassets.filter.cssrewrite.base import PatternRewriter
import webassets.filter.cssrewrite.urlpath as urlpath
def replace_url(source_url, output_url, url):
# If path is an absolute one, keep it
parsed = urlparse.urlparse(url)
if not parsed.scheme and not parsed.path.startswith('/'):
abs_source_url = urlparse.urljoin(source_url, url)
# relpath() will not detect this case
if urlparse.urlparse(abs_source_url).scheme:
return abs_source_url
# rewritten url: relative path from new location (output)
# to location of referenced file (source + current url)
url = urlpath.relpath(output_url, abs_source_url)
return url
class UrlRewriter(PatternRewriter):
def input(self, _in, out, **kw):
source, source_path, output, output_path = \
kw['source'], kw['source_path'], kw['output'], kw['output_path']
self.source_path = source_path
self.output_path = output_path
self.source_url = self.ctx.resolver.resolve_source_to_url(
self.ctx, source_path, source)
self.output_url = self.ctx.resolver.resolve_output_to_url(
self.ctx, output)
return super(UrlRewriter, self).input(_in, out, **kw)
def replace_url(self, url):
return replace_url(self.source_url, self.output_url, url)
class LessImportRewrite(UrlRewriter):
name = "less_importrewrite"
patterns = {
"import_rewrite": re.compile("(@import(\s+\(.*\))?\s+)\"(.*)\";")
}
def import_rewrite(self, m):
import_with_options = m.group(1)
import_url = self.replace_url(m.group(3))
return "{import_with_options}\"{import_url}\";".format(**locals())
class SourceMapRewrite(UrlRewriter):
name = "sourcemap_urlrewrite"
patterns = {
"url_rewrite": re.compile("(//#\s+sourceMappingURL=)(.*)")
}
def url_rewrite(self, m):
mapping = m.group(1)
source_url = self.replace_url(m.group(2))
return "{mapping}{source_url}".format(**locals())
class SourceMapRemove(PatternRewriter):
name = "sourcemap_remove"
patterns = {
"sourcemap_remove": re.compile("(//#\s+sourceMappingURL=)(.*)")
}
def sourcemap_remove(self, m):
return ""
class JsDelimiterBundler(Filter):
name = "js_delimiter_bundler"
options = {}
def input(self, _in, out, **kwargs):
out.write(_in.read())
out.write("\n;\n")

View file

@ -0,0 +1,30 @@
# coding=utf-8
"""
Unit tests for ``octoprint.server.util.flask``.
"""
from __future__ import absolute_import
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2016 The OctoPrint Project - Released under terms of the AGPLv3 License"
import unittest
import ddt
from octoprint.server.util.webassets import replace_url
@ddt.ddt
class UrlReplaceTest(unittest.TestCase):
@ddt.data(
("mytest/some/path/", "mytest/another/longer/path/", "http://example.com/foo.html", "http://example.com/foo.html"),
("mytest/some/path/", "mytest/another/longer/path/", "/path/foo.html", "/path/foo.html"),
("http://example.com/mytest/some/path/", "mytest/another/longer/path/", "../foo.html", "http://example.com/mytest/some/foo.html"),
("mytest/some/path/", "mytest/another/longer/path/", "../foo.html", "../../../some/foo.html")
)
@ddt.unpack
def test_replace_url(self, source_url, output_url, url, expected):
actual = replace_url(source_url, output_url, url)
self.assertEqual(actual, expected)