Split JS/CSS/LESS assets between core+bundled plugins and external plugins

That way a JS error in an external plugin won't nuke the whole UI, which IMHO
is worth the additional requests needed to load the split up files.

See #1544 for an example of such a situation.
This commit is contained in:
Gina Häußge 2016-10-13 12:07:00 +02:00
parent 1370c7a9cc
commit 419f3370a2
4 changed files with 74 additions and 48 deletions

View file

@ -1015,7 +1015,8 @@ class Server(object):
enable_gcodeviewer = settings().getBoolean(["gcodeViewer", "enabled"])
preferred_stylesheet = settings().get(["devel", "stylesheet"])
dynamic_assets = util.flask.collect_plugin_assets(
dynamic_core_assets = util.flask.collect_core_assets(enable_gcodeviewer=enable_gcodeviewer)
dynamic_plugin_assets = util.flask.collect_plugin_assets(
enable_gcodeviewer=enable_gcodeviewer,
preferred_stylesheet=preferred_stylesheet
)
@ -1051,11 +1052,13 @@ class Server(object):
"js/lib/loglevel.min.js",
"js/lib/sockjs-0.3.4.min.js"
]
js_app = dynamic_assets["js"] + [
"js/app/dataupdater.js",
"js/app/helpers.js",
"js/app/main.js",
]
js_core = dynamic_core_assets["js"] + \
dynamic_plugin_assets["bundled"]["js"] + \
["js/app/dataupdater.js",
"js/app/helpers.js",
"js/app/main.js"]
js_plugins = dynamic_plugin_assets["external"]["js"]
js_app = js_core + js_plugins
css_libs = [
"css/bootstrap.min.css",
@ -1066,13 +1069,21 @@ class Server(object):
"css/jquery.fileupload-ui.css",
"css/pnotify.min.css"
]
css_app = list(dynamic_assets["css"])
if len(css_app) == 0:
css_app = ["empty"]
css_core = list(dynamic_core_assets["css"]) + list(dynamic_plugin_assets["bundled"]["css"])
if len(css_core) == 0:
css_core = ["empty"]
css_plugins = list(dynamic_plugin_assets["external"]["css"])
if len(css_plugins) == 0:
css_plugins = ["empty"]
css_app = css_core + css_plugins
less_app = list(dynamic_assets["less"])
if len(less_app) == 0:
less_app = ["empty"]
less_core = list(dynamic_core_assets["less"]) + list(dynamic_plugin_assets["bundled"]["less"])
if len(less_core) == 0:
less_core = ["empty"]
less_plugins = list(dynamic_plugin_assets["external"]["less"])
if len(less_plugins) == 0:
less_plugins = ["empty"]
less_app = less_core + less_plugins
from webassets.filter import register_filter, Filter
from webassets.filter.cssrewrite.base import PatternRewriter
@ -1093,7 +1104,7 @@ class Server(object):
return "{import_with_options}\"{import_url}\";".format(**locals())
class JsDelimiterBundle(Filter):
class JsDelimiterBundler(Filter):
name = "js_delimiter_bundler"
options = {}
def input(self, _in, out, **kwargs):
@ -1101,24 +1112,42 @@ class Server(object):
out.write("\n;\n")
register_filter(LessImportRewrite)
register_filter(JsDelimiterBundle)
register_filter(JsDelimiterBundler)
# JS
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js", filters="js_delimiter_bundler")
if settings().getBoolean(["devel", "webassets", "minify"]):
js_core_bundle = Bundle(*js_core, output="webassets/packed_core.js", filters="rjsmin, js_delimiter_bundler")
js_plugins_bundle = Bundle(*js_plugins, output="webassets/packed_plugins.js", filters="rjsmin, js_delimiter_bundler")
js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="rjsmin, js_delimiter_bundler")
else:
js_core_bundle = Bundle(*js_core, output="webassets/packed_core.js", filters="js_delimiter_bundler")
js_plugins_bundle = Bundle(*js_plugins, output="webassets/packed_plugins.js", filters="js_delimiter_bundler")
js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="js_delimiter_bundler")
# CSS
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css")
css_core_bundle = Bundle(*css_core, output="webassets/packed_core.css", filters="cssrewrite")
css_plugins_bundle = Bundle(*css_plugins, output="webassets/packed_plugins.css", filters="cssrewrite")
css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css", filters="cssrewrite")
all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite")
# LESS
less_core_bundle = Bundle(*less_core, output="webassets/packed_core.less", filters="cssrewrite, less_importrewrite")
less_plugins_bundle = Bundle(*less_plugins, output="webassets/packed_plugins.less", filters="cssrewrite, less_importrewrite")
less_app_bundle = Bundle(*less_app, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite")
# asset registration
assets.register("js_libs", js_libs_bundle)
assets.register("js_core", js_core_bundle)
assets.register("js_plugins", js_plugins_bundle)
assets.register("js_app", js_app_bundle)
assets.register("css_libs", css_libs_bundle)
assets.register("css_core", css_core_bundle)
assets.register("css_plugins", css_plugins_bundle)
assets.register("css_app", css_app_bundle)
assets.register("less_app", all_less_bundle)
assets.register("less_core", less_core_bundle)
assets.register("less_plugins", less_plugins_bundle)
assets.register("less_app", less_app_bundle)
def _start_intermediary_server(self, s):
import BaseHTTPServer

View file

@ -1134,12 +1134,8 @@ class SettingsCheckUpdater(webassets.updater.BaseUpdater):
cache_value = webassets.utils.hash_func(json.dumps(settings().effective_yaml))
ctx.cache.set(cache_key, cache_value)
##~~ plugin assets collector
def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
logger = logging.getLogger(__name__ + ".collect_plugin_assets")
supported_stylesheets = ("css", "less")
##~~ core assets collector
def collect_core_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
assets = dict(
js=[],
css=[],
@ -1178,9 +1174,24 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
elif preferred_stylesheet == "css":
assets["css"].append('css/octoprint.css')
return assets
##~~ plugin assets collector
def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
logger = logging.getLogger(__name__ + ".collect_plugin_assets")
supported_stylesheets = ("css", "less")
assets = dict(bundled=dict(js=[], css=[], less=[]),
external=dict(js=[], css=[], less=[]))
asset_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.AssetPlugin)
for implementation in asset_plugins:
name = implementation._identifier
is_bundled = implementation._plugin_info.bundled
asset_key = "bundled" if is_bundled else "external"
try:
all_assets = implementation.get_assets()
basefolder = implementation.get_asset_folder()
@ -1198,13 +1209,13 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
for asset in all_assets["js"]:
if not asset_exists("js", asset):
continue
assets["js"].append('plugin/{name}/{asset}'.format(**locals()))
assets[asset_key]["js"].append('plugin/{name}/{asset}'.format(**locals()))
if preferred_stylesheet in all_assets:
for asset in all_assets[preferred_stylesheet]:
if not asset_exists(preferred_stylesheet, asset):
continue
assets[preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
assets[asset_key][preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
else:
for stylesheet in supported_stylesheets:
if not stylesheet in all_assets:
@ -1213,7 +1224,7 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
for asset in all_assets[stylesheet]:
if not asset_exists(stylesheet, asset):
continue
assets[stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
assets[asset_key][stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
break
return assets

View file

@ -1,11 +1,4 @@
{% assets "js_libs" %}
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}
{% assets "js_app" %}
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}
{% if g.locale %}
<script type="text/javascript" src="{{ url_for('localeJs', locale=g.locale, domain='messages') }}"></script>
{% endif %}
{% assets "js_libs" %}<script type="text/javascript" src="{{ ASSET_URL }}"></script>{% endassets %}
{% assets "js_core" %}<script type="text/javascript" src="{{ ASSET_URL }}"></script>{% endassets %}
{% assets "js_plugins" %}<script type="text/javascript" src="{{ ASSET_URL }}"></script>{% endassets %}
{% if g.locale %}<script type="text/javascript" src="{{ url_for('localeJs', locale=g.locale, domain='messages') }}"></script>{% endif %}

View file

@ -1,13 +1,6 @@
{% assets "css_libs" %}
<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">
{% endassets %}
{% assets "css_app" %}
<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">
{% endassets %}
{% assets "less_app" %}
<link href="{{ ASSET_URL }}" rel="stylesheet/less" type="text/css" media="screen">
{% endassets %}
{% assets "css_libs" %}<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">{% endassets %}
{% assets "css_core" %}<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">{% endassets %}
{% assets "css_plugins" %}<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">{% endassets %}
{% assets "less_core" %}<link href="{{ ASSET_URL }}" rel="stylesheet/less" type="text/css" media="screen">{% endassets %}
{% assets "less_plugins" %}<link href="{{ ASSET_URL }}" rel="stylesheet/less" type="text/css" media="screen">{% endassets %}
<script src="{{ url_for('static', filename='js/lib/less.min.js') }}" type="text/javascript"></script>