diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2023-04-20 16:08:58 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-20 04:08:58 -0400 |
commit | 722dab5286a001a0bd367d42258a8613a944e1c1 (patch) | |
tree | fcb205e049d778e879f12272cf306d58b9aa4ce0 /modules/context | |
parent | de2268ffab922de67f51e98541d0f9078795ac5d (diff) | |
download | gitea-722dab5286a001a0bd367d42258a8613a944e1c1.tar.gz gitea-722dab5286a001a0bd367d42258a8613a944e1c1.zip |
Make HTML template functions support context (#24056)
# Background
Golang template is not friendly for large projects, and Golang template
team is quite slow, related:
* `https://github.com/golang/go/issues/54450`
Without upstream support, we can also have our solution to make HTML
template functions support context.
It helps a lot, the above Golang template issue `#54450` explains a lot:
1. It makes `{{Locale.Tr}}` could be used in any template, without
passing unclear `(dict "root" . )` anymore.
2. More and more functions need `context`, like `avatar`, etc, we do not
need to do `(dict "Context" $.Context)` anymore.
3. Many request-related functions could be shared by parent&children
templates, like "user setting" / "system setting"
See the test `TestScopedTemplateSetFuncMap`, one template set, two
`Execute` calls with different `CtxFunc`.
# The Solution
Instead of waiting for upstream, this PR re-uses the escaped HTML
template trees, use `AddParseTree` to add related templates/trees to a
new template instance, then the new template instance can have its own
FuncMap , the function calls in the template trees will always use the
new template's FuncMap.
`template.New` / `template.AddParseTree` / `adding-FuncMap` are all
quite fast, so the performance is not affected.
The details:
1. Make a new `html/template/Template` for `all` templates
2. Add template code to the `all` template
3. Freeze the `all` template, reset its exec func map, it shouldn't
execute any template.
4. When a router wants to render a template by its `name`
1. Find the `name` in `all`
2. Find all its related sub templates
3. Escape all related templates (just like what the html template
package does)
4. Add the escaped parse-trees of related templates into a new (scoped)
`text/template/Template`
5. Add context-related func map into the new (scoped) text template
6. Execute the new (scoped) text template
7. To improve performance, the escaped templates are cached to `template
sets`
# FAQ
## There is a `unsafe` call, is this PR unsafe?
This PR is safe. Golang has strict language definition, it's safe to do
so: https://pkg.go.dev/unsafe#Pointer (1) Conversion of a *T1 to Pointer
to *T2
## What if Golang template supports such feature in the future?
The public structs/interfaces/functions introduced by this PR is quite
simple, the code of `HTMLRender` is not changed too much. It's very easy
to switch to the official mechanism if there would be one.
## Does this PR change the template execution behavior?
No, see the tests (welcome to design more tests if it's necessary)
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Diffstat (limited to 'modules/context')
-rw-r--r-- | modules/context/context.go | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/modules/context/context.go b/modules/context/context.go index 21bae91129..7e986b0119 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -47,7 +47,7 @@ const CookieNameFlash = "gitea_flash" // Render represents a template render type Render interface { - TemplateLookup(tmpl string) (*template.Template, error) + TemplateLookup(tmpl string) (templates.TemplateExecutor, error) HTML(w io.Writer, status int, name string, data interface{}) error } |