Шаблоны в Go: text/template, html/template и Templ
Шаблоны в Go представляют собой один из ключевых инструментов для создания динамического контента — от простых консольных сообщений до сложных веб-интерфейсов. В основе их работы лежит фундаментальный принцип разделения логики приложения и представления данных, что позволяет разработчикам создавать более поддерживаемый и масштабируемый код.

Когда мы говорим о шаблонах в контексте Go, речь идет прежде всего о двух стандартных пакетах: text/template для работы с текстовыми данными и html/template для генерации HTML-контента с встроенной защитой от XSS-атак. Эти инструменты решают широкий спектр задач — от формирования электронных писем и документов до создания полноценных веб-страниц с динамическим содержимым.
Однако по мере развития экосистемы Go появляются и альтернативные решения. Современные шаблонизаторы, такие как Templ, предлагают новые подходы к работе с шаблонами, включая статическую типизацию и компонентную архитектуру. В данной статье мы рассмотрим как классические подходы к шаблонизации в Go, так и современные альтернативы, которые могут значительно улучшить процесс разработки.
- Что такое шаблоны и зачем они нужны
- Основные пакеты Go для работы с шаблонами
- Базовые сущности шаблонов в Go
- Управление шаблонами и функции
- Шаблоны в веб-приложениях
- Ограничения стандартных шаблонов Go
- Современная альтернатива: Templ
- Заключение
- Рекомендуем посмотреть курсы по golang разработке
Что такое шаблоны и зачем они нужны
Статические и динамические страницы
В мире веб-разработки существует четкое разграничение между статическими и динамическими страницами, которое напрямую влияет на выбор инструментов для их создания. Статические HTML-страницы представляют собой неизменяемый контент — например, страница «О компании» или пользовательское соглашение. Такие страницы формируются один раз и хранятся на сервере в готовом виде, что обеспечивает максимальную скорость загрузки.

Сравнение статических и динамических страниц: первые неизменны и хранятся на сервере, вторые генерируются при каждом запросе. Такой визуальный контраст помогает понять, где шаблоны особенно полезны.
Динамические страницы, напротив, генерируются в момент запроса и содержат актуальную информацию, которая может изменяться в зависимости от контекста. Представьте видео-платформу с каталогом фильмов — список доступного контента постоянно обновляется, появляются новые релизы, изменяется статус просмотра для конкретного пользователя. В этом случае веб-приложение должно взять базовый шаблон страницы и подставить в него актуальные данные из базы данных.
Основные задачи шаблонов
Шаблонизация решает несколько ключевых задач современной веб-разработки. Во-первых, это динамическая вставка данных в HTML-разметку — процесс, который позволяет одному и тому же шаблону отображать различный контент в зависимости от переданных параметров. Вместо создания отдельной HTML-страницы для каждого пользователя, мы используем единый шаблон профиля, подставляя в него имя, электронную почту и другие персональные данные.
Второй важный аспект — повторное использование кода. Шаблоны позволяют создавать переиспользуемые компоненты интерфейса, такие как заголовки страниц, навигационные меню или карточки товаров. Это значительно упрощает поддержку кодовой базы и обеспечивает консистентность дизайна.
Наконец, при работе с HTML-контентом критически важна безопасность. Пакет html/template автоматически экранирует пользовательский ввод, предотвращая XSS-атаки и другие виды инъекций. Это означает, что даже если злоумышленник попытается вставить вредоносный JavaScript-код через форму комментария, шаблонизатор преобразует его в безопасный текст.
Основные пакеты Go для работы с шаблонами
text/template
Пакет text/template представляет собой универсальный инструмент для работы с текстовыми данными любого формата. Его основное назначение — генерация структурированного текста на основе данных приложения. Мы можем использовать этот пакет для создания конфигурационных файлов, электронных писем, отчетов или даже SQL-запросов.

