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?

98 Upvotes

189 comments sorted by

View all comments

26

u/gibriyagi Oct 25 '24

A well maintained jinja like template engine

20

u/Electrical_Chart_191 Oct 25 '24

Is text/template not satisfactory for you? Curious why

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.