Как работать с html в golang

Решил написать веб-приложение на golang и столкнулся с вопросом, как правильно работать с html страницами.

Когда пробовал что-то похожее написать на Python, то там создавал base.html, где задавалась общая структура страницы и там где разметка страницы должна меняться, создавал блоки. Далее, подключал base.html вначале другой страницы (например index.html) и добавлял контент в указанные блоки.

Попробовал так же сделать на golang. Создал простой base.html

{{ define "base"}}

<!DOCTYPE html>
<html lang="en">
<head>
      <title>
        {{block "title" .}} 

        {{end}}
      </title>
</head>
<body>
   {{block "content" .}}

   {{ end }}
</body>
</html>
{{ end }}

и index.html

{{ define "index" }}

{{ template "header" .}}
{{ define "title" }}
Home
{{ end }}

{{ define "content" }}
<h1> Content </h1>
{{ end }}

{{ end }}

В самом golang вызываю следующую функцию:

func Index(w http.ResponseWriter, r *http.Request) {

    t, err := template.ParseFiles("templates/base.html", "templates/index.html")
    if err != nil {
        log.Println("%v : [WARNING] %v", time.Now(), err)
    }
    err = t.ExecuteTemplate(w, "index", data)
    if err != nil {
        log.Println("%v : [ERROR] %v", time.Now(), err)
    }
}

При запуске приложения и загрузки страницы в консоль выдаёт следующие ошибки
template: index.html:4: unexpected define in command
template: index.html:4: unexpected define in command
runtime error: invalid memory address or nil pointer dereference

Подскажите, в чём может быть ошибка и правильно ли так делать в golang. Гуглил, но ничего толкового не нашёл.

Разобрался с ошибками. Заменил

{{ define "title" }}
Home
{{ end }}

на

{{ block "title" .}}
Home
{{end}}

Страницы открывается, всё работает.


Ответы (1 шт):

Автор решения: Сергей Коновалов

Нельзя использовать в одном файле два и более define, лучше только один. Define это связывание строковой константы и кода шаблона. Включение дефайнов друг в друга вызовет ошибку.

Отвечая на вопрос "как лучше делать", я бы посоветовал следующее:

1) использовать github.com/valyala/fasthttp вместо net/http. Данный пакет намного производительней

2) подумать над роутингом, я использую github.com/buaazp/fasthttprouter

3) организовать что-то вроде лайт MVC, когда каждый урл обрабатывается отдельной функцией, я лично использую в связке с fasthttp такую конструкцию

func RunController(controller func(ctx *fasthttp.RequestCtx)) func(ctx *fasthttp.RequestCtx) {
    return func(ctx *fasthttp.RequestCtx) {
        setDefaultHeaders(ctx)
        controller(ctx)
    }
}

функция выше принимает в качестве параметра другую функцию (контроллер), выполняет некий middleware код и выполняет уже сам контроллер.

а в связке с fasthttprouter это работает так

router.GET("/user", RunController(User))

func User(ctx *fasthttp.RequestCtx) {
    //получаем некие данные
    interactor := components.GetInteractor()
    users, _ := interactor.UserRep.GetAll()
    data := map[string]interface{}{
        "users": users,
    }
    //рисуем наш Html
    components.ExecuteTemplate(ctx, "user/user.html", data)
}

4) не парсить шаблоны при каждом вызове контроллера (функции Index в вашем случае)

→ Ссылка