Страница официальной документации Go для пакета text/template
Функциональность пакета включает все необходимые элементы для создания сложных шаблонов: подстановку переменных через синтаксис {{ .FieldName }}, условные конструкции if-else, циклы range для обработки массивов и срезов, а также возможность определения пользовательских функций. Важно отметить, что text/template работает исключительно с текстовыми данными и не предоставляет никаких специфических механизмов защиты — вся ответственность за безопасность лежит на разработчике.
html/template
Пакет html/template построен на основе text/template, но имеет специализированное назначение — создание HTML-контента для веб-приложений. Ключевое отличие заключается в автоматической защите от различных видов атак, включая межсайтовое скриптование (XSS).
Когда мы используем html/template, все пользовательские данные автоматически экранируются в зависимости от контекста их использования. Например, если пользователь попытается ввести в комментарий код <script>alert(‘XSS’)</script>, шаблонизатор преобразует его в безопасный текст <script>alert(‘XSS’)</script>. Эта защита работает контекстуально — данные, вставляемые в HTML-атрибуты, JavaScript-код или CSS, обрабатываются по-разному.
Интеграция с net/http делает html/template естественным выбором для создания веб-серверов на Go. Шаблоны можно легко встраивать в HTTP-обработчики, передавая результат рендеринга напрямую в ResponseWriter. Такой подход обеспечивает эффективную работу с веб-трафиком и позволяет создавать масштабируемые веб-приложения с минимальными накладными расходами.
Базовые сущности шаблонов в Go
Actions (действия)
Actions представляют собой фундаментальный элемент любого Go-шаблона — это фрагменты кода, заключенные в двойные фигурные скобки {{ }}, внутри которых выполняется вычисление или подстановка данных. Именно через действия статический текст превращается в динамический контент.
Внутри действий мы можем размещать различные конструкции: простые переменные {{ .Name }}, вызовы функций {{ len .Items }}, арифметические операции или даже сложные выражения с несколькими операндами. Важно понимать, что все действия выполняются в контексте переданных в шаблон данных — точка . всегда ссылается на корневой объект.
Условия (if)
Условные конструкции в Go-шаблонах следуют привычной логике if-else, но имеют свои особенности синтаксиса. Базовая форма выглядит как {{ if condition }} … {{ else }} … {{ end }}, где каждый блок должен быть явно закрыт оператором end.
{{ if eq .Status "active" }} Пользователь активен {{ else }} Пользователь заблокирован {{ end }}
Для сравнения значений используются специальные функции: eq (равенство), ne (неравенство), lt (меньше), gt (больше). Альтернативно можно передавать булевы значения напрямую: {{ if .IsLoggedIn }}.
Циклы (range)
Цикл range позволяет перебирать коллекции данных — массивы, срезы или карты. Базовый синтаксис: {{ range .Items }} {{ . }} {{ end }}, где внутри цикла точка ссылается на текущий элемент.
Для более сложных сценариев доступен расширенный синтаксис с переменными:
{{ range $index, $item := .Products }} {{ if $index }}, {{ end }}{{ $item.Name }} {{ end }}
Переменные в шаблонах
Шаблоны Go поддерживают создание локальных переменных через оператор присваивания := с префиксом доллара. Переменные существуют только в рамках текущего блока и могут использоваться для промежуточных вычислений:
{{ $userName := .User.FirstName }} {{ $greeting := "Привет" }} {{ $greeting }}, {{ $userName }}!
Управление пробелами
Маркеры обрезки {{- и -}} позволяют контролировать пробельные символы вокруг действий. Левый маркер {{- удаляет пробелы слева от действия, правый -}} — справа. Это особенно полезно при генерации компактного HTML или форматированного текста, где важен точный контроль над отступами и переносами строк.
Управление шаблонами и функции
Основные методы (New, Parse, Execute)
Жизненный цикл работы с шаблонами в Go строится вокруг трех ключевых методов, каждый из которых выполняет определенную роль в процессе подготовки и выполнения шаблона. Метод New создает новый экземпляр шаблона с указанным именем — это своеобразная заготовка, которую предстоит наполнить содержимым.

