-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
snippet performance improvement #8226
base: master
Are you sure you want to change the base?
Conversation
It's a little concerning that |
Suggestion for simpler migration/detecting cached templates. In addition to currently supported forms of snippet
let's add another one: In addition, let's add config option or environment variable that reports any usage of simplest form In this way a developer can enable this switch and see all the templates, that are cached and may be outdated, just as Because of the |
@smotornyuk @amercader I've removed caching for snippets without parameters. It seems jinja2 caching ignores everything, including the language setting, making it useless on many sites and not worth the breaking change for the remaining ones. |
Just found a problem with variables in the parent templates leaking into the snippets. Working on a different approach using |
ckan/config/middleware/flask_app.py
Outdated
@@ -190,11 +190,8 @@ def make_flask_stack(conf: Union[Config, CKANConfig]) -> CKANApp: | |||
app.after_request(ckan_after_request) | |||
|
|||
# Template context processors | |||
app.context_processor(helper_functions) | |||
app.context_processor(c_object) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is deliberately left out from globals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't run into any failing tests, but some extensions might depend on it so I'll move it too
tags = set(['snippet']) | ||
tags = {'snippet'} | ||
|
||
def parse(self, parser: Parser): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must confess that I don't fully grasp this code. Would this be a fair summary?
Here we parse the {% snippet 'path/to/snippet.html', arg1=test %}
string, and turn it into a node tree equivalent to:
{% with %}
{% import ... as snippet %}
{{ snippet(...) }}
{% endwith %}
And then this will be picked up in the CkanFileSystemLoader.parse()
method above which will turn it into :
{% macro snippet(...) %}
{% include ... %}
{% endmacro %}
Which is what will be finally rendered by Jinja. Or is this the other way around?
Sorry I find this a bit confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. The snippet with
/import
node tree references a specially named wrapper template original_name§arg1,arg2.html
that gets generated by CkanFileSystemLoader.get_source()
containing macro
/include
tags.
The imported wrapper template is necessary to create a separate namespace and convert arg1
, arg2
… into local variables for the snippet template.
Co-authored-by: Adrià Mercader <amercadero@gmail.com>
The old code has 7 stack frames between snippet tag and the actual snippet html: File "/srv/app/src_extensions/ckan/ckan/templates/development/primer.html", line 21, in block 'secondary_content'
{% snippet 'development/snippets/nav.html', heading='Navigation' %}
File "/srv/app/src_extensions/ckan/ckan/lib/jinja_extensions.py", line 277, in _call
return base.render_snippet(*args, **kwargs)
File "/srv/app/src_extensions/ckan/ckan/lib/base.py", line 69, in render_snippet
output = render(template_name, extra_vars=kw)
File "/srv/app/src_extensions/ckan/ckan/lib/base.py", line 104, in render
return flask_render_template(template_name, **extra_vars)
File "/usr/lib/python3.10/site-packages/flask/templating.py", line 150, in render_template
return _render(app, template, context)
File "/usr/lib/python3.10/site-packages/flask/templating.py", line 131, in _render
rv = template.render(context)
File "/usr/lib/python3.10/site-packages/jinja2/environment.py", line 1304, in render
self.environment.handle_exception()
File "/usr/lib/python3.10/site-packages/jinja2/environment.py", line 939, in handle_exception
raise rewrite_traceback_stack(source=source)
File "/srv/app/src_extensions/ckan/ckan/templates/development/snippets/nav.html", line 1, in top-level template code Now there are only 2 stack frames (including the generated intermediate File "/srv/app/src_extensions/ckan/ckan/templates/development/primer.html", line 21, in block 'secondary_content'
{% snippet 'development/snippets/nav.html', heading='Navigation' %}
File "/usr/lib/python3.10/site-packages/jinja2/runtime.py", line 782, in _invoke
rv = self._func(*arguments)
File "development/snippets/nav§heading.html", line 1, in template
File "/srv/app/src_extensions/ckan/ckan/templates/development/snippets/nav.html", line 1, in top-level template code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me @smotornyuk, but feel free to have another look
Once the last changes are done I'll merge it
Fixes #6146
Proposed fixes:
reduce separate rendering steps for
{% snippet %}
by converting to:and a generated template with
for fewer extra stack frames and better performance.
Note
does not improve performance of
h.snippet
and other helpers that call it, likeh.user_image
,h.follow_button
,h.csrf_input
Features: