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:
parent
59d78ba893
commit
832c27ed18
3 changed files with 153 additions and 37 deletions
|
|
@ -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)
|
||||
|
|
|
|||
100
src/octoprint/server/util/webassets.py
Normal file
100
src/octoprint/server/util/webassets.py
Normal 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")
|
||||
30
tests/server/util/test_webassets.py
Normal file
30
tests/server/util/test_webassets.py
Normal 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)
|
||||
Loading…
Reference in a new issue