Схема показывает последовательность действий при работе с шаблоном. Такой наглядный формат помогает быстро уловить логику взаимодействия методов.
Метод Parse анализирует строку с текстом шаблона и преобразует ее в внутреннее представление, готовое к исполнению. На этом этапе происходит синтаксический разбор всех действий, условий и циклов. Если в шаблоне обнаруживаются ошибки синтаксиса, они будут выявлены именно на стадии парсинга, а не во время выполнения.
template := template.New("example").Parse("Привет, {{ .Name }}!")
Финальный этап — метод Execute, который применяет подготовленный шаблон к конкретным данным и записывает результат в указанный io.Writer. Этот метод может вызываться многократно с различными наборами данных, что делает шаблоны переиспользуемыми.
Работа с файлами (ParseFiles)
В реальных проектах шаблоны редко хранятся прямо в коде — гораздо практичнее выносить их в отдельные файлы. Метод ParseFiles позволяет загружать шаблоны из файловой системы, что обеспечивает лучшую организацию проекта и упрощает совместную работу дизайнеров и разработчиков.
tmpl, err := template.ParseFiles("templates/header.html", "templates/content.html")
Такой подход позволяет создавать модульную архитектуру шаблонов, где различные части страницы хранятся в отдельных файлах и могут комбинироваться по мере необходимости.
Пользовательские функции (FuncMap)
Одной из мощных возможностей Go-шаблонов является расширение функциональности через пользовательские функции. Метод Funcs принимает template.FuncMap — карту, которая связывает имена функций в шаблоне с их реализацией в Go-коде:
funcMap := template.FuncMap{ "add": func(a, b int) int { return a + b }, "formatDate": func(t time.Time) string { return t.Format("02.01.2006") }, } tmpl := template.New("calc").Funcs(funcMap).Parse("{{ add 5 3 }}")
Это позволяет выносить сложную логику обработки данных из шаблонов в Go-код, сохраняя при этом гибкость использования результатов в разметке.
Шаблоны в веб-приложениях
Интеграция с net/http
Интеграция шаблонов с пакетом net/http представляет собой естественный способ создания веб-серверов на Go. В основе этого подхода лежит передача результата рендеринга шаблона напрямую в http.ResponseWriter, что обеспечивает эффективную обработку HTTP-запросов.
Типичный HTTP-обработчик с использованием шаблонов выглядит следующим образом:
func profileHandler(w http.ResponseWriter, r *http.Request) { tmpl := template.Must(template.ParseFiles("profile.html")) data := UserData{Name: "Алексей", Email: "alex@example.com"} tmpl.Execute(w, data) }
Функция template.Must оборачивает вызов ParseFiles и автоматически вызывает panic в случае ошибки парсинга — это удобно для инициализации шаблонов на старте приложения, когда критические ошибки должны приводить к немедленной остановке.
Организация структуры проекта
Правильная организация файловой структуры проекта критически важна для поддержания порядка в шаблонах. Стандартной практикой является создание отдельной директории templates/ в корне проекта, где хранятся все файлы шаблонов:
. ├── main.go ├── templates/ │ ├── layout.html │ ├── profile.html │ └── film-list.html └── static/ ├── css/ └── js/
Такая структура позволяет четко разделить серверную логику, шаблоны представления и статические ресурсы. При работе с ParseFiles мы можем загружать как отдельные шаблоны, так и группы связанных файлов.

Иллюстрация демонстрирует стандартное разделение проекта на код, шаблоны и статические ресурсы. Такая организация делает кодовую базу более поддерживаемой и понятной для команды.
Пример простого веб-приложения
Рассмотрим полный пример веб-приложения, демонстрирующего работу с шаблонами. Создадим сервер, который отображает список фильмов с возможностью отметки просмотренных:
package main import ( "html/template" "net/http" "log" ) type Film struct { Title string IsViewed bool } func main() { films := []Film{ {"Побег из Шоушенка", true}, {"Крестный отец", false}, } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { tmpl := template.Must(template.ParseFiles("templates/films.html")) tmpl.Execute(w, films) }) log.Println("Сервер запущен на :8080") http.ListenAndServe(":8080", nil) }
Соответствующий файл templates/films.html:
<!DOCTYPE html>
<html> <head><title>Фильмы</title></head> <body> <h1>Каталог фильмов</h1> {{ range . }} <div> <h3>{{ .Title }}</h3> {{ if .IsViewed }}✅{{ else }}❌{{ end }} </div> {{ end }} </body> </html> |
Ограничения стандартных шаблонов Go
Несмотря на универсальность и надежность стандартных пакетов text/template и html/template, они имеют ряд фундаментальных ограничений, которые становятся особенно заметными в крупных проектах или высоконагруженных системах.

