Склеивание файлов 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<br /><p>Created by Nic Raboy</p>";

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

<html>
    <head>
        <title>The Polyglot Developer</title>
        <link rel="stylesheet" href="custom.css" />
    </head>
    <body>
        <div class="container">
            <p id="text" class="text"></p>
        </div>
        <script src="app.js"></script>
    </body>
</html>


Теперь перейдём к коду на 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 сохранились и были бы доступны из корневой директории нашего приложения. То есть при запуске приложения мы могли получить к ним доступ по адресу 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<br /><p>Created by Nic Raboy</p>\";"),
	}
	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("<html>\r\n    <head>\r\n        <title>The Polyglot Developer</title>\r\n        <link rel=\"stylesheet\" href=\"custom.css\" />\r\n    </head>\r\n    <body>\r\n        <div class=\"container\">\r\n            <p id=\"text\" class=\"text\"></p>\r\n        </div>\r\n        <script src=\"app.js\"></script>\r\n    </body>\r\n</html>"),
	}

	// 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
0 комментариев
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.