openpeeps / tim

This is Tim ⚡️ A high-performance template engine & markup language written in Nim
https://openpeeps.github.io/tim/
GNU Lesser General Public License v3.0
51 stars 1 forks source link

Example of using tim with mummy? #2

Closed matkuki closed 9 months ago

matkuki commented 9 months ago

Hi,

I have tried to get tim with (mummy)[], but I cannot get render to work in a multi-threaded enivironment. Could you give me a working example of how to use tim with mummy? Thanks

Here is my attempt:

import
    std/os,
    mummy,
    mummy/routers,
    tim

var
    timl = newTim(
        src = "templates",
        output = "storage",
        basepath = currentSourcePath(),
        minify = true,
        indent = 2
    )

proc index_handler(request: Request) =
    var headers: HttpHeaders
    headers["Content-Type"] = "text/html"
    let content: string = timl.render("index") # <- This line causes a compile error!
    request.respond(200, headers, $content)

proc main() =
    var router: Router
    router.get("/", index_handler)

    let
        server = newServer(router)
        ip_address = "0.0.0.0"
    echo "Serving on http://localhost:8080"
    server.serve(Port(8080), address=ip_address)

if is_main_module:
    main()
georgelemon commented 9 months ago

Thanks for trying Tim <3, note that this is still work in progress!

Don't forget to precompile your templates before rendering. Compile with -d:timHotCode to enable the filesystem monitor

var timThread: Thread[void]
proc precompileEngine() {.thread.} =
  {.gcsafe.}:
    timl.precompile(
      waitThread = true,  # optional, keeps thread alive
      flush = true,             # flush old cache on reboot
    )

createThread(timThread, precompileEngine)

Regarding your problem,timl is a global var, but we can make use of gcsafe pragma.

proc index_handler(request: Request) =
  var headers: HttpHeaders
  headers["Content-Type"] = "text/html"
  {.gcsafe.}:
    let content: string = timl.render("index") # safe for reading
  request.respond(200, headers, content)  # content is a string, no need for a `$` conversion

Add this JS snippet somewhere in your index view (js snippets in a layout won't work right now).

@js
  {
    const watchout = new WebSocket('ws://127.0.0.1:6502/ws');
    watchout.addEventListener('message', () => location.reload());
  }
@end

Will add a full working example of Mummy + Tim.

matkuki commented 9 months ago

Thanks for the quick reply @georgelemon ,

I have tried the modified example:

import
    std/os,
    mummy,
    mummy/routers,
    tim

var
    timl = newTim(
        src = "templates",
        output = "storage",
        basepath = currentSourcePath(),
        minify = true,
        indent = 2
    )
    timThread: Thread[void]
    comm_channel: Channel[string]

proc precompileEngine() {.thread.} =
    {.gcsafe.}:
        timl.precompile(
            waitThread = true, # optional, keeps thread alive
            flush = true, # flush old cache on reboot
        )

# Initialize Tim stuff
createThread(timThread, precompileEngine)

proc index_handler(request: Request) =
    var headers: HttpHeaders
    headers["Content-Type"] = "text/html"
    {.gcsafe.}:
        let content: string = timl.render("index")
    request.respond(200, headers, content)

proc main() =
    var router: Router
    router.get("/", index_handler)

    let
        server = newServer(router)
        ip_address = "0.0.0.0"
    echo "Serving on http://localhost:8080"
    server.serve(Port(8080), address=ip_address)

if is_main_module:
    main()

... but now when I connect to the url, the application crashes with:

~/Nim/http_test_server/test$ nim c -r test2.nim                                                                              
Hint: used config file '/home/user/.choosenim/toolchains/nim-2.0.2/config/nim.cfg' [Conf]                                                
Hint: used config file '/home/user/.choosenim/toolchains/nim-2.0.2/config/config.nims' [Conf]                                            
Hint: used config file '/home/user/Nim/http_test_server/nim.cfg' [Conf]                                                                  
Hint: used config file '/home/user/Nim/http_test_server/test/nim.cfg' [Conf]                                                             
Hint: mm: orc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)                                                          
10127 lines; 0.035s; 10.48MiB peakmem; proj: /home/user/Nim/http_test_server/test/test2.nim; out: /home/user/Nim/http_test_server
/test/test2 [SuccessX]                                                                                                                           
Hint: /home/user/Nim/http_test_server/test/test2 [Exec]                                                                                  
Serving on http://localhost:8080                                                                                                                 
Traceback (most recent call last)                                                                                                                
/home/user/Nim/http_test_server/deps/mummy/src/mummy.nim(515) workerProc                                                                 
/home/user/Nim/http_test_server/deps/mummy/src/mummy.nim(449) runTask                                                                    
/home/user/Nim/http_test_server/deps/mummy/src/mummy/routers.nim(271) :anonymous                                                         
/home/user/Nim/http_test_server/test/test2.nim(46) index_handler                                                                         
/home/user/Nim/http_test_server/deps/tim/src/tim.nim(208) render                                                                         
/home/user/Nim/http_test_server/deps/tim/src/tim.nim(24) jitCompiler                                                                     
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(1079) newCompiler                                             
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(994) walkNodes                                                
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(980) htmlElement                                              
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(994) walkNodes                                                
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(980) htmlElement                                              
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(994) walkNodes                                                
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(980) htmlElement                                              
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(994) walkNodes                                                
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(980) htmlElement                                              
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(994) walkNodes                                                
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(980) htmlElement                                              
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(994) walkNodes                                                
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(980) htmlElement                                              
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(1030) walkNodes                                               
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(699) evalConcat                                               
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(523) getValue                                                 
/home/user/Nim/http_test_server/deps/tim/src/tim/engine/compilers/html.nim(173) toString                                                 
SIGSEGV: Illegal storage access. (Attempt to read from nil?)                                                                                     
Segmentation fault (core dumped)
georgelemon commented 9 months ago

That is because HtmlCompiler is trying to access some data from global storage. I just pushed some fixes (forgot to check for nil when calling toString). Reinstalling tim via nimble should do the trick.

Also, if you're using the /example dir, try expose some data to global storage:

import std/json
proc precompileEngine() {.thread.} =
    {.gcsafe.}:
        timl.precompile(
            waitThread = true, # optional, keeps thread alive
            flush = true, # flush old cache on reboot
            global = %*{"year": 2024}  
        )

Where year can be accessed in your timl templates using $app.year

Trying to access an undeclared field should prompt the following error:

Error (13:29) Undeclared field year 
/.../example/templates/views/index.timl
matkuki commented 9 months ago

Yes, excellent, it works as you described :+1:

Thanks