🚀Announcing Flightcontrol - Easily Deploy Blitz.js and Next.js to AWS 🚀
Back to Documentation Menu

Blitz Templating Language

Topics

Jump to a Topic

Blitz provides a completely custom templating language for use in custom templates. The goal was for templates to always be valid syntax in whatever language you're writing, rather than getting syntax errors in your IDE and having to build the template to see if its output is correct like you do with embedded languages like EJS.

Variable Interpolation

This is the core of any templating language, and this syntax should be fairly familiar if you've used Handlebars or anything similar. To insert a variable that's been provided to the template's context argument, surround it with double underscores: __.

// Input
export default function __ModelName__Home() {
  return <div />
}

// Output
export default function TodosHome() {
  return <div />
}

Conditional Expressions

In order to retain our first principle of valid syntax, conditional experessions currently only work in TypeScript templates. At runtime we place all of the provided template context values onto process.env, and when compiling the template we search for any conditional expressions against a valid template value on process.env. This works both for traditional if statements as well as ternary operations. Soon we hope to add support for conditional expressions in JSX for conditional component insertion as well.

If you access a variable that isn't a template value it is ignored, allowing functionality like dead code elimination via process.env.NODE_ENV into template to work properly.

Info

The conditions are not dynamically evaluated, they're only checked for truthiness. This means that for dynamic evaluation you'll need to do the check ahead of time and pass it into the template as context, a check like if (process.env.componentName === 'SomeComp') will not work properly.

// Input
export default function __ModelName__Home() {
  if (process.env.includeAnalytics) {
    useEffect(() => {
      setupAnalytics()
    }, [])
  }
  // ...
}

// Output (includeAnalytics: true)
export default function __ModelName__Home() {
  useEffect(() => {
    setupAnalytics()
  }, [])
  // ...
}

// Output (includeAnalytics: false)
export default function __ModelName__Home() {
  // ...
}

Conditional JSX Expressions

In the case where you need to conditionally insert different JSX into your templates, the process.env solution isn't ideal. Because we only do naive replacement of the inner node, if you embed a process.env conditional in JSX you'll have something like this:

// input
function MyLink() {
  return (
    <>
      {process.env.useLinkWrapper ? (
        <Link>
          <a href="//blitzjs.com">Blitz</a>
        </Link>
      ) : (
        <a href="//blitzjs.com">Blitz</a>
      )}
    </>
  )
}

// output
function MyLink() {
  return (
    <>
      {
        <Link>
          <a href="//blitzjs.com">Blitz</a>
        </Link>
      }
    </>
  )
}

As you can see, the curly braces that wrap the inner script will persist in the template output. This is where we can use our custom JSX conditional syntax. The generator exposes two new JSX elements to TSX templates: <if condition="value" /> and <else />. Their behavior is exactly the same as a standard process.env conditional. The condition prop on the if statement is read out of the template context. If its value is truthy the first child of <if /> will be rendered, otherwise the contents of the <else /> element will be rendered.

Info

Both <if /> and <else /> only accept a single child component. You will see unexpected behavior and errors if you try to provide a fragment or multiple elements.

// input
function MyLink() {
  return (
    <if condition="useLinkWrapper">
      <Link>
        <a href="//blitzjs.com">Blitz</a>
      </Link>
      <else>
        <a href="//blitzjs.com">Blitz</a>
      </else>
    </if>
  )
}

// output
function MyLink() {
  return (
    <Link>
      <a href="//blitzjs.com">Blitz</a>
    </Link>
  )
}

Interested in helping with the templating language? There's plenty of room for improvement including supporting loops and iteration, actual evaluation of conditionals rather than only truthiness checks, and more! Join us in Discord.


Idea for improving this page? Edit it on GitHub.