Go library support for Google Closure templates (Soy)

Andy Hochhaus db02bb38b6 Update rules_go 1 year ago
generator e92a395ea7 Move to code.taxi 1 year ago
test e92a395ea7 Move to code.taxi 1 year ago
.gitignore 3b32930e1a Fix license headers & files 1 year ago
AUTHORS 3b32930e1a Fix license headers & files 1 year ago
BUILD e92a395ea7 Move to code.taxi 1 year ago
CONTRIBUTORS 3b32930e1a Fix license headers & files 1 year ago
LICENSE 792d029517 Initial commit 1 year ago
README.md 23723868d1 Detect correct go protobuf import path 1 year ago
WORKSPACE db02bb38b6 Update rules_go 1 year ago
defs.bzl 171b274c7c First commit on code.taxi 1 year ago
soyotto.go a54b98d224 lint 1 year ago
typedarray.js f3900a1039 Polyfill Uint8Array support 1 year ago

README.md

SoyOtto (alpha)

Overview

SoyOtto provides Go support for Google Closure templates. Most users should prefer robfig/soy as it is written in pure Go.

SoyOtto invokes the JavaScript version of Closure templates from Go using robertkrimen/otto -- a pure Go JavaScript interpreter. This design is inherently slow but provides first class support for all Soy language features (some of which at not supported by robfig/soy).

To provide strong compile time type checking for template parameters, soyotto generates *.go and *.js binding files. These binding files also provide transparent proto.Marshal() -> pbType.deserializeBinary() calls to seamlessly pass template parameters between Go and JS native types. This design comes at a significant performance penalty. For each template invocation, the following steps are required:

  • From Go, call the generated Go template binding function (eg: <TmplName>() or Call<TmplName>())
  • proto.Marshal() parameters (as necessary)
  • vm.Copy() the otto vm
  • invoke the JS binding func (soyotto.<TmplName>())
  • <protoType>.deserializeBinary() parameters (as necessary)
  • evaluate the template
  • return the populated template as a string from JS to Go
  • GC the copied vm

By sharing soy templates between your back-end and front-end you can generate HTML at initial page load (on the back-end) to render quickly in the browser. Then update (a portion of) the page dynamically on the front-end based on user interaction. Combining this pattern with the incremental-dom soy back-end results in a particularly smooth UX.

Benefits of robfig/soy

  • Native Go implementation
  • High performance
  • Quick test/debug cycle via hot reloading of templates

Prefer robfig/soy in the vast majority of cases.

Benefits of soyotto

  • Support for all Closure templates features
    • Contextual autoescaping
    • Strict autoescaping
    • @param support
    • protobuf support
  • Compile time type checking for template parameters
  • Widely tested & used escaping code (uses Google's JS implementation)
  • Very small code base, heavily building on closure templates and otto

Usage

TODO(hochhaus)

Roadmap

Alpha

  • Cleanup naming of bazel targets / generated go packages
  • TODOs
  • Variable name shadowing (both JS & Go) [eg: reserve words, imports/goog.requires, etc]
  • lint/vet/fmt/imports/clang-format the code
  • WORKSPACE deps
  • Finish writing README
  • Convert go generation to use go/ast and go/printer
  • Convert js generation to use otto/ast and printer?
  • Ensure works with standard go tools (without bazel)
  • Document soyotto usage with bazel (rules_closure, rules_go) vs standard go tooling

Beta

Future

  • Deprecate in favor of Google open sourcing their Go soy implementation :)