Skip to content

Commit b63f842

Browse files
committed
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.
1 parent 55650cd commit b63f842

File tree

7 files changed

+79
-54
lines changed

7 files changed

+79
-54
lines changed

babel.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[python: src/octoprint/**.py]
22
[jinja2: src/octoprint/templates/**.jinja2]
33
[jinja2: src/octoprint/plugins/**.jinja2]
4-
extensions=jinja2.ext.autoescape, jinja2.ext.with_
4+
extensions=jinja2.ext.autoescape, jinja2.ext.with_, webassets.ext.jinja2.AssetsExtension
55

66
[javascript: src/octoprint/static/js/app/**.js]
77
[javascript: src/octoprint/plugins/**.js]

src/octoprint/server/__init__.py

+36-31
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,6 @@ def template_disabled(name, plugin):
290290

291291
# register API blueprint
292292
self._setup_blueprints()
293-
def blueprint_enabled(name, plugin):
294-
if plugin.implementation is None or not isinstance(plugin.implementation, octoprint.plugin.BlueprintPlugin):
295-
return
296-
self._register_blueprint_plugin(plugin.implementation)
297-
pluginLifecycleManager.add_callback(["enabled"], blueprint_enabled)
298293

299294
## Tornado initialization starts here
300295

@@ -313,7 +308,7 @@ def blueprint_enabled(name, plugin):
313308
# camera snapshot
314309
(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))),
315310
# generated webassets
316-
(r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("webassets")))
311+
(r"/static/webassets/(.*)", util.tornado.LargeResponseHandler, dict(path=os.path.join(s.getBaseFolder("generated"), "webassets")))
317312
]
318313
for name, hook in pluginManager.get_hooks("octoprint.server.http.routes").items():
319314
try:
@@ -667,12 +662,28 @@ def _setup_assets(self):
667662
global assets
668663
global pluginManager
669664

665+
base_folder = settings().getBaseFolder("generated")
666+
670667
AdjustedEnvironment = type(Environment)(Environment.__name__, (Environment,), dict(
671668
resolver_class=util.flask.PluginAssetResolver
672669
))
673-
assets = AdjustedEnvironment(app)
674-
675-
dynamic_assets = util.flask.collect_plugin_assets()
670+
class CustomDirectoryEnvironment(AdjustedEnvironment):
671+
@property
672+
def directory(self):
673+
return base_folder
674+
675+
assets = CustomDirectoryEnvironment(app)
676+
assets.debug = not settings().getBoolean(["devel", "webassets", "bundle"])
677+
678+
enable_gcodeviewer = settings().getBoolean(["gcodeViewer", "enabled"])
679+
enable_timelapse = (settings().get(["webcam", "snapshot"]) and settings().get(["webcam", "ffmpeg"]))
680+
preferred_stylesheet = settings().get(["devel", "stylesheet"])
681+
682+
dynamic_assets = util.flask.collect_plugin_assets(
683+
enable_gcodeviewer=enable_gcodeviewer,
684+
enable_timelapse=enable_timelapse,
685+
preferred_stylesheet=preferred_stylesheet
686+
)
676687

677688
js_libs = [
678689
"js/lib/jquery/jquery.min.js",
@@ -696,16 +707,15 @@ def _setup_assets(self):
696707
"js/lib/jquery/jquery.fileupload.js",
697708
"js/lib/jquery/jquery.slimscroll.min.js",
698709
"js/lib/jquery/jquery.qrcode.min.js",
699-
"js/lib/sockjs-0.3.4.min.js",
700710
"js/lib/moment-with-locales.min.js",
701711
"js/lib/pusher.color.min.js",
702712
"js/lib/detectmobilebrowser.js",
703713
"js/lib/md5.min.js",
704714
"js/lib/pnotify.min.js",
705715
"js/lib/bootstrap-slider-knockout-binding.js",
706-
"js/lib/loglevel.min.js"
716+
"js/lib/loglevel.min.js",
717+
"js/lib/sockjs-0.3.4.min.js"
707718
]
708-
709719
js_app = dynamic_assets["js"] + [
710720
"js/app/dataupdater.js",
711721
"js/app/helpers.js",
@@ -721,29 +731,24 @@ def _setup_assets(self):
721731
"css/jquery.fileupload-ui.css",
722732
"css/pnotify.min.css"
723733
]
724-
725-
css_app = []
726-
less_app = []
727-
for sheet, path in dynamic_assets["stylesheets"]:
728-
if sheet == "css":
729-
css_app.append(path)
730-
elif sheet == "less":
731-
less_app.append(path)
734+
css_app = ["empty"] + dynamic_assets["css"]
735+
less_app = ["empty"] + dynamic_assets["less"]
732736

733737
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js")
734-
js_app_bundle = Bundle(*js_app, output="webassets/package_app.js")
735-
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css")
738+
if settings().getBoolean(["devel", "webassets", "minify"]):
739+
js_app_bundle = Bundle(*js_app, output="webassets/package_app.js", filters="rjsmin")
740+
else:
741+
js_app_bundle = Bundle(*js_app, output="webassets/package_app.js")
742+
all_js_bundle = Bundle(js_libs_bundle, js_app_bundle, output="webassets/packed.js")
736743

737-
assets.register("js_libs", js_libs_bundle)
738-
assets.register("js_app", js_app_bundle)
739-
assets.register("css_libs", css_libs_bundle)
744+
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css")
745+
css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css")
746+
all_css_bundle = Bundle(css_libs_bundle, css_app_bundle, output="webassets/packed.css")
747+
all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less")
740748

741-
if len(css_app):
742-
css_app_bundle = Bundle(*css_app, output="webassets/packed_app.css")
743-
assets.register("css_app", css_app_bundle)
744-
if len(less_app):
745-
less_app_bundle = Bundle(*less_app, output="webassets/packed_app.less")
746-
assets.register("less_app", less_app_bundle)
749+
assets.register("all_js", all_js_bundle)
750+
assets.register("all_css", all_css_bundle)
751+
assets.register("less_app", all_less_bundle)
747752

748753

749754
class LifecycleManager(object):

src/octoprint/server/util/flask.py

+34-9
Original file line numberDiff line numberDiff line change
@@ -431,18 +431,43 @@ def split_prefix(self, item):
431431
return flask.ext.assets.FlaskResolver.split_prefix(self, item)
432432

433433
def resolve_output_to_path(self, target, bundle):
434-
if target.startswith("webassets/"):
435-
import os
436-
return os.path.normpath(os.path.join(settings().getBaseFolder("webassets"), target[len("webassets/"):]))
437-
return flask.ext.assets.FlaskResolver.resolve_output_to_path(self, target, bundle)
434+
import os
435+
return os.path.normpath(os.path.join(self.env.directory, target))
436+
437+
def resolve_source_to_url(self, filepath, item):
438+
if item.startswith("plugin/"):
439+
try:
440+
prefix, plugin, name = item.split('/', 2)
441+
blueprint = prefix + "." + plugin
442+
443+
self.env._app.blueprints[blueprint] # keyerror if no module
444+
endpoint = '%s.static' % blueprint
445+
filename = name
446+
except (ValueError, KeyError):
447+
endpoint = 'static'
448+
filename = item
449+
450+
ctx = None
451+
if not flask._request_ctx_stack.top:
452+
ctx = self.env._app.test_request_context()
453+
ctx.push()
454+
try:
455+
return flask.url_for(endpoint, filename=filename)
456+
finally:
457+
if ctx:
458+
ctx.pop()
459+
460+
return flask.ext.assets.FlaskResolver.resolve_source_to_url(self, filepath, item)
461+
438462

439463
##~~ plugin assets collector
440464

441465
def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, preferred_stylesheet="css"):
442466
supported_stylesheets = ("css", "less")
443467
assets = dict(
444468
js=[],
445-
stylesheets=[]
469+
css=[],
470+
less=[]
446471
)
447472
assets["js"] = [
448473
'js/app/viewmodels/appearance.js',
@@ -473,9 +498,9 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer
473498
assets["js"].append('js/app/viewmodels/timelapse.js')
474499

475500
if preferred_stylesheet == "less":
476-
assets["stylesheets"].append(("less", 'less/octoprint.less'))
501+
assets["less"].append('less/octoprint.less')
477502
elif preferred_stylesheet == "css":
478-
assets["stylesheets"].append(("css", 'css/octoprint.css'))
503+
assets["css"].append('css/octoprint.css')
479504

480505
asset_plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.AssetPlugin)
481506
for implementation in asset_plugins:
@@ -488,14 +513,14 @@ def collect_plugin_assets(enable_gcodeviewer=True, enable_timelapse=True, prefer
488513

489514
if preferred_stylesheet in all_assets:
490515
for asset in all_assets[preferred_stylesheet]:
491-
assets["stylesheets"].append((preferred_stylesheet, 'plugin/{name}/{asset}'.format(**locals())))
516+
assets[preferred_stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
492517
else:
493518
for stylesheet in supported_stylesheets:
494519
if not stylesheet in all_assets:
495520
continue
496521

497522
for asset in all_assets[stylesheet]:
498-
assets["stylesheets"].append((stylesheet, 'plugin/{name}/{asset}'.format(**locals())))
523+
assets[stylesheet].append('plugin/{name}/{asset}'.format(**locals()))
499524
break
500525

501526
return assets

src/octoprint/settings.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def settings(init=False, basedir=None, configfile=None):
156156
"printerProfiles": None,
157157
"scripts": None,
158158
"translations": None,
159-
"webassets": None
159+
"generated": None
160160
},
161161
"temperature": {
162162
"profiles": [
@@ -249,6 +249,10 @@ def settings(init=False, basedir=None, configfile=None):
249249
"cache": {
250250
"enabled": True
251251
},
252+
"webassets": {
253+
"minify": True,
254+
"bundle": True
255+
},
252256
"virtualPrinter": {
253257
"enabled": False,
254258
"okAfterResend": False,

src/octoprint/static/empty

Whitespace-only changes.

src/octoprint/templates/javascripts.jinja2

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
<script type="text/javascript" src="{{ url_for('static', filename='js/lib/moment-with-locales.min.js') }}"></script>
2-
{% assets "js_libs" %}
3-
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
4-
{% endassets %}
5-
6-
{% assets "js_app" %}
1+
{% assets "all_js" %}
72
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
83
{% endassets %}
94

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
{% assets "css_libs" %}
1+
{% assets "all_css" %}
22
<link href="{{ ASSET_URL }}" rel="stylesheet" media="screen">
33
{% endassets %}
44

5-
{% assets "css_app" %}
6-
<link href="{{ ASSET_URL }}" rel="stylesheet" type="text/css" media="screen">
7-
{% endassets %}
8-
95
{% assets "less_app" %}
10-
<link href="{{ url }}" rel="stylesheet/less" type="text/css" media="screen">
6+
<link href="{{ ASSET_URL }}" rel="stylesheet/less" type="text/css" media="screen">
117
{% endassets %}
128

139
<script src="{{ url_for('static', filename='js/lib/less.min.js') }}" type="text/javascript"></script>

0 commit comments

Comments
 (0)