Embed templates and statics into package (#48)

* Embed templates and statics into package
* Make mbtileserver 'go get'-able
This commit is contained in:
Fabian Wickborn 2017-11-15 16:32:37 +01:00 committed by Brendan Ward
parent 6eafd14c6a
commit b7e662d704
15 changed files with 411 additions and 17 deletions

View File

@ -34,10 +34,14 @@ virtual machine without any issues.
## Installation
Currently, this project is not `go get`-able because static assets and
templates are not downloaded via `go get`. We're working toward this.
You can install this project with
```sh
go get github.com/consbio/mbtileserver
```
This will create and install an executable called `mbtileserver`.
In the meantime, clone this repository using your `git` tool of choice.
This uses `Govendor` tool, so dependencies ship with the repo for easier builds.
@ -49,16 +53,12 @@ Dependencies:
* [github.com/Sirupsen/logrus](https://github.com/Sirupsen/logrus)
* [golang.org/x/crypto/acme/autocert](https://golang.org/x/crypto/acme/autocert)
Development Dependencies (only needed when modifying the code):
* [github.com/shurcooL/vfsgen](https://github.com/shurcooL/vfsgen)
On Windows, it is necessary to install `gcc` in order to compile `mattn/go-sqlite3`.
MinGW or [TDM-GCC](https://sourceforge.net/projects/tdm-gcc/) should work fine.
Then build it:
```
go build .
```
This will create an executable called `mbtileserver`.
If you experience very slow builds each time, it may be that you need to first run
```
@ -69,9 +69,9 @@ to make subsequent builds much faster.
## Usage
From within the repository root:
From within the repository root ($GOPATH/bin needs to be in in your $PATH):
```
$ ./mbtileserver --help
$ mbtileserver --help
Serve tiles from mbtiles files.
Usage:
@ -203,7 +203,6 @@ See the issues tagged to the [0.5 version](https://github.com/consbio/mbtileserv
for our near term features and improvements.
In short, we are planning to:
* make this project `go get`-able
* add tests and benchmarks
* get things production ready
@ -212,7 +211,7 @@ In short, we are planning to:
Development of the templates and static assets likely requires using
`node` and `npm`. Install these tools in the normal way.
From the `templates/static` folder, run
From the `handlers/templates/static` folder, run
```
$npm install
```
@ -225,7 +224,21 @@ Then to build the minified version, run:
$gulp build
```
Modifying the `.go` files always requires re-running `go build`.
In case you have modified the templates and static assets, you need to run `go
generate` from the `handlers` sub-directory to ensure that your modifications
are embedded into the executable. For this to work, you must have
[github.com/shurcooL/vfsgen)[https://github.com/shurcooL/vfsgen) installed.
This will rewrite the `assets_vfsdata.go` which you must commit along with your
modification. Also you should run `go build` after `go generate`.
During the development cycle you may use `go build -tags dev` to build the
binary, in which case it will always take the assets from the relative file
path `handlers/templates/` directly and you can omit the `go generate` step.
But do not forget to perform it in the end.
Modifying the `go` files requires re-running `go build`.

10
handlers/assets.go Normal file
View File

@ -0,0 +1,10 @@
// +build dev
package handlers
import (
"net/http"
)
// Assets contains project assets.
var Assets http.FileSystem = http.Dir("templates")

View File

@ -0,0 +1,21 @@
// +build ignore
package main
import (
"log"
"github.com/consbio/mbtileserver/handlers"
"github.com/shurcooL/vfsgen"
)
func main() {
err := vfsgen.Generate(handlers.Assets, vfsgen.Options{
PackageName: "handlers",
BuildTags: "!dev",
VariableName: "Assets",
})
if err != nil {
log.Fatalln(err)
}
}

249
handlers/assets_vfsdata.go Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,7 @@
package handlers
//go:generate go run -tags=dev assets_generate.go
import (
"encoding/json"
"fmt"

26
handlers/static.go Normal file
View File

@ -0,0 +1,26 @@
package handlers
import (
"net/http"
"path"
"time"
)
// Static returns an http.Handler that will serve the contents of
// the subdirectory "/static/dist" of the Assets.
func Static() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
f, err := Assets.Open(path.Join("/static/dist", r.URL.Path))
if err != nil {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
defer f.Close()
mtime := time.Now()
st, err := f.Stat()
if err == nil {
mtime = st.ModTime()
}
http.ServeContent(w, r, path.Base(r.URL.Path), mtime, f)
})
}

52
handlers/templates.go Normal file
View File

@ -0,0 +1,52 @@
package handlers
import (
"html/template"
"io/ioutil"
"path"
"strings"
)
// TemplatesFromAssets returns the HTML templates from the assets filesystem.
// It has a signature that allows it to be used with templates.Must.
func TemplatesFromAssets() (*template.Template, error) {
t := template.New("_base_")
d, err := Assets.Open("/")
if err != nil {
return t, err
}
files, err := d.Readdir(0)
if err != nil {
return t, err
}
for _, file := range files {
name := file.Name()
ext := strings.ToLower(path.Ext(name))
if ext != ".html" || file.IsDir() {
continue
}
name = name[:len(name)-len(ext)]
if _, err := tmplFromAssets(t, name); err != nil {
return t, err
}
}
return t, nil
}
// tmplFromAssets returns the HTML templates from the assets filesystem.
func tmplFromAssets(t *template.Template, name string) (*template.Template, error) {
f, err := Assets.Open("/" + name + ".html")
if err != nil {
return nil, err
}
defer f.Close()
buf, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
t, err = t.New(name).Parse(string(buf))
if err != nil {
return nil, err
}
return t, nil
}

View File

@ -194,7 +194,7 @@ func serve() {
e.Use(middleware.CORS())
t := &Template{
templates: template.Must(template.ParseGlob("templates/*.html")),
templates: template.Must(handlers.TemplatesFromAssets()),
}
e.Renderer = t
@ -205,7 +205,12 @@ func serve() {
e.File("/favicon.png", "favicon.png")
// TODO: can use more caching here
e.Group(fmt.Sprintf("/%s/static/", pathPrefix), gzip, middleware.Static("templates/static/dist/"))
staticPrefix := "/static"
if pathPrefix != "" {
staticPrefix = "/" + pathPrefix + staticPrefix
}
staticHandler := http.StripPrefix(staticPrefix, handlers.Static())
e.GET(staticPrefix+"*", echo.WrapHandler(staticHandler), gzip)
e.GET("/services", ListServices, NotModifiedMiddleware, gzip)

16
main_dev.go Normal file
View File

@ -0,0 +1,16 @@
// +build dev
package main
import (
"net/http"
"github.com/consbio/mbtileserver/handlers"
)
// This is an temporary vehicle until we can stop serving the assets from the
// main package (that is, until https://github.com/consbio/mbtileserver/pull/47
// is merged). Afterwards, it is safe to remove this whole file.
func init() {
handlers.Assets = http.Dir("handlers/templates")
}