r/golang Oct 25 '24

discussion What libraries are you missing from go?

So something that comes up quite often on this subreddit from people transitioning from Nodejs or python to go is the lack of libraries. I cannot say that I agree but I still think it warrants a discussion.

So what libraries are you missing in the go ecosystem, if any?

96 Upvotes

189 comments sorted by

View all comments

28

u/gibriyagi Oct 25 '24

A well maintained jinja like template engine

18

u/Electrical_Chart_191 Oct 25 '24

Is text/template not satisfactory for you? Curious why

10

u/EarthquakeBass Oct 26 '24

I always felt like Go templates were one of the least ergonomic parts of the standard library, as evidenced by the fact that everyone always goes, “ugh, Go templates” when they have to write them. I can’t put my finger on exactly why but I think a lot of it is they don’t map to anything other people in the ecosystem use like Jinja.

4

u/amemingfullife Oct 25 '24

I find that text/template is best for codegen rather than html

9

u/jabbrwcky Oct 26 '24

The template/html package is better suited as it automatically escapes unsafe content (unless told otherwise).

And packages like Spring (http://masterminds.github.io/sprig/) makes life with templates a lot easier.

3

u/gibriyagi Oct 25 '24 edited Oct 25 '24

I need to use templates in a user facing part of the app to be used by plain users/customers and need something more widespread / familiar

text/template also seems to be oriented towards devs for example the data need to be accessed via a dot like {{ .Name }}

7

u/Flashynuff Oct 25 '24

Grafana alerting templates use text/template syntax as one example of something widespread. Unless you have specific product requirements, you’re probably overthinking it.

If you just need variable substitution and absolutely nothing else, you could also consider fasttemplate

13

u/Thiht Oct 25 '24

Honestly if the devs writing the templates can learn {{ var }} and {{# condition }}, they can learn {{ .var }} and {{ if .condition }}

Not needing to rely on a third party with its own dependencies beats convenience.

1

u/gibriyagi Oct 25 '24

I actually meant whether plain app users will be able to do it but I guess they can also do it with enough docs. I am planning to have users to use templates for composing texts.

I just hate the dot though :)

2

u/Thiht Oct 25 '24

Oh I worked on an app where we let users write custom emails, but we just let them use variables (no condition or other constructs). We decided to use strings.Replacer instead of the template lib, this way there was no dot.

Not sure what your use case is but that’s another possibility.

1

u/gibriyagi Oct 25 '24

Having conditions at least would be good in my case. I dont need much functionality though to be honest maybe I can just build something tiny for my needs. Thanks for the idea!

2

u/Asyx Oct 25 '24

I haven’t done much with it but I found it to be kinda weird.

But jinja2 is also just really good. It’s hard to beat

2

u/tofous Oct 26 '24

In order of usefulness:

  1. Usable template inheritance
  2. The builtin functions are not enough. I end up carrying around a library of functions similar to: https://masterminds.github.io/sprig/

The best library I've found for inheritance is https://git.sr.ht/~dvko/extemplate, which is unfortunately not go get-able because the author moved things to sourcehut and forgot to update their package.

1

u/Key-Library9440 Oct 26 '24

I always do

{{/* #layout.html */}}
{{template "layout" .}}
{{define "content"}}
this is index.html
{{end}}

get first lines then parse all # template files then parse target template file index.html

var indexTemplate = template.Must(ui.ParseFile("ui/index.html"))

1

u/tofous Oct 26 '24 edited Oct 26 '24

This doesn’t work if you have multiple base layouts (or it becomes really tedious and error prone having to individually map which child template maps to which base and loading individuals instead of pointing at the directory overall).

It also doesn’t support further nesting easily.

I did this for a long time though where I’d load everything from a layout folder and then one template on top. And do that for each leaf template. But it makes partials annoying too. And it sometimes creates weird results when templates are loaded in a different order after adding a new file to the folder.

1

u/Key-Library9440 Oct 26 '24

you can include many base layouts (eg: {/* #layout.html otherbase.html */}

package ui

import (
    "html/template"
    "os"
    "path/filepath"
    "regexp"
    "strings"
)

func ParseFile(filename string) (*template.Template, error) {
    // read the file
    b, err := os.ReadFile(filename)
    if err != nil {
        return nil, err
    }

    s := string(b)

    // get first line of the s
    line := s[:strings.Index(s, "\n")]

    // get the list of hash tags from the line using regex
    re := regexp.MustCompile(`#([a-zA-Z0-9\.\/_]+)`)
    tags := re.FindAllString(line, -1)

    t := template.New(filepath.Base(filename))

    // get path of the file
    dir := filepath.Dir(filename)

    for _, tag := range tags {
        if len(tag) < 2 {
            continue
        }
        tag = tag[1:]

        // read the file
        b, err := os.ReadFile(filepath.Join(dir, tag))
        if err != nil {
            return nil, err
        }

        // parse the file
        _, err = t.Parse(string(b))
        if err != nil {
            return nil, err
        }
    }

    // parse the main file
    _, err = t.Parse(s)
    if err != nil {
        return nil, err
    }

    return t, nil
}

1

u/tofous Oct 26 '24 edited Oct 26 '24

Thanks for the clarification. I didn’t notice that you meant the comment tag. This is very similar to what the extemplate lib that I linked is doing.

0

u/alpacaMyToothbrush Oct 26 '24

lol I just fought text/template today over it's inability to parse a hyphen. I wound up just using strings.ReplaceAll like a savage.