gohugoio / hugo

The world’s fastest framework for building websites.
https://gohugo.io
Apache License 2.0
75.65k stars 7.52k forks source link

Support template function definitions #8509

Open bep opened 3 years ago

bep commented 3 years ago

See https://pkg.go.dev/rsc.io/tmplfunc#hdr-Function_Definitions

I don't think it's practical to use that library directly, but the idea (and the parsing logic) is intriguing.

I'll use one the examples in his docs:

{{define "link url text?"}}<a href="{{.url}}">{{or .text .url}}</a>{{end}}

The Go home page is {{link "https://golang.org"}}.
The Go home page is {{link "https://golang.org" "Google Home"}}.

It would also be nice if we could support the return keyword for these so we could do:

{{define "add a b"}}{{ $result := add .a .b }}{{ return $result }}{{end}}

The above example probably shows that we should have a check to make sure you don't redefine an existing func.

/cc @regisphilibert

regisphilibert commented 3 years ago

TL;DR: Awesome! Can't wait!


I do see it as an opportunity to step away from the partial API that I (and possibly others) have been exploiting all around to achieve goals it has never been designed for (having to use dict to pass >1 arguments is tiresome.) This would also bring the usage of reusable code closer to other templating or even programming languages.

{{ link "https://golang.org" "Google Home" }} 🎉 vs {{ partial "func/link" (dict "url" "https://golang.org" "text" "Google Home") }} 😩

Even without the return keyword it would really help create reusable template components for any given projects (link, button, image etc...) aligned with other template languages like Nunjucks and its macros or other's mixins and the like.

return

But I'm very excited about the possibility of adding the return keyword in the mix! It would really change the way reusable non-templating code is handled in Hugo. This would bring the DX closer to regular programming languages.

partialCached equivalent?

Is there a cached solution in place so that the process is never done twice for the same set of argument values?

best practices (too soon?)

I already wonder what the best practice should be as in order to keep functions in their own files, we'd have to call a partial containing the define before using it.

  1. Call a partial once which declares all the defines (stored in their own partials maybe)
  2. Call a single partial containing the define in every template file the "defined function" needs to be used.
{{ partial "defines/func/process" }}

{{ $first := process .first }}
{{ $second := process .second }}
{{ $third := process .thirst }}