Фронтенд на Go с использованием библиотеки RUI

от автора

Изначально библиотека RUI разработана для создания клиент-серверных веб приложений на языке go, где вся обработка осуществляется на сервере, а браузер используется только как тонкий клиент.

Однако в последней версии библиотеки (0.10.0) была добавлена поддержка технологии WebAssembly. Теперь стало возможным объединить серверную и клиентскую часть в единый модуль исполняемый в браузере. При этом требуются минимальные изменения в уже существующем проекте использующем библиотеку RUI

В этой статье я покажу как переделать уже существующий проект чтобы его можно было скомпилировать в wasm модуль и запустить его в браузере

Рассматривать данный процесс будем на примере демонстрационного приложения библиотеки RUI.

Для того чтобы подготовить проект в него необходимо внести следующие изменения:

  1. добавить страницу загрузки приложения;

  2. вынести из ресурсов приложения все мультимедиа файлы (графику, видео, аудио);

  3. где необходимо, добавить в ImageView свойство «srcset».

Страница загрузки приложения

Страница загрузки приложения уже добавлена в проект (файл «wasm_exec.html») и выглядит она следующим образом

<!doctype html> <html>  <head>     <meta charset="utf-8">     <title>Go wasm</title> </head>  <body>    <script src="wasm_exec.js"></script>    <script>         if (WebAssembly) {             const go = new Go();             WebAssembly.instantiateStreaming(fetch("demo.wasm"), go.importObject).then((result) => {                 go.run(result.instance);             });         } else {             console.log("WebAssembly is not supported in your browser")         }    </script> </body>  </html> 

Это стандартная методика загрузки wasm модуля. Такой код вы можете увидеть практически в любом проекте на go для WebAssembly. Просто копируйте эту страницу в ваш проект

Код страницы очень простой: он загружает файл «demo.wasm» и запускает его.

Однако возникает вопрос: что за файл «wasm_exec.js» и где его взять?

Файл «wasm_exec.js» это файл из стандартной библиотеки golang. Он используется для согласования типов данных go и WebAssembly. Найти его можно по адресу «$GOROOT/misc/wasm/wasm_exec.js».

ВНИМАНИЕ. Файл «wasm_exec.js» может изменяться. Поэтому если вы переходите на новую версию go, то необходимо обновить и «wasm_exec.js» на вашем веб сервере. Если этого не сделать то wasm модуль может перестать загружаться 

Вынесение из ресурсов приложения всех мультимедиа файлов

Приложение скомпилированное в wasm модуль, по умолчанию, не умеет загружать картинки, видео и аудио из ресурсов приложения. Поэтому их необходимо исключить из модуля и разместить на сервере.

В принципе, данные файлы можно было бы оставить в ресурсах и подключать, например, так

imageView.Set(rui.Source, "data:image/png;base64,"+base64.StdEncoding.EncodeToString(data))

Однако этот способ вызывает жуткие тормоза в Safari и не рекомендуется к использованию (при этом в хроме и мозилле все работает быстро, никаких задержек нет).

Кроме того включение мультимедиа в ресурсы значительно увеличивает размер и так не маленького модуля, что, в свою очередь, увеличивает время загрузки страницы (а это всегда плохо).

Для того чтобы исключить все мультимедиа файлы, в проекте они вынесены в отдельную папку «media» и их включение в ресурсы осуществляется только если целевая платформа не js/wasm. Для всех платформ за исключение js/wasm ресурсы объявляются в файле resources.go

//go:build !wasm  package main  import "embed"  //go:embed resources media var resources embed.FS

А для платформы js/wasm ресурсы объявляются в файле resourcesWasm.go

//go:build wasm  package main  import "embed"  //go:embed resources var resources embed.FS

Добавление в ImageView свойства «srcset»

Библиотека RUI поддерживает возможность использования разных вариантов изображения для различных плотностей пикселей экрана. Для этого в ресурсы приложения включатся несколько версий изображения. Например в рассматриваемом проекте это cat.jpg и cat@2x.jpg, sample.png, sample@2x.png и sample@3x.png. Приложение само анализирует какие версии картинки есть и использует нужную. 

Однако в случае wasm модуля картинки расположены на внешнем сервере и приложение не знает какие версии изображения имеются. Поэтому для платформы wasm необходимо с помощью свойства «srcset» явно задавать список вариантов изображений. Например:

if runtime.GOOS == "js" { imageView.Set(rui.SrcSet, "cat.jpg, cat@2x.jpg") }

В свойстве «srcset» вы должны перечислить через запятую все варианты изображения.

Это все изменения которые необходимо сделать в проекте для поддержки технологии WebAssembly

Компиляция и запуск

Теперь необходимо скомпилировать проект. Для этого переходим в папку проекта и выполняем команду

GOOS=js GOARCH=wasm go build -o demo.wasm

В результате у вас появится файл demo.wasm.

Теперь если вы попытаетесь открыть в браузере wasm_exec.html, то вы увидите пустую страницу, а в консоли браузера следующую ошибку

Access to fetch at ‘file://…/demo.wasm’ from origin ‘null’ has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted.

Этот говорит нам о том, что нам нужен http сервер. Напишем его на go

package main  import (     "fmt"     "log"     "net/http"     "os" )  var projectPath = "<your path>/ruiDemo"  func main() {     http.HandleFunc("/", server)     log.Fatal(http.ListenAndServe("localhost:8080", nil)) }  func server(w http.ResponseWriter, req *http.Request) {     switch req.Method {     case "GET":         fmt.Print(req.URL.Path)          switch req.URL.Path {         case "/", "/wasm_exec.html":             http.ServeFile(w, req, projectPath+"/wasm_exec.html")          case "/demo.wasm", "/wasm_exec.js":             http.ServeFile(w, req, projectPath+req.URL.Path)          default:             path := projectPath + "/media/images" + req.URL.Path             if _, err := os.Stat(path); err == nil {                 http.ServeFile(w, req, path)                 return             }             path = projectPath + "/media/raw" + req.URL.Path             http.ServeFile(w, req, path)         }     } }

После запуска данного сервера и перехода в браузере по адресу «localhost:8080» вы должны увидеть демо приложение библиотеки RUI

И в конце об одной проблеме с которой вы можете столкнуться если в качестве сервера будете использовать nginx или Apache. Если зальете данное приложение на данные сервера и попробуете открыть, то с большой вероятностью вы увидите пустой экран, а в консоле браузера ошибку:

Uncaught (in promise) TypeError: Failed to execute ‘compile’ on ‘WebAssembly’: Incorrect response MIME type. Expected ‘application/wasm’

Для решения этой проблемы необходимо прописать в настройках сервера для файлов с расширением «wasm» mime-тип «application/wasm»

На этом все


ссылка на оригинал статьи https://habr.com/ru/articles/698818/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *