@@ -40,15 +40,16 @@ var ErrUnknownTemplate = fmt.Errorf("unknown template")
4040
4141// Options holds parameters for creating Templates.
4242type Options struct {
43- fileFindFunc func (filename string ) string
44- fileReadFunc FileReadFunc
45- contentType string
46- files map [string ][]string
47- strings map [string ][]string
48- functions template.FuncMap
49- delimOpen string
50- delimClose string
51- logf func (format string , a ... interface {})
43+ fileFindFunc func (filename string ) string
44+ fileReadFunc FileReadFunc
45+ fileReadOnRender bool
46+ contentType string
47+ files map [string ][]string
48+ strings map [string ][]string
49+ functions template.FuncMap
50+ delimOpen string
51+ delimClose string
52+ logf func (format string , a ... interface {})
5253}
5354
5455// Option sets parameters used in New function.
@@ -83,6 +84,15 @@ func WithFileReadFunc(fn FileReadFunc) Option {
8384 return func (o * Options ) { o .fileReadFunc = fn }
8485}
8586
87+ // WithFileReadOnRender forces template files to be read and
88+ // parsed every time Render or Respond functions are called.
89+ // This is useful for quickly reloading template files,
90+ // but with a performance cost. This functionality
91+ // is disabled by default.
92+ func WithFileReadOnRender (yes bool ) Option {
93+ return func (o * Options ) { o .fileReadOnRender = yes }
94+ }
95+
8696// WithTemplateFromFiles adds a template parsed from files.
8797func WithTemplateFromFiles (name string , files ... string ) Option {
8898 return func (o * Options ) { o .files [name ] = files }
@@ -142,6 +152,7 @@ func WithLogFunc(logf func(format string, a ...interface{})) Option {
142152// Templates structure holds parsed templates.
143153type Templates struct {
144154 templates map [string ]* template.Template
155+ parseFiles func (name string ) (* template.Template , error )
145156 defaultName string
146157 contentType string
147158 logf func (format string , a ... interface {})
@@ -181,16 +192,31 @@ func New(opts ...Option) (t *Templates, err error) {
181192 }
182193 t .templates [name ] = tpl
183194 }
184- for name , files := range o .files {
195+
196+ parse := func (files []string ) (tpl * template.Template , err error ) {
185197 fs := []string {}
186198 for _ , f := range files {
187199 fs = append (fs , o .fileFindFunc (f ))
188200 }
189- tpl , err := parseFiles (o .fileReadFunc , template .New ("" ).Funcs (o .functions ).Delims (o .delimOpen , o .delimClose ), fs ... )
190- if err != nil {
191- return nil , err
201+ return parseFiles (o .fileReadFunc , template .New ("" ).Funcs (o .functions ).Delims (o .delimOpen , o .delimClose ), fs ... )
202+ }
203+
204+ if o .fileReadOnRender {
205+ t .parseFiles = func (name string ) (tpl * template.Template , err error ) {
206+ files , ok := o .files [name ]
207+ if ! ok {
208+ return nil , & Error {Err : ErrUnknownTemplate , Template : name }
209+ }
210+ return parse (files )
211+ }
212+ } else {
213+ for name , files := range o .files {
214+ tpl , err := parse (files )
215+ if err != nil {
216+ return nil , err
217+ }
218+ t .templates [name ] = tpl
192219 }
193- t .templates [name ] = tpl
194220 }
195221 return
196222}
@@ -199,11 +225,8 @@ func New(opts ...Option) (t *Templates, err error) {
199225// then writes the the status and body to the response writer.
200226// A panic will be raised if the template does not exist or fails to execute.
201227func (t Templates ) RespondTemplateWithStatus (w http.ResponseWriter , name , templateName string , data interface {}, status int ) {
228+ tpl := t .mustTemplate (name )
202229 buf := bytes.Buffer {}
203- tpl , ok := t .templates [name ]
204- if ! ok {
205- panic (& Error {Err : ErrUnknownTemplate , Template : name })
206- }
207230 if err := tpl .ExecuteTemplate (& buf , templateName , data ); err != nil {
208231 panic (err )
209232 }
@@ -222,11 +245,8 @@ func (t Templates) RespondTemplateWithStatus(w http.ResponseWriter, name, templa
222245// then writes the the status and body to the response writer.
223246// A panic will be raised if the template does not exist or fails to execute.
224247func (t Templates ) RespondWithStatus (w http.ResponseWriter , name string , data interface {}, status int ) {
248+ tpl := t .mustTemplate (name )
225249 buf := bytes.Buffer {}
226- tpl , ok := t .templates [name ]
227- if ! ok {
228- panic (& Error {Err : ErrUnknownTemplate , Template : name })
229- }
230250 if err := tpl .Execute (& buf , data ); err != nil {
231251 panic (err )
232252 }
@@ -257,11 +277,8 @@ func (t Templates) Respond(w http.ResponseWriter, name string, data interface{})
257277
258278// RenderTemplate executes a named template and returns the string.
259279func (t Templates ) RenderTemplate (name , templateName string , data interface {}) (s string , err error ) {
280+ tpl := t .mustTemplate (name )
260281 buf := bytes.Buffer {}
261- tpl , ok := t .templates [name ]
262- if ! ok {
263- return "" , & Error {Err : ErrUnknownTemplate , Template : name }
264- }
265282 if err := tpl .ExecuteTemplate (& buf , templateName , data ); err != nil {
266283 return "" , err
267284 }
@@ -270,17 +287,29 @@ func (t Templates) RenderTemplate(name, templateName string, data interface{}) (
270287
271288// Render executes a template and returns the string.
272289func (t Templates ) Render (name string , data interface {}) (s string , err error ) {
290+ tpl := t .mustTemplate (name )
273291 buf := bytes.Buffer {}
274- tpl , ok := t .templates [name ]
275- if ! ok {
276- return "" , & Error {Err : ErrUnknownTemplate , Template : name }
277- }
278292 if err := tpl .Execute (& buf , data ); err != nil {
279293 return "" , err
280294 }
281295 return buf .String (), nil
282296}
283297
298+ func (t Templates ) mustTemplate (name string ) (tpl * template.Template ) {
299+ tpl , ok := t .templates [name ]
300+ if ok {
301+ return tpl
302+ }
303+ if t .parseFiles != nil {
304+ tpl , err := t .parseFiles (name )
305+ if err != nil {
306+ panic (err )
307+ }
308+ return tpl
309+ }
310+ panic (& Error {Err : ErrUnknownTemplate , Template : name })
311+ }
312+
284313func parseFiles (fn FileReadFunc , t * template.Template , filenames ... string ) (* template.Template , error ) {
285314 for _ , filename := range filenames {
286315 b , err := fn (filename )
0 commit comments