На диаграмме показано условное сравнение производительности трёх инструментов. Templ демонстрирует преимущество благодаря статической генерации, тогда как стандартные пакеты работают медленнее.
Производительность: парсинг и компиляция шаблонов
Хотя пакеты text/template и html/template действительно анализируют и интерпретируют шаблоны, в реальных приложениях на Go эта операция обычно выполняется только один раз — на старте программы. Разработчики используют такие подходы, как кэширование с помощью template.Must(template.ParseGlob(…)), чтобы избежать повторного парсинга при каждом запросе. Таким образом, накладные расходы на парсинг и построение внутреннего дерева представления возникают только при запуске, а не во время обработки запросов.
Проблема «интерпретации на лету» и связанные с ней накладные расходы становятся актуальными, только если шаблоны парсятся при каждом HTTP-запросе, что является анти-паттерном и не рекомендуется для высоконагруженных систем.
В этом контексте, Templ предлагает альтернативный подход: он полностью исключает этап интерпретации во время выполнения, так как компилирует шаблоны в обычный Go-код на этапе сборки. Это делает его особенно привлекательным для проектов, где важна абсолютная производительность и минимальные задержки при обработке запросов..
Отсутствие статической типизации
Возможно, наиболее болезненным ограничением является отсутствие проверки типов на этапе компиляции. Если мы передаем в шаблон структуру User, но пытаемся обратиться к несуществующему полю {{ .NonExistentField }}, **ошибка будет обнаружена только во время выполнения, и поле просто будет проигнорировано**, что приведет к неполноценному отображению страницы.
Сложность переиспользования и тестирования
Хотя стандартные шаблоны Go поддерживают включение вложенных шаблонов для создания переиспользуемых частей, их архитектура менее гибкая и строгая, чем у современных компонентных фреймворков. Это может затруднять создание сложных библиотек UI-компонентов и их тестирование.
Ограниченная выразительность синтаксиса
Хотя Go-шаблоны поддерживают базовые конструкции программирования, их синтаксис остается довольно примитивным по сравнению с современными шаблонизаторами других языков. Отсутствие продвинутых возможностей, таких как композиция компонентов или декларативное описание состояний, ограничивает возможности создания сложных пользовательских интерфейсов.
Современная альтернатива: Templ
Что такое Templ
Templ представляет собой кардинально иной подход к шаблонизации в Go, основанный на принципе генерации статического кода вместо интерпретации во время выполнения. Этот инструмент компилирует шаблоны в обычный Go-код, который затем становится частью приложения и проверяется компилятором наравне с остальной кодовой базой.
Синтаксис Templ напоминает JSX из мира React, что делает его интуитивно понятным для разработчиков с опытом фронтенд-разработки. Однако за знакомым синтаксисом скрывается полноценная интеграция с типовой системой Go — все переменные и функции проверяются на этапе компиляции.
Преимущества Templ
Производительность через статическую генерацию. Поскольку Templ генерирует обычный Go-код, отсутствуют накладные расходы на парсинг и интерпретацию шаблонов во время выполнения. Результирующий код работает с той же скоростью, что и любой другой скомпилированный Go-код.
Статическая типизация и безопасность. Все обращения к полям структур и вызовы функций проверяются компилятором Go. Если мы попытаемся обратиться к несуществующему полю {{ user.NonExistentField }}, получим ошибку компиляции, а не runtime-панику.
Компонентный подход. Templ поддерживает создание переиспользуемых компонентов с явно определенными интерфейсами. Каждый компонент — это обычная Go-функция с проверяемыми типами параметров:
templ UserCard(user User) {
<div class=»user-card»> <h3>{ user.Name }</h3> <p>{ user.Email }</p> </div> } |
Пример использования
Рабочий процесс с Templ состоит из нескольких этапов. Сначала мы определяем компонент в файле с расширением .templ:
templ FilmList(films []Film) {
<div class=»film-container»> for _, film := range films { <div class=»film-card»> <h3>{ film.Title }</h3> if film.IsViewed { <span class=»status viewed»>Просмотрено ✅</span> } else { <span class=»status»>Не просмотрено ❌</span> } </div> } </div> } |
Затем выполняем команду templ generate, которая создает соответствующий Go-файл с функцией, реализующей интерфейс templ.Component. Полученный компонент можно использовать в обычном HTTP-обработчике:
func filmsHandler(w http.ResponseWriter, r *http.Request) {
films := getFilmsFromDB() component := FilmList(films) component.Render(context.Background(), w) } |
Такой подход объединяет лучшие качества статической типизации Go с удобством современных шаблонизаторов, создавая мощный инструмент для разработки веб-приложений.
Заключение
При выборе между различными подходами к шаблонизации в Go необходимо учитывать специфику конкретного проекта и его требования. Стандартные пакеты остаются надежным выбором для большинства сценариев использования, особенно когда речь идет о небольших и средних приложениях с умеренной нагрузкой. Подведем итоги:
- Шаблоны в Go отделяют логику от представления. Это повышает читаемость и упрощает поддержку.
- text/template решает задачи генерации текста. Это удобно для писем, конфигов и отчетов.
- html/template добавляет XSS-безопасность. Это делает вывод HTML надежным в веб-приложениях.
- Условия, циклы и переменные дают гибкость. Это позволяет динамически формировать содержимое.
- FuncMap расширяет возможности шаблонов. Это переносит сложную логику в Go-код.
- Грамотная структура папок упорядочивает проект. Это ускоряет командную работу и ревью.
- Templ компилирует шаблоны в код. Это повышает производительность и типобезопасность.
Если вы только начинаете осваивать профессию Go-разработчика, рекомендуем обратить внимание на подборку курсов по Go-программированию. В них есть теоретическая и практическая часть, чтобы быстрее закрепить работу с шаблонами и применить её в реальных задачах.
Рекомендуем посмотреть курсы по golang разработке
Курс | Школа | Цена | Рассрочка | Длительность | Дата начала | Ссылка на курс |
---|---|---|---|---|---|---|
Искусство написания сервиса на Go
|
GOLANG NINJA
13 отзывов
|
Цена
38 565 ₽
92 096 ₽
|
|
Длительность
5 месяцев
|
Старт
в любое время
|
Ссылка на курс |
Программирование на Go
|
Stepik
33 отзыва
|
Цена
4 400 ₽
|
|
Длительность
|
Старт
7 октября
|
Ссылка на курс |
Go-разработчик
|
Нетология
43 отзыва
|
Цена
с промокодом kursy-online
105 500 ₽
185 000 ₽
|
От
3 083 ₽/мес
0% на 36 месяцев
8 041 ₽/мес
|
Длительность
6 месяцев
|
Старт
25 октября
2 раз в неделю после 18:00 МСК
|
Ссылка на курс |
Искусство работы с ошибками и безмолвной паники в Go
|
GOLANG NINJA
13 отзывов
|
Цена
26 545 ₽
39 620 ₽
|
|
Длительность
9 недель
|
Старт
в любое время
|
Ссылка на курс |

Препресс: почему без него даже лучший макет может провалиться
Что скрывается за этапом препресса и почему без него макет может превратиться в головную боль? Расскажем, как не потерять качество на пути от дизайна до печати.

Что такое Tableau и зачем он нужен в 2025 году
Что такое Tableau, зачем она нужна бизнесу и как с её помощью сократить время на аналитику? Разбираем простым языком для начинающих и продвинутых пользователей.

Что такое операционная система и зачем она нужна
Операционная система — это сердце любого устройства. Разберёмся, какие функции выполняет ОС, почему она так важна для работы техники, и как грамотно выбирать между разными платформами.

Собрать робота своими руками: пошаговый план
В статье покажем, как сделать робота даже тем, кто последний раз держал паяльник в школе. Пошагово, с объяснениями и без занудства.