Склеивание файлов HTML, CSS и JavaScript в исполняемый файл приложения Go

Склеивание файлов HTML, CSS и JavaScript в исполняемый файл приложения Go
Недавно я работал над приложением на языке Go. Это веб-приложение, которое я планирую продавать. Однако мне не хочется отдавать при этом сотни файлов, а обойтись по возможности одним исполняемым файлом. Это приложение имеет API, построенный на Go, и фронтенд на Angular, взаимодействующий с этим API. И так я начал искать способы склеить все файлы приложения в один финальный бинарник.

Есть несколько подобных утилит, среди популярных: go-bindata, go-bindata-assetfs и go.rice. У меня получилось всё сделать с go.rice, поэтому я и опишу это здесь.

Хотя я разрабатываю приложение на Go и Angular, думаю, что для примера это будет очень сложно. Вместо этого мы построим простенькую программу, использующую Golang, HTML, CSS и JavaScript.

Создание проекта и установка зависимостей

Перед тем, как приступить к разработке, убедитесь, что у вас установлен дистрибутив Go и настроены необходимые переменные среды. Создайте папку myproject и приступим.

Этот проект должен состоять из следующих файлов и папок:

touch main.go
mkdir website
touch website/index.html
touch website/custom.css
touch website/app.js

Если у вас нет команд mkdir и touch, просто создайте файлы вручную.
Установим зависимости:

go get github.com/GeertJohan/go.rice
go get github.com/GeertJohan/go.rice/rice
go get github.com/gorilla/mux

Библиотека mux облегчает работу с роутами, но вы можете работать и без неё.

А теперь приступим к разработке приложения.

Разработка приложения

Начнём с разработки веб-части приложения.
Откройте файл website/custom.css и вставьте в него следующие стили:

.container {
width: 400px;
height: 100px;
background-color: #009ACD;
margin: auto;
}

.text {
position: relative;
top: 50%;
transform: translateY(-50%);
text-align: center;
color: #FFFFFF;
}

Здесь у нас цветной контейнер с выровненным по вертикали текстом.
Теперь откройте файл website/app.js и вставьте следующий JavaScript код:

document.getElementById("text").innerHTML = "Hello World

Created by Nic Raboy

";

Здесь наш код найдёт элемент с идентификатором text и заполнит его HTML разметкой. Теперь свяжем их в несложном HTML файле. Откройте файл website/index.html и вставьте следующую разметку:



The Polyglot Developer



Теперь перейдём к коду на Go. В нашем приложении нет конечных точек API, но их несложно добавить при желании. Откройте файл main.go и вставьте следующий код:

package main

import (
"log"
"net/http"

"github.com/GeertJohan/go.rice"
"github.com/gorilla/mux"
)

func main() {
router := mux.NewRouter()
router.PathPrefix("/").Handler(http.FileServer(rice.MustFindBox("website").HTTPBox()))
log.Fatal(http.ListenAndServe(":12345", router))
}

Самая важная строка здесь — та, где мы работаем с компонентом go.rice. Мы говорим приложению, что хотим чтобы наши статические файлы из папки website сохранились и были бы доступны из корневой директории нашего приложения. То есть при запуске приложения мы могли получить к ним доступ по адресу http://localhost:12345/.

Но мы не закончили на этом. Мы-то знаем где находятся наши файлы, но приложение пока не может их прочитать. Для этого нам необходимо склеить их в единый Go файл, который можно будет собрать.

Сборка приложения

Пакет go.rice работает следующим образом: он смотрит наш исходный код в поисках метода MustFindBox. Затем он находит папку website и понимает, что мы хотим встроить содержимое этой папки в наше приложение.

Но для сборки приложения нам нужна отдельная утилита и go build тут не подойдёт.

Запустим её

rice embed-go
Если у вас система не обнаружила такой команды, добавьте папку с приложениями Go в переменную PATH и перезапустите окно консоли:

export PATH=$PATH:$GOPATH/bin
Итак, у нас появился файл rice-box.go:

package main

import (
"github.com/GeertJohan/go.rice/embedded"
"time"
)

func init() {

// define files
file2 := &embedded.EmbeddedFile{
Filename: `app.js`,
FileModTime: time.Unix(1489834507, 0),
Content: string("document.getElementById(\"text\").innerHTML = \"Hello World

Created by Nic Raboy

\";"),
}
file3 := &embedded.EmbeddedFile{
Filename: `custom.css`,
FileModTime: time.Unix(1489834495, 0),
Content: string(".container {\r\n width: 400px;\r\n height: 100px;\r\n background-color: #009ACD;\r\n margin: auto;\r\n}\r\n \r\n.text {\r\n position: relative;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n text-align: center;\r\n color: #FFFFFF;\r\n}"),
}
file4 := &embedded.EmbeddedFile{
Filename: `index.html`,
FileModTime: time.Unix(1489834522, 0),
Content: string("\r\n\r\nThe Polyglot Developer\r\n\r\n\r\n\r\n

\r\n

\r\n

\r\n \r\n\r\n"),
}

// define dirs
dir1 := &embedded.EmbeddedDir{
Filename: ``,
DirModTime: time.Unix(1489834345, 0),
ChildFiles: []*embedded.EmbeddedFile{
file2, // app.js
file3, // custom.css
file4, // index.html

},
}

// link ChildDirs
dir1.ChildDirs = []*embedded.EmbeddedDir{}

// register embeddedBox
embedded.RegisterEmbeddedBox(`website`, &embedded.EmbeddedBox{
Name: `website`,
Time: time.Unix(1489834345, 0),
Dirs: map[string]*embedded.EmbeddedDir{
"": dir1,
},
Files: map[string]*embedded.EmbeddedFile{
"app.js": file2,
"custom.css": file3,
"index.html": file4,
},
})
}

Довольно любопытный код, да? В нём хранится информация обо всех файлах в папке website. И когда мы соберём наше приложение, в нашем бинарнике будут хранится все необходимые файлы. Круто!

Текст основан на материалах из Bundle HTML, CSS, And JavaScript To Be Served In A Golang Application

Склеивание файлов HTML, CSS и JavaScript в исполняемый файл приложения Go

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Пишите: @ighar. Buy me a coffee, please :).

Leave a Comment

Чтобы не пропустить новые статьи, оставь свой Email

Поздравляем вы подписаны на новости ТехноДжем!

TВо время отправки данных произошла ошибка. Попробуйте ещё раз

Оставляя свою почту