Search code examples
javascriptpythonhtmltemplatesmustache

Mustache.js render function returning empty string for page rendered using Chevron


I have the following code to display a webpage using Mustache templating (simplified for clarity)

<!doctype html>
<html lang="en" data-theme="dark">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/4.1.0/mustache.min.js"</script>
    <link rel="stylesheet" href="/static/css/pico.min.css">

  </head>

  <body>
    <main class="container">
      <button type="submit"
          id="submitBtn"
          onclick= "foo();">
          Foo
      </button>

      <script>
        function foo() {
          var newHTML = Mustache.render("{{food}}", { food: "tacos" });
          console.log("newHTML:", newHTML)
        }
      </script>

    </main>
  </body>
</html>

I expect the value of newHTML to be "tacos" but instead it's an empty string. I suspect this has something to do with the fact that the page itself is initially rendered from Python using Chevron (I can't get around that, it's part of a larger codebase). I tried making the same page in a standalone HTML file and the value of newHTML is indeed set to "tacos"

<!doctype html>
<html>
<head>
    <title>Mustache Example</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/4.1.0/mustache.min.js"</script>
</head>
<body>
    <h1 id="heading">{{food}}</h1>
    <script>
        var newHTML = Mustache.render("{{food}}", { food: "tacos" });
        console.log(newHTML)
        document.querySelector('#heading').innerHTML = newHTML
    </script>
</body>
</html>

Please help! Just spent half my day going in circles with ChatGPT

I've tried using different versions of Mustache.js, using a try/catch block, simplifying my code, console logging all the variables, and the issue still persists.


Solution

  • Your suspicion is likely to be correct: Chevron encounters the {{food}} and replaces it with the empty string before the browser and Mustache.js can have a go at it.

    You can prevent this from happening by temporarily changing the tag delimiters around parts of the template that should be rendered at the client side. Chevron will no longer recognize {{food}} as a tag and leave it alone. Conveniently, it will strip out the change delimiter tags, so the client will not see them.

    For example, you can change the line with your client side template to this:

    var newHTML = Mustache.render("{{=[[ ]]=}}{{food}}[[={{ }}=]]", { food: "tacos" });
    

    In this example, I put the change delimiter tags tightly around {{food}}. This is not necessary; to Chevron, everything looks like plain text, so you can put the tags anywhere. If there is a part of the page with only client side templates and no tags that should be processed by Chevron, you can wrap the entire section in a single pair of change delimiter tags. For example like this:

    {{=[[ ]]=}}
    var newHTML = Mustache.render("{{food}}", { food: "tacos" });
    [[={{ }}=]]