mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
add 'iris.Ace' template engine: _examples/view/template_ace_0
This commit is contained in:
parent
dfa08041a1
commit
6844be57ea
|
@ -359,6 +359,8 @@ Response:
|
|||
|
||||
Other Improvements:
|
||||
|
||||
- Add [Ace](_examples/view/template_ace_0) template parser to the view engine and other minor improvements. <!-- a new html/template-based engine, with a different layout-page syntax but better performance, follows this week. -->
|
||||
|
||||
- Fix huge repo size of 55.7MB, which slows down the overall Iris installation experience. Now, go-get performs ~3 times faster. I 've managed it using the [bfg-repo-cleaner](https://github.com/rtyley/bfg-repo-cleaner) tool - an alternative to git-filter-branch command. Watch the small gif below to learn how:
|
||||
|
||||
[![](https://media.giphy.com/media/U8560aiWTurW4iAOLn/giphy.gif)](https://media.giphy.com/media/U8560aiWTurW4iAOLn/giphy.gif)
|
||||
|
|
5
NOTICE
5
NOTICE
|
@ -10,7 +10,10 @@ Revision ID: d1c07411df0bb21f6b21f5b5d9325fac6f29c911
|
|||
|
||||
----------------- ----------------- ------------------------------------------
|
||||
Package Version Website
|
||||
----------------- ----------------- ------------------------------------------
|
||||
----------------- ----------------- ------------------------------------------
|
||||
ace ea038f4770b6746 https://github.com/yosssi/ace
|
||||
c3f8f84f14fa60d
|
||||
9fe1205b56
|
||||
badger 536fed1846d0f4d https://github.com/dgraph-io/badger
|
||||
b9579bcff679761
|
||||
4e134eadfa
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
* [Jet Embedded](view/template_jet_1_embedded)
|
||||
* [Jet 'urlpath' tmpl func](view/template_jet_2)
|
||||
* [Jet Template Funcs from Struct](view/template_jet_3)
|
||||
- [Ace](view/template_ace_0)
|
||||
* Third-Parties
|
||||
* [Render `valyala/quicktemplate` templates](view/quicktemplate)
|
||||
* [Render `shiyanhui/hero` templates](view/herotemplate)
|
||||
|
|
31
_examples/view/template_ace_0/main.go
Normal file
31
_examples/view/template_ace_0/main.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package main
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
// Read about its markup syntax at: https://github.com/yosssi/ace
|
||||
tmpl := iris.Ace("./views", ".ace")
|
||||
// tmpl.Layout("layouts/main.ace") -> global layout for all pages.
|
||||
|
||||
app.RegisterView(tmpl)
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.View("index.ace", iris.Map{
|
||||
"Title": "Title of The Page",
|
||||
})
|
||||
})
|
||||
|
||||
app.Get("/layout", func(ctx iris.Context) {
|
||||
ctx.ViewLayout("layouts/main.ace") // layout for that response.
|
||||
ctx.View("index.ace", iris.Map{
|
||||
"Title": "Title of the main Page",
|
||||
})
|
||||
})
|
||||
|
||||
// otherGroup := app.Party("/other").Layout("layouts/other.ace") -> layout for that party.
|
||||
// otherGroup.Get("/", func(ctx iris.Context) { ctx.View("index.ace", [...]) })
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
5
_examples/view/template_ace_0/views/index.ace
Normal file
5
_examples/view/template_ace_0/views/index.ace
Normal file
|
@ -0,0 +1,5 @@
|
|||
= include partials/header.ace .
|
||||
|
||||
h2 {{.Title}}
|
||||
|
||||
= include partials/footer.ace .
|
6
_examples/view/template_ace_0/views/layouts/main.ace
Normal file
6
_examples/view/template_ace_0/views/layouts/main.ace
Normal file
|
@ -0,0 +1,6 @@
|
|||
= doctype html
|
||||
html
|
||||
head
|
||||
title Main Page
|
||||
body
|
||||
{{ yield }}
|
1
_examples/view/template_ace_0/views/partials/footer.ace
Normal file
1
_examples/view/template_ace_0/views/partials/footer.ace
Normal file
|
@ -0,0 +1 @@
|
|||
h1 Partial Footer
|
1
_examples/view/template_ace_0/views/partials/header.ace
Normal file
1
_examples/view/template_ace_0/views/partials/header.ace
Normal file
|
@ -0,0 +1 @@
|
|||
h1 Partial Header
|
|
@ -1,3 +1,3 @@
|
|||
## Info
|
||||
|
||||
This folder examines the {{render "dir/templatefilename"}} functionality to manually render any template inside any template
|
||||
This folder examines the {{render "dir/templatefilename" .}} functionality to manually render any template inside any template
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
<h1>Page 1 {{ greet "iris developer"}}</h1>
|
||||
|
||||
{{ render "partials/page1_partial1.html"}}
|
||||
{{ render "partials/page1_partial1.html" }}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -207,6 +207,9 @@ var (
|
|||
// Jet view engine.
|
||||
// Shortcut of the kataras/iris/view.Jet.
|
||||
Jet = view.Jet
|
||||
// Ace view engine.
|
||||
// Shortcut of the kataras/iris/view.Ace.
|
||||
Ace = view.Ace
|
||||
)
|
||||
|
||||
// PrefixDir returns a new FileSystem that opens files
|
||||
|
|
|
@ -81,7 +81,7 @@ func parseYAML(filename string) (Configuration, error) {
|
|||
//
|
||||
// Accepts the absolute path of the cfg.yml.
|
||||
// An error will be shown to the user via panic with the error message.
|
||||
// Error may occur when the cfg.yml doesn't exists or is not formatted correctly.
|
||||
// Error may occur when the cfg.yml does not exist or is not formatted correctly.
|
||||
//
|
||||
// Note: if the char '~' passed as "filename" then it tries to load and return
|
||||
// the configuration from the $home_directory + iris.yml,
|
||||
|
@ -115,7 +115,7 @@ func YAML(filename string) Configuration {
|
|||
//
|
||||
// Accepts the absolute path of the configuration file.
|
||||
// An error will be shown to the user via panic with the error message.
|
||||
// Error may occur when the file doesn't exists or is not formatted correctly.
|
||||
// Error may occur when the file does not exist or is not formatted correctly.
|
||||
//
|
||||
// Note: if the char '~' passed as "filename" then it tries to load and return
|
||||
// the configuration from the $home_directory + iris.tml,
|
||||
|
|
5
go.mod
5
go.mod
|
@ -33,10 +33,11 @@ require (
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693
|
||||
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1
|
||||
github.com/yosssi/ace v0.0.5
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
||||
golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3
|
||||
golang.org/x/text v0.3.3
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||
google.golang.org/protobuf v1.25.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# View
|
||||
|
||||
Iris supports 6 template engines out-of-the-box, developers can still use any external golang template engine,
|
||||
as `context/context#ResponseWriter()` is an `io.Writer`.
|
||||
Iris supports 7 template engines out-of-the-box, developers can still use any external golang template engine,
|
||||
as `Context.ResponseWriter()` is an `io.Writer`.
|
||||
|
||||
All of these six template engines have common features with common API,
|
||||
like Layout, Template Funcs, Party-specific layout, partial rendering and more.
|
||||
|
@ -12,6 +12,7 @@ like Layout, Template Funcs, Party-specific layout, partial rendering and more.
|
|||
- Handlebars, its template parser is the [github.com/aymerick/raymond](https://github.com/aymerick/raymond)
|
||||
- Amber, its template parser is the [github.com/eknkc/amber](https://github.com/eknkc/amber)
|
||||
- Jet, its template parser is the [github.com/CloudyKit/jet](https://github.com/CloudyKit/jet)
|
||||
- Ace, its template parser is the [github.com/yosssi/ace](https://github.com/yosssi/ace)
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -27,8 +28,9 @@ like Layout, Template Funcs, Party-specific layout, partial rendering and more.
|
|||
- [Pug (Jade) Actions`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_1)
|
||||
- [Pug (Jade) Includes`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_2)
|
||||
- [Pug (Jade) Extends`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_3)
|
||||
- [Jet](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_0) **NEW**
|
||||
- [Jet Embedded](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_1_embedded) **NEW**
|
||||
- [Jet](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_0)
|
||||
- [Jet Embedded](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_1_embedded)
|
||||
- [Ace](https://github.com/kataras/iris/blob/master/_examples/view/template_ace_0)
|
||||
|
||||
You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files too, simply by using the `context#ResponseWriter`, take a look at the [iris/_examples/view/quicktemplate](https://github.com/kataras/iris/tree/master/_examples/view/quicktemplate) example.
|
||||
|
||||
|
|
57
view/ace.go
Normal file
57
view/ace.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/yosssi/ace"
|
||||
)
|
||||
|
||||
// Ace returns a new ace view engine.
|
||||
// It shares the same exactly logic with the
|
||||
// html view engine, it uses the same exactly configuration.
|
||||
//
|
||||
// Read more about the Ace Go Parser: https://github.com/yosssi/ace
|
||||
func Ace(directory, extension string) *HTMLEngine {
|
||||
s := HTML(directory, extension)
|
||||
|
||||
funcs := make(map[string]interface{}, 0)
|
||||
|
||||
once := new(sync.Once)
|
||||
s.middleware = func(name string, text []byte) (contents string, err error) {
|
||||
once.Do(func() { // on first template parse, all funcs are given.
|
||||
for k, v := range s.funcs {
|
||||
funcs[k] = v
|
||||
}
|
||||
for k, v := range emptyFuncs {
|
||||
funcs[k] = v
|
||||
}
|
||||
})
|
||||
|
||||
name = path.Join(path.Clean(directory), name)
|
||||
|
||||
src := ace.NewSource(
|
||||
ace.NewFile(name, text),
|
||||
ace.NewFile("", []byte{}),
|
||||
[]*ace.File{},
|
||||
)
|
||||
|
||||
rslt, err := ace.ParseSource(src, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
t, err := ace.CompileResult(name, rslt, &ace.Options{
|
||||
Extension: extension[1:],
|
||||
FuncMap: funcs,
|
||||
DelimLeft: s.left,
|
||||
DelimRight: s.right,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return t.Lookup(name).Tree.Root.String(), nil
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -220,5 +220,5 @@ func (s *AmberEngine) ExecuteWriter(w io.Writer, filename string, layout string,
|
|||
return tmpl.Execute(w, bindingData)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Template with name %s doesn't exists in the dir", filename)
|
||||
return fmt.Errorf("Template with name: %s does not exist in the dir: %s", filename, s.directory)
|
||||
}
|
||||
|
|
|
@ -376,5 +376,5 @@ func (s *DjangoEngine) ExecuteWriter(w io.Writer, filename string, layout string
|
|||
return tmpl.ExecuteWriter(getPongoContext(bindingData), w)
|
||||
}
|
||||
|
||||
return fmt.Errorf("template with name %s doesn't exists in the dir", filename)
|
||||
return fmt.Errorf("template with name: %s ddoes not exist in the dir: %s", filename, s.directory)
|
||||
}
|
||||
|
|
|
@ -291,5 +291,5 @@ func (s *HandlebarsEngine) ExecuteWriter(w io.Writer, filename string, layout st
|
|||
return err
|
||||
}
|
||||
|
||||
return fmt.Errorf("template with name %s[original name = %s] doesn't exists in the dir", renderFilename, filename)
|
||||
return fmt.Errorf("template with name: %s[original name = %s] does not exist in the dir: %s", renderFilename, filename, s.directory)
|
||||
}
|
||||
|
|
105
view/html.go
105
view/html.go
|
@ -26,8 +26,8 @@ type HTMLEngine struct {
|
|||
right string
|
||||
layout string
|
||||
rmu sync.RWMutex // locks for layoutFuncs and funcs
|
||||
layoutFuncs map[string]interface{}
|
||||
funcs map[string]interface{}
|
||||
layoutFuncs template.FuncMap
|
||||
funcs template.FuncMap
|
||||
|
||||
//
|
||||
middleware func(name string, contents []byte) (string, error)
|
||||
|
@ -38,7 +38,7 @@ type HTMLEngine struct {
|
|||
var _ Engine = (*HTMLEngine)(nil)
|
||||
|
||||
var emptyFuncs = template.FuncMap{
|
||||
"yield": func() (string, error) {
|
||||
"yield": func(binding interface{}) (string, error) {
|
||||
return "", fmt.Errorf("yield was called, yet no layout defined")
|
||||
},
|
||||
"part": func() (string, error) {
|
||||
|
@ -52,7 +52,8 @@ var emptyFuncs = template.FuncMap{
|
|||
},
|
||||
"current": func() (string, error) {
|
||||
return "", nil
|
||||
}, "render": func() (string, error) {
|
||||
},
|
||||
"render": func() (string, error) {
|
||||
return "", nil
|
||||
},
|
||||
}
|
||||
|
@ -70,8 +71,8 @@ func HTML(directory, extension string) *HTMLEngine {
|
|||
left: "{{",
|
||||
right: "}}",
|
||||
layout: "",
|
||||
layoutFuncs: make(map[string]interface{}),
|
||||
funcs: make(map[string]interface{}),
|
||||
layoutFuncs: make(template.FuncMap),
|
||||
funcs: make(template.FuncMap),
|
||||
}
|
||||
|
||||
return s
|
||||
|
@ -172,10 +173,34 @@ func (s *HTMLEngine) AddLayoutFunc(funcName string, funcBody interface{}) *HTMLE
|
|||
// - url func(routeName string, args ...string) string
|
||||
// - urlpath func(routeName string, args ...string) string
|
||||
// - render func(fullPartialName string) (template.HTML, error).
|
||||
func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) {
|
||||
func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) *HTMLEngine {
|
||||
s.rmu.Lock()
|
||||
s.funcs[funcName] = funcBody
|
||||
s.rmu.Unlock()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// SetFuncs overrides the template funcs with the given "funcMap".
|
||||
func (s *HTMLEngine) SetFuncs(funcMap template.FuncMap) *HTMLEngine {
|
||||
s.rmu.Lock()
|
||||
s.funcs = funcMap
|
||||
s.rmu.Unlock()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Funcs adds the elements of the argument map to the template's function map.
|
||||
// It is legal to overwrite elements of the map. The return
|
||||
// value is the template, so calls can be chained.
|
||||
func (s *HTMLEngine) Funcs(funcMap template.FuncMap) *HTMLEngine {
|
||||
s.rmu.Lock()
|
||||
for k, v := range funcMap {
|
||||
s.funcs[k] = v
|
||||
}
|
||||
s.rmu.Unlock()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Load parses the templates to the engine.
|
||||
|
@ -266,6 +291,7 @@ func (s *HTMLEngine) loadDirectory() error {
|
|||
name := filepath.ToSlash(rel)
|
||||
tmpl := s.Templates.New(name)
|
||||
tmpl.Option(s.options...)
|
||||
|
||||
if s.middleware != nil {
|
||||
contents, err = s.middleware(name, buf)
|
||||
}
|
||||
|
@ -275,7 +301,12 @@ func (s *HTMLEngine) loadDirectory() error {
|
|||
}
|
||||
// s.mu.Lock()
|
||||
// Add our funcmaps.
|
||||
_, err = tmpl.Funcs(emptyFuncs).Funcs(s.funcs).Parse(contents)
|
||||
_, err = tmpl.
|
||||
Funcs(emptyFuncs).
|
||||
// Funcs(s.makeDefaultLayoutFuncs(name)).
|
||||
// Funcs(s.layoutFuncs).
|
||||
Funcs(s.funcs).
|
||||
Parse(contents)
|
||||
// s.mu.Unlock()
|
||||
if err != nil {
|
||||
templateErr = err
|
||||
|
@ -393,15 +424,28 @@ func (s *HTMLEngine) executeTemplateBuf(name string, binding interface{}) (*byte
|
|||
return buf, err
|
||||
}
|
||||
|
||||
func (s *HTMLEngine) layoutFuncsFor(name string, binding interface{}) {
|
||||
func (s *HTMLEngine) layoutFuncsFor(lt *template.Template, name string, binding interface{}) {
|
||||
s.runtimeFuncsFor(lt, name, binding)
|
||||
|
||||
funcs := template.FuncMap{
|
||||
"yield": func() (template.HTML, error) {
|
||||
buf, err := s.executeTemplateBuf(name, binding)
|
||||
// Return safe HTML here since we are rendering our own template.
|
||||
return template.HTML(buf.String()), err
|
||||
},
|
||||
}
|
||||
|
||||
for k, v := range s.layoutFuncs {
|
||||
funcs[k] = v
|
||||
}
|
||||
|
||||
lt.Funcs(funcs)
|
||||
}
|
||||
|
||||
func (s *HTMLEngine) runtimeFuncsFor(t *template.Template, name string, binding interface{}) {
|
||||
funcs := template.FuncMap{
|
||||
"part": func(partName string) (template.HTML, error) {
|
||||
nameTemp := strings.Replace(name, ".html", "", -1)
|
||||
nameTemp := strings.Replace(name, s.extension, "", -1)
|
||||
fullPartName := fmt.Sprintf("%s-%s", nameTemp, partName)
|
||||
buf, err := s.executeTemplateBuf(fullPartName, binding)
|
||||
if err != nil {
|
||||
|
@ -440,25 +484,7 @@ func (s *HTMLEngine) layoutFuncsFor(name string, binding interface{}) {
|
|||
},
|
||||
}
|
||||
|
||||
for k, v := range s.layoutFuncs {
|
||||
funcs[k] = v
|
||||
}
|
||||
if tpl := s.Templates.Lookup(name); tpl != nil {
|
||||
tpl.Funcs(funcs)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HTMLEngine) runtimeFuncsFor(name string, binding interface{}) {
|
||||
funcs := template.FuncMap{
|
||||
"render": func(fullPartialName string) (template.HTML, error) {
|
||||
buf, err := s.executeTemplateBuf(fullPartialName, binding)
|
||||
return template.HTML(buf.String()), err
|
||||
},
|
||||
}
|
||||
|
||||
if tpl := s.Templates.Lookup(name); tpl != nil {
|
||||
tpl.Funcs(funcs)
|
||||
}
|
||||
t.Funcs(funcs)
|
||||
}
|
||||
|
||||
// ExecuteWriter executes a template and writes its result to the w writer.
|
||||
|
@ -474,14 +500,21 @@ func (s *HTMLEngine) ExecuteWriter(w io.Writer, name string, layout string, bind
|
|||
}
|
||||
}
|
||||
|
||||
layout = getLayout(layout, s.layout)
|
||||
if layout = getLayout(layout, s.layout); layout != "" {
|
||||
lt := s.Templates.Lookup(layout)
|
||||
if lt == nil {
|
||||
return fmt.Errorf("layout: %s does not exist in the dir: %s", name, s.directory)
|
||||
}
|
||||
|
||||
if layout != "" {
|
||||
s.layoutFuncsFor(name, bindingData)
|
||||
name = layout
|
||||
} else {
|
||||
s.runtimeFuncsFor(name, bindingData)
|
||||
s.layoutFuncsFor(lt, name, bindingData)
|
||||
return lt.Execute(w, bindingData)
|
||||
}
|
||||
|
||||
return s.Templates.ExecuteTemplate(w, name, bindingData)
|
||||
t := s.Templates.Lookup(name)
|
||||
if t == nil {
|
||||
return fmt.Errorf("template: %s does not exist in the dir: %s", name, s.directory)
|
||||
}
|
||||
s.runtimeFuncsFor(t, name, bindingData)
|
||||
|
||||
return t.Execute(w, bindingData)
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@ import (
|
|||
// Pug (or Jade) returns a new pug view engine.
|
||||
// It shares the same exactly logic with the
|
||||
// html view engine, it uses the same exactly configuration.
|
||||
// It has got some features and a lot of functions
|
||||
// which will make your life easier.
|
||||
//
|
||||
// Read more about the Jade Go Parser: https://github.com/Joker/jade
|
||||
//
|
||||
// Examples:
|
||||
|
|
Loading…
Reference in New Issue
Block a user