Пост Запуск Go в браузере с веб-сборкой (WASM) впервые появился на Qvault.

Если вы знакомы с Go Playground, то знаете, как удобно иметь блокнот Go в браузере. Хотите показать кому-нибудь фрагмент кода? Хотите быстро протестировать синтаксис? Кодовые панели на основе браузера полезны. На этой ноте я создал новую игровую площадку. Самое классное в этой новой игровой площадке то, что она не использует удаленный сервер для запуска кода, а только для его компиляции. Код запускается в вашем браузере с использованием веб-сборки (WASM).

Попробуйте игровую площадку Qvault здесь: https://classroom.qvault.io/#/playground/go

Как это работает?

Когда пользователь нажимает «Выполнить», код (в виде текста) отправляется обратно на наши серверы. Сервер написан на Go. Таким образом, обработчик API выглядит примерно так:

func compileCodeHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	// Get code from params
	type parameters struct {
		Code string
	}
	decoder := json.NewDecoder(r.Body)
	params := parameters{}
	err := decoder.Decode(&params)
	if err != nil {
		respondWithError(w, 500, "Couldn't decode parameters")
		return
	}

	// create file system location for compilation path
	usr, err := user.Current()
	if err != nil {
		respondWithError(w, 500, "Couldn't get system user")
		return
	}
	workingDir := filepath.Join(usr.HomeDir, ".wasm", uuid.New().String())
	err = os.MkdirAll(workingDir, os.ModePerm)
	if err != nil {
		respondWithError(w, 500, "Couldn't create directory for compilation")
		return
	}
	defer func() {
		err = os.RemoveAll(workingDir)
		if err != nil {
			respondWithError(w, 500, "Couldn't clean up code from compilation")
			return
		}
	}()
	f, err := os.Create(filepath.Join(workingDir, "main.go"))
	if err != nil {
		respondWithError(w, 500, "Couldn't create code file for compilation")
		return
	}
	defer f.Close()
	dat := []byte(params.Code)
	_, err = f.Write(dat)
	if err != nil {
		respondWithError(w, 500, "Couldn't write code to file for compilation")
		return
	}

	// compile the wasm
	const outputBinary = "main.wasm"
	os.Setenv("GOOS", "js")
	os.Setenv("GOARCH", "wasm")
	cmd := exec.Command("go", "build", "-o", outputBinary)
	cmd.Dir = workingDir
	stderr, err := cmd.StderrPipe()
	if err != nil {
		respondWithError(w, 500, err.Error())
		return
	}
	if err := cmd.Start(); err != nil {
		respondWithError(w, 500, err.Error())
		return
	}
	stdErr, err := ioutil.ReadAll(stderr)
	if err != nil {
		respondWithError(w, 500, err.Error())
		return
	}
	stdErrString := string(stdErr)
	if stdErrString != "" {
		parts := strings.Split(stdErrString, workingDir)
		if len(parts) < 2 {
			respondWithError(w, 500, stdErrString)
			return
		}
		respondWithError(w, 400, parts[1])
		return
	}
	if err := cmd.Wait(); err != nil {
		respondWithError(w, 500, err.Error())
		return
	}

	// write wasm binary to response
	dat, err = ioutil.ReadFile(filepath.Join(workingDir, outputBinary))
	if err != nil {
		respondWithError(w, 500, err.Error())
		return
	}
	w.Write(dat)
}

Как видите, обработчик просто принимает код в качестве входных данных и отвечает фрагментом байтов WASM.

Что насчет фронтенда?

Передняя часть довольно проста. Во-первых, нам нужно включить официальный исполнитель Go WASM на нашу страницу. Предполагая, что на вашем компьютере установлена ​​версия go, этот файл JavaScript можно найти по адресу:

$(go env GOROOT)/misc/wasm/wasm_exec.js

Затем включите скрипт в тело вашего html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Qvault Classroom - Learn Coding</title>
  </head>
  <body>
    <script src="wasm_exec.js"></script>
  </body>
</html>

Поскольку интерфейс Qvault Classroom написан как одностраничное приложение Vue.js, я создал небольшой модуль es6, который запускает массив байтов WASM и возвращает результат в виде массива строк:

const go = new window.Go();

export default async function runGoWasm(rawData) {
  const result = await WebAssembly.instantiate(rawData, go.importObject);
  let oldLog = console.log;
  let stdOut = [];
  console.log = (line) => {stdOut.push(line);};
  await go.run(result.instance);
  console.log = oldLog;
  return stdOut;
}

Вот и все! Запустить Go в браузере довольно просто 🙂

Спасибо за чтение

Напишите мне в твиттере @wagslane, если у вас есть какие-либо вопросы или комментарии.

Поднимите свою карьеру программиста на новый уровень с курсами Qvault Classroom

Следите за мной на Dev.to: wagslane

Пост Запуск Go в браузере с веб-сборкой (WASM) впервые появился на Qvault.