Webassets are now written to ~/.octoprint/generated
Same holds true for cache files, so there should be no problem anymore with installs where the static folder is not writable. Also introduced two new devel config vars to disable merging and minifying of the assets, solved the empty-less-bundle problem and made sure babel knows about the jinja extension.
This commit is contained in:
parent
55650cd416
commit
b63f842210
7 changed files with 78 additions and 53 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
[python: src/octoprint/**.py]
|
[python: src/octoprint/**.py]
|
||||||
[jinja2: src/octoprint/templates/**.jinja2]
|
[jinja2: src/octoprint/templates/**.jinja2]
|
||||||
[jinja2: src/octoprint/plugins/**.jinja2]
|
[jinja2: src/octoprint/plugins/**.jinja2]
|
||||||
extensions=jinja2.ext.autoescape, jinja2.ext.with_
|
extensions=jinja2.ext.autoescape, jinja2.ext.with_, webassets.ext.jinja2.AssetsExtension
|
||||||
|
|
||||||
[javascript: src/octoprint/static/js/app/**.js]
|
[javascript: src/octoprint/static/js/app/**.js]
|
||||||
[javascript: src/octoprint/plugins/**.js]
|
[javascript: src/octoprint/plugins/**.js]
|
||||||
|
|
|
||||||
|
|
@ -290,11 +290,6 @@ class Server():
|
||||||
|
|
||||||
# register API blueprint
|
# register API blueprint
|
||||||
self._setup_blueprints()
|
self._setup_blueprints()
|
||||||
def blueprint_enabled(name, plugin):
|
|
||||||
if plugin.implementation is None or not isinstance(plugin.implementation, octoprint.plugin.BlueprintPlugin):
|
|
||||||
return
|
|
||||||
self._register_blueprint_plugin(plugin.implementation)
|
|
||||||
pluginLifecycleManager.add_callback(["enabled"], blueprint_enabled)
|
|
||||||
|
|
||||||
## Tornado initialization starts here
|
## Tornado initialization starts here
|
||||||
|
|
||||||
|
|
@ -313,7 +308,7 @@ class Server():
|
||||||
# camera snapshot
|
# camera snapshot
|
||||||
(r"/downloads/camera/current", util.tornado.UrlForwardHandler, dict(url=s.get(["webcam", "snapshot"]), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))),
|
(r"/downloads/camera/current", util.tornado.UrlForwardHandler, dict(url=s.get(["webcam", "snapshot"]), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))),
|
||||||
# generated webassets
|
# generated webassets
|
||||||
(r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("webassets")))
|
(r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=os.path.join(s.getBaseFolder("generated"), "webassets")))
|
||||||
]
|
]
|
||||||
for name, hook in pluginManager.get_hooks("octoprint.server.http.routes").items():
|
for name, hook in pluginManager.get_hooks("octoprint.server.http.routes").items():
|
||||||
try:
|
try:
|
||||||
|
|
@ -667,12 +662,28 @@ class Server():
|
||||||
global assets
|
global assets
|
||||||
global pluginManager
|
global pluginManager
|
||||||
|
|
||||||
|
base_folder = settings().getBaseFolder("generated")
|
||||||
|
|
||||||
AdjustedEnvironment = type(Environment)(Environment.__name__, (Environment,), dict(
|
AdjustedEnvironment = type(Environment)(Environment.__name__, (Environment,), dict(
|
||||||
resolver_class=util.flask.PluginAssetResolver
|
resolver_class=util.flask.PluginAssetResolver
|
||||||
))
|
))
|
||||||
assets = AdjustedEnvironment(app)
|
class CustomDirectoryEnvironment(AdjustedEnvironment):
|
||||||
|
@property
|
||||||
|
def directory(self):
|
||||||
|
return base_folder
|
||||||
|
|
||||||
dynamic_assets = util.flask.collect_plugin_assets()
|
assets = CustomDirectoryEnvironment(app)
|
||||||
|
assets.debug = not settings().getBoolean(["devel", "webassets", "bundle"])
|
||||||
|
|
||||||
|
enable_gcodeviewer = settings().getBoolean(["gcodeViewer", "enabled"])
|
||||||
|
enable_timelapse = (settings().get(["webcam", "snapshot"]) and settings().get(["webcam", "ffmpeg"]))
|
||||||
|
preferred_stylesheet = settings().get(["devel", "stylesheet"])
|
||||||
|
|
||||||
|
dynamic_assets = util.flask.collect_plugin_assets(
|
||||||
|
enable_gcodeviewer=enable_gcodeviewer,
|
||||||
|
enable_timelapse=enable_timelapse,
|
||||||
|
preferred_stylesheet=preferred_stylesheet
|
||||||
|
)
|
||||||
|
|
||||||
js_libs = [
|
js_libs = [
|
||||||
"js/lib/jquery/jquery.min.js",
|
"js/lib/jquery/jquery.min.js",
|
||||||
|
|
@ -696,16 +707,15 @@ class Server():
|
||||||
"js/lib/jquery/jquery.fileupload.js",
|
"js/lib/jquery/jquery.fileupload.js",
|
||||||
"js/lib/jquery/jquery.slimscroll.min.js",
|
"js/lib/jquery/jquery.slimscroll.min.js",
|
||||||
"js/lib/jquery/jquery.qrcode.min.js",
|
"js/lib/jquery/jquery.qrcode.min.js",
|
||||||
"js/lib/sockjs-0.3.4.min.js",
|
|
||||||
"js/lib/moment-with-locales.min.js",
|
"js/lib/moment-with-locales.min.js",
|
||||||
"js/lib/pusher.color.min.js",
|
"js/lib/pusher.color.min.js",
|
||||||
"js/lib/detectmobilebrowser.js",
|
"js/lib/detectmobilebrowser.js",
|
||||||
"js/lib/md5.min.js",
|
"js/lib/md5.min.js",
|
||||||
"js/lib/pnotify.min.js",
|
"js/lib/pnotify.min.js",
|
||||||
"js/lib/bootstrap-slider-knockout-binding.js",
|
"js/lib/bootstrap-slider-knockout-binding.js",
|
||||||
"js/lib/loglevel.min.js"
|
"js/lib/loglevel.min.js",
|
||||||
|
"js/lib/sockjs-0.3.4.min.js"
|
||||||
]
|
]
|
||||||
|
|
||||||
js_app = dynamic_assets["js"] + [
|
js_app = dynamic_assets["js"] + [
|
||||||
"js/app/dataupdater.js",
|
"js/app/dataupdater.js",
|
||||||
"js/app/helpers.js",
|
"js/app/helpers.js",
|
||||||
|
|
@ -721,29 +731,24 @@ class Server():
|
||||||
"css/jquery.fileupload-ui.css",
|
"css/jquery.fileupload-ui.css",
|
||||||
"css/pnotify.min.css"
|
"css/pnotify.min.css"
|
||||||
]
|
]
|
||||||
|
css_app = ["empty"] + dynamic_assets["css"]
|
||||||
css_app = []
|
less_app = ["empty"] + dynamic_assets["less"]
|
||||||
less_app = []
|
|
||||||
for sheet, path in dynamic_assets["stylesheets"]:
|
|
||||||
if sheet == "css":
|
|
||||||
css_app.append(path)
|
|
||||||
elif sheet == "less":
|
|
||||||
less_app.append(path)
|
|
||||||
|
|
||||||
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js")
|
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js")
|
||||||
js_app_bundle = Bundle(*js_app, output="webassets/package_app.js")
|
if settings().getBoolean(["devel", "webassets", "minify"]):
|
||||||
|
js_app_bundle = Bundle(*js_app, output="webassets/package_app.js", filters="rjsmin")
|
||||||
|
else:
|
||||||
|
js_app_bundle = Bundle(*js_app, output="webassets/package_app.js")
|
||||||
|
all_js_bundle = Bundle(js_libs_bundle, js_app_bundle, output="webassets/packed.js")
|
||||||
|
|
||||||
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css")
|
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css")
|
||||||
|
css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css")
|
||||||
|
all_css_bundle = Bundle(css_libs_bundle, css_app_bundle, output="webassets/packed.css")
|
||||||
|
all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less")
|
||||||
|
|
||||||
assets.register("js_libs", js_libs_bundle)
|
assets.register("all_js", all_js_bundle)
|
||||||
assets.register("js_app", js_app_bundle)
|
assets.register("all_css", all_css_bundle)
|
||||||
assets.register("css_libs", css_libs_bundle)
|
assets.register("less_app", all_less_bundle)
|
||||||
|
|
||||||
if len(css_app):
|
|
||||||
css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css")
|
|
||||||
assets.register("css_app", css_app_bundle)
|
|
||||||
if len(less_app):
|
|
||||||
less_app_bundle = Bundle(*less_app, output="webassets/packed_app.less")
|
|
||||||
assets.register("less_app", less_app_bundle)
|
|
||||||
|
|
||||||
|
|
||||||
class LifecycleManager(object):
|
class LifecycleManager(object):
|
||||||
|
|
|
||||||
|
|
@ -431,10 +431,34 @@ class PluginAssetResolver(flask.ext.assets.FlaskResolver):
|
||||||
return flask.ext.assets.FlaskResolver.split_prefix(self, item)
|
return flask.ext.assets.FlaskResolver.split_prefix(self, item)
|
||||||
|
|
||||||
def resolve_output_to_path(self, target, bundle):
|
def resolve_output_to_path(self, target, bundle):
|
||||||
if target.startswith("webassets/"):
|
import os
|
||||||
import os
|
return os.path.normpath(os.path.join(self.env.directory, target))
|
||||||
return os.path.normpath(os.path.join(settings().getBaseFolder("webassets"), target[len("webassets/"):]))
|
|
||||||
return flask.ext.assets.FlaskResolver.resolve_output_to_path(self, target, bundle)
|
def resolve_source_to_url(self, filepath, item):
|
||||||
|
if item.startswith("plugin/"):
|
||||||
|
try:
|
||||||
|
prefix, plugin, name = item.split('/', 2)
|
||||||
|
blueprint = prefix + "." + plugin
|
||||||
|
|
||||||
|
self.env._app.blueprints[blueprint] # keyerror if no module
|
||||||
|
endpoint = '%s.static' % blueprint
|
||||||
|
filename = name
|
||||||
|
except (ValueError, KeyError):
|
||||||
|
endpoint = 'static'
|
||||||
|
filename = item
|
||||||
|
|
||||||
|
ctx = None
|
||||||
|
if not flask._request_ctx_stack.top:
|
||||||
|
ctx = self.env._app.test_request_context()
|
||||||
|
ctx.push()
|
||||||
|
try:
|
||||||
|
return flask.url_for(endpoint, filename=filename)
|
||||||
|
finally:
|
||||||
|
if ctx:
|
||||||
|
ctx.pop()
|
||||||
|
|
||||||
|
return flask.ext.assets.FlaskResolver.resolve_source_to_url(self, filepath, item)
|
||||||
|
|
||||||
|
|
||||||
##~~ plugin assets collector
|
##~~ plugin assets collector
|
||||||
|
|
||||||
|
|
@ -442,7 +466,8 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer
|
||||||
supported_stylesheets = ("css", "less")
|
supported_stylesheets = ("css", "less")
|
||||||
assets = dict(
|
assets = dict(
|
||||||
js=[],
|
js=[],
|
||||||
stylesheets=[]
|
css=[],
|
||||||
|
less=[]
|
||||||
)
|
)
|
||||||
assets["js"] = [
|
assets["js"] = [
|
||||||
'js/app/viewmodels/appearance.js',
|
'js/app/viewmodels/appearance.js',
|
||||||
|
|
@ -473,9 +498,9 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer
|
||||||
assets["js"].append('js/app/viewmodels/timelapse.js')
|
assets["js"].append('js/app/viewmodels/timelapse.js')
|
||||||
|
|
||||||
if preferred_stylesheet == "less":
|
if preferred_stylesheet == "less":
|
||||||
assets["stylesheets"].append(("less", 'less/octoprint.less'))
|
assets["less"].append('less/octoprint.less')
|
||||||
elif preferred_stylesheet == "css":
|
elif preferred_stylesheet == "css":
|
||||||
assets["stylesheets"].append(("css", 'css/octoprint.css'))
|
assets["css"].append('css/octoprint.css')
|
||||||
|
|
||||||
asset_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.AssetPlugin)
|
asset_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.AssetPlugin)
|
||||||
for implementation in asset_plugins:
|
for implementation in asset_plugins:
|
||||||
|
|
@ -488,14 +513,14 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer
|
||||||
|
|
||||||
if preferred_stylesheet in all_assets:
|
if preferred_stylesheet in all_assets:
|
||||||
for asset in all_assets[preferred_stylesheet]:
|
for asset in all_assets[preferred_stylesheet]:
|
||||||
assets["stylesheets"].append((preferred_stylesheet, 'plugin/{name}/{asset}'.format(**locals())))
|
assets[preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
|
||||||
else:
|
else:
|
||||||
for stylesheet in supported_stylesheets:
|
for stylesheet in supported_stylesheets:
|
||||||
if not stylesheet in all_assets:
|
if not stylesheet in all_assets:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for asset in all_assets[stylesheet]:
|
for asset in all_assets[stylesheet]:
|
||||||
assets["stylesheets"].append((stylesheet, 'plugin/{name}/{asset}'.format(**locals())))
|
assets[stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
|
||||||
break
|
break
|
||||||
|
|
||||||
return assets
|
return assets
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ default_settings = {
|
||||||
"printerProfiles": None,
|
"printerProfiles": None,
|
||||||
"scripts": None,
|
"scripts": None,
|
||||||
"translations": None,
|
"translations": None,
|
||||||
"webassets": None
|
"generated": None
|
||||||
},
|
},
|
||||||
"temperature": {
|
"temperature": {
|
||||||
"profiles": [
|
"profiles": [
|
||||||
|
|
@ -249,6 +249,10 @@ default_settings = {
|
||||||
"cache": {
|
"cache": {
|
||||||
"enabled": True
|
"enabled": True
|
||||||
},
|
},
|
||||||
|
"webassets": {
|
||||||
|
"minify": True,
|
||||||
|
"bundle": True
|
||||||
|
},
|
||||||
"virtualPrinter": {
|
"virtualPrinter": {
|
||||||
"enabled": False,
|
"enabled": False,
|
||||||
"okAfterResend": False,
|
"okAfterResend": False,
|
||||||
|
|
|
||||||
0
src/octoprint/static/empty
Normal file
0
src/octoprint/static/empty
Normal file
|
|
@ -1,9 +1,4 @@
|
||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/lib/moment-with-locales.min.js') }}"></script>
|
{% assets "all_js" %}
|
||||||
{% assets "js_libs" %}
|
|
||||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
|
||||||
{% endassets %}
|
|
||||||
|
|
||||||
{% assets "js_app" %}
|
|
||||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||||
{% endassets %}
|
{% endassets %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
{% assets "css_libs" %}
|
{% assets "all_css" %}
|
||||||
<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">
|
<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">
|
||||||
{% endassets %}
|
{% endassets %}
|
||||||
|
|
||||||
{% assets "css_app" %}
|
|
||||||
<link href="{{ ASSET_URL }}" rel="stylesheet" type="text/css" media="screen">
|
|
||||||
{% endassets %}
|
|
||||||
|
|
||||||
{% assets "less_app" %}
|
{% assets "less_app" %}
|
||||||
<link href="{{ url }}" rel="stylesheet/less" type="text/css" media="screen">
|
<link href="{{ ASSET_URL }}" rel="stylesheet/less" type="text/css" media="screen">
|
||||||
{% endassets %}
|
{% endassets %}
|
||||||
|
|
||||||
<script src="{{ url_for('static', filename='js/lib/less.min.js') }}" type="text/javascript"></script>
|
<script src="{{ url_for('static', filename='js/lib/less.min.js') }}" type="text/javascript"></script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue