Separating webserver/app code and site templates

[Background - I'm porting my golang blog app to racket, and figuring it out as I go]

I've been working through the web-server-lib docs and learning to use include-template. In my existing app, the installation of the blog software is separate from the templates, content, and other assets for a specific site. I did some work to configure the site-base and relative template and posts paths, but found that include-template will not read the template, but fails with "bad relative pathname string". After some frustrating RTFMing I found that all the variants of include* in racket expect a path-spec that is only a relative path:

That is, string refers to a file using a platform-independent relative path

A jump to Github led me to the actual code:

(unless (module-path? s)
  (raise-syntax-error
   #f
   "bad relative pathname string"
   stx
   fn))

I didn't read up on module-path? yet but I assume it keeps to things under the module file system structure.

I can imagine this is a security feature since include-template derives (not in the technical sense) from the same code that is used for require, ie trying to avoid a malicious program from include-ing /etc/passwd for example.

This leaves me with the question: is there a way to integrate with web-server/templates where I read the files myself and add them to some namespace so that they can be included (including in sub-templates) or am I trying to do something 1) bad 2) stupid 3) both?

I really don't want to embed the entire look and feel of a site into the racket application?

--Steve

2 Likes

After a lot more research realized this was way more complicated than I needed, and I'm looking now at just copying the templates to a "nearby" tmp directory that can be required from (hoping it works)

1 Like

Keep in mind that, in using include-template from web-server/templates, you're effectively running a program written in #lang scribble/text, IIRC.

As for the relative paths, probably you need to set current-load-relative-directory to the directory containing the template. Then use the relative file names in the requires.

Also, to access certain variables within the template -- e.g. @contents or @title and so on, which is kind of the whole point of a template approach -- then you need to:

  • create a namespace
  • attach/require some other modules into that
  • make a form that introduces your own variable bindings and calls include-template
  • eval that form in that namespace (and with the load-relative directory set).

I found this confusing when I did it many years agoo, for my now-dormant blog app, Frog. I got some help on the old mailing list, and cargo-culted some things. I barely understood how/why it worked, years ago, much less today.

Having said that, you're welcome to scrounge my old code. See template.rkt, which provides a wrapper for include-template -- a render-template function. It takes a directory, a template file path, and a dictionary of variables/values to be used within the template. It returns the HTML text. Search other files for some example uses of render-template.

Hi Greg! I actually found Frog and have been trolling through the code for a few days! Thanks! I do need to revisit your template code, I didn't understand it at all when I started, but I've been deep in racket's include code recently so hopefully it will make more sense.

Question @greghendershott -- I understand that templates are their own "lang" (scribble/text) but is there a performance hit or something? Your "keep in mind" felt a bit like a "beware" :smiley:

Not re performance. Just in terms of how to use include-template. Using the template is effectively like running an end user program, and you need to be aware of things like namespaces and load-directories, which you wouldn't with a "normal" function call. Also the use of eval, which is usually a smell, is IIUC fine here.

1 Like