Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃挕 Changing the Template system #331

Closed
Fenny opened this issue Apr 30, 2020 · 7 comments
Closed

馃挕 Changing the Template system #331

Fenny opened this issue Apr 30, 2020 · 7 comments

Comments

@Fenny
Copy link
Member

Fenny commented Apr 30, 2020

I'm writing this issue publicly so that everyone using Fiber can share their opinion regarding this matter. The way it currently works is very limited, outdated and not stable (#277, #330, #320, #190, #182)

Fiber currently has one render function that parses a template file and executes the given bind values.

app.Get("/", func(c *fiber.Ctx) {
  c.Render("./views/index.tmpl", fiber.Map{
    "title":   "Homepage",
    "counter": 9000,
  })
})

With some simple app settings you can suger-coat the syntax by pre-defining the template folder, extension and parser (if you are using the gofiber/template middleware).

app := fiber.New(&fiber.Settings{
    TemplateEngine:    template.Mustache(),
    TemplateFolder:    "./views",
    TemplateExtension: ".tmpl",
})
app.Get("/", func(c *fiber.Ctx) {
  c.Render("index", fiber.Map{
    "title":   "Homepage",
    "counter": 9000,
  })
})

You can see that this is a limited template system that doesn't have support for custom functions or partials to include multiple files for one template which is a must have for front-end developers.

I would like to re-think the way we handle/register templates/views and code a better, solid and a more flexible system that supports custom template functions, partials and caching but still support different template engines like amber, handlebars, mustache or pug.

Here is a bundled list of other Go frameworks and their template logic for inspiration.

I would love to hear your ideas on how our next template/view syntax should look like and bring it into production 馃挭

@thomasvvugt
Copy link
Contributor

thomasvvugt commented Apr 30, 2020

I really much like the way Laravel implemented their Laravel Blade templating system. It allows code executing in a template, as well as escaping HTML characters to reduce injection attack-surface and has zero overhead to the application.
It's written in PHP, but I like their approach to templating. Personally, I do use Mustache for templating but also miss some features Laravel Blade offers. I'll get back to you about the templating logic implemented by other Go Web Frameworks.

EDIT: Some examples as requested: https://laravel.com/docs/7.x/blade

@harikt
Copy link

harikt commented May 1, 2020

Hey,

About me : I am not a guru in golang, but a php developer. I have played a bit with Beego building website. Also tried buffallo. ie my background.

In expressive now mezzio it tries to bring multiple template engines. The way you mentioned in the fiber template is what it also does behind the scenes. But it also add another feature like namespace and adding multiple paths.

So if you add a path $renderer->addPath('templates/error/', 'error'); then error namespace get preference if you try $content = $renderer->render('error::404'); .

Else it will try looking at multiple locations.

Source : https://github.com/mezzio/mezzio-template

You can see that this is a limited template system that doesn't have support for custom functions or partials to include multiple files for one template which is a must have for front-end developers.

I think we cannot provide a generic way to create custom functions. To my believe this part depends on the templating system the user choose.

May be if we can expose the templating systems object it may help to add custom functions on initialization ?

@thomasvvugt
Copy link
Contributor

Mainly, in-line functions using templating in Go is a difficult job to do just right. Therefore, just like Node, templating commonly has the ability to add Template Functions to a specific template.
I like you approach on having a seperate template directory for server-side errors, I also do this when creating applications as well as a seperate directory for a back-end or commonly nested imports like headers and footers.
However, I don't see the point in having to specify this sub-directory; instead I'd rather see something like this:

$renderer->path('views/', "views");
$content = $renderer->render("views/errors/404.extension", $data);

I also know that @Fenny was working on improving our current templating API, so maybe he has some ideas about Nested templates as well.

@thomasvvugt thomasvvugt added this to To do in Development May 1, 2020
@pharrisee
Copy link

pharrisee commented May 2, 2020

I would think that the renderer should be an interface, take a look at the way Echo and Ship do it for instance.

This would mean that the fiber team can implement out-of-the-box template systems which match the interface, and end users can implement other more esoteric template systems if required.

a simple interface copied from Echo :

// Renderer is the interface that wraps the Render function.
Renderer interface {
    Render(io.Writer, string, interface{}, fiber.Ctx) error
}

A naive implementation for Unrolled/render would look something like:

type Urender struct{
    r *render.Render
}

func (u *Urender) Render(w io.Write, name string, data interface{}, ctx *fiber.Ctx) error{
    i:=ctx.Locals("__template")
    if i != nil{
        return u.HTML(w, name, data, render.HTMLOptions{Layout: i.(string)}) // allow for template overrides
    }

    return u.HTML(w, name, data)
}

Creating an instance of the renderer would look like:

renderer:=&Urender{
    r: render.New(render.Options{
        IsDevelopment: os.Getenv("RUNMODE")=="DEV",
        Directory: "views",
        Layout: "layouts/master",
        Extensions:[]string{".html"},
        Funcs:[]template.FuncMap{
            template.FuncMap:{
                "html": func(s string) template.HTML {
		    return template.HTML(s)
		},
            },
        },
    },
}

@Fenny Fenny moved this from To do to In progress in Development May 3, 2020
@amjadniazi48
Copy link

In think if fiber use twig, it will be great.I am new in fiber,I want to render a template without mustache and with native go "html/template" package is there any example , how to do that?

@Fenny
Copy link
Member Author

Fenny commented May 27, 2020

v1.10.0 contains the new Templates interface, see https://github.com/gofiber/template for examples.

@Fenny Fenny closed this as completed May 27, 2020
Development automation moved this from In progress to Done May 27, 2020
@frederikhors
Copy link

@Fenny is quicktemplate still not supported from v1.10.0?

Is c.SendString(templates.Hello()) the only way today with Fiber?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Development
  
Done
Development

No branches or pull requests

6 participants