Edited at

GAE/GoでPugを使おうとしてちょっとハマった

More than 1 year has passed since last update.


GoでPugを使う

Go(GAE)でちょっとしたHTMLを返すアプリを作っているんですが、生HTML書きたくないのとhtml/templateは避けたいのでPugのライブラリをさわってみました。


Pug(Jade)ライブラリ

いくつかあるっぽいですが、以下の2つがメジャー?なようでした。

前者の方がPugとしての機能は充実してそうなんですが、今回そんなに複雑な機能はいらないのと、I/Fが後者の方がシンプルでこれで十分だなって思えたのでそちらを使うことにしました。


*.pugファイルへのpath

若干はまりました。

GAE+dupで開発しており、GOPATH以下にgoのソースをおいて、app.yamlがあるディレクトリにはmain.goのみ、という構成にしていたので*.pugファイルもGOPATH以下におこうとしてました。

pug.CompileFileの第二引数でdirを指定できるのでそれでやろうとしたのですが、GAEだとうまくいかなかったです。

import (

"net/http"
"path/filepath"

"github.com/eknkc/pug"
"github.com/eknkc/pug/compiler"
)

func Render(w http.ResponseWrite) error {
path, err := filepath.Abs("../lib/view")
if err != nil {
return err
}
t, err := pug.CompileFile("index.pug", pug.Options{Dir: compiler.FsDir(path)})
if err != nil {
return err
}

params := map[string]string{
Key1: "foo",
Key2: "bar",
}
if err := t.Execute(w, params); err != nil {
return err
}
return nil
}

compiler.FsDir../みたいのをうけつけないので、filepath.Absで絶対パスを渡してあげます。

これだとlocalでdev_appserver.pyとかする分には動きます。

ただdeployすると、index.pugにpermissionがないっていわれてエラーになってしまいます。

これはGAEだと読み込めるpathが制限されているからです。

app.yamlがあるディテクトリ以下のファイルしか開けないようなので、そちらにviewディレクトリを作るようにします。

  path, err := filepath.Abs("view")

if err != nil {
return err
}
t, err := pug.CompileFile("index.pug", pug.Options{Dir: compiler.FsDir(path)})
if err != nil {
return err
}

最初こんな感じで絶対パスにしてたんですが、これだとapp.yaml以下であってもpermission errorになってしまい、動きませんでした。

絶対パスだと有無をいわさずダメっぽいですね。(documentに書いてありそうですがみつけられておらず…)

そもそも絶対パスは最早不要なので、素直にmain.goからのpathを渡すようにします。

import (

"net/http"

"github.com/eknkc/pug"
)

func Render(w http.ResponseWrite) error {
t, err := pug.CompileFile("view/index.pug")
if err != nil {
return err
}

params := map[string]string{
Key1: "foo",
Key2: "bar",
}
if err := t.Execute(w, params); err != nil {
return err
}
return nil
}

全体はこんな感じに。

だいぶスッキリしましたね!

これでGAE上でpugをrenderできるようになりました。