Home

Awesome

react-template-render npm version dependency status

npm install react-template-render

Use React as your server-side HTML templating library the same way you'd use Pug, Nunjucks, Handlebars, etc.

Not intended to be used for anything more clever that 100% server-side rendering.

const makeRender = require('react-template-render')

const root = require('path').join(__dirname, 'views')

// `render` is an object with two functions: { string(), stream() }
const render = makeRender(root, { parent: 'parent' })

// As string
// Expects files ./views/template.jsx and ./views/parent.jsx to exist
render.string('template', { foo: 42 })

// As stream
render.stream('template', { foo: 42 })

Check out the example/ folder for a minimal demo using Koa: cd example && npm install && npm start.

Usage

The library exports a single function that takes some options and returns a renderer. The first argument is required as it specifies the directory that holds your .jsx templates.

These are the default options.

const makeRender = require('react-template-render')
const root = require('path').join(__dirname, 'views')
const render = makeRender(root, {
    parent: null,
    prefix: '<!doctype html>',
    keyPropWarnings: true,
})

These options can be overridden ad-hoc via the third argument to .string()/.stream():

const html = render('profile', { name: 'katie' }, { parent: 'katies-layout' })

JSX compilation in Node

Simplest way I know how is with babel-register.

Put this at the top of your server's entry-point:

require('babel-register')({
    presets: ['react'],
    extensions: ['.jsx'],
})
npm i babel-register babel-preset-react

For info on precompiling, check out: https://github.com/babel/example-node-server#getting-ready-for-production-use

Note that if you precompile, babel will change ".jsx" extensions to ".js" which will break your require()s if you use require('homepage.jsx') instead of require('homepage'). My solution is to just leave off the extension entirely.

This way, your code will work in development since Babel resolves ".jsx" files, yet it will still work after compilation since require natively works with ".js" files.

Extras

This library provides some extra features:

Example parent.jsx:

const React = require('react')

module.exports = ({ children, title }) => (
    <html>
        <head>
            <title>{title ? title + ' - Example.com' : 'The Best Example - Example.com'}</title>
        </head>
        <body>{children}</body>
    </html>
)

Example child.jsx:

const React = require('react')

module.exports = ({ greeting }) => <div>{greeting}, world!</div>

All togther:

const makeRender = require('react-template-render')
const root = require('path').join(__dirname, 'views')
const render = makeRender(root, { parent: 'parent' })

const html = render('child', { greeting: 'hello', title: "child's title" })
<!doctype html>
<html>
    <head>
        <title>child's title - Example.com</title>
    </head>
    <body>hello, world!</body>
</html>

Benefits of jsx on the server

Drawbacks

Koa example

A fully working Koa example can be found in the example/ folder.

cd example && npm install && npm start

But for the sake of readme skimmability, here's the gist of what the Koa middleware would look like:

const makeRenderer = require('react-template-render')

const middleware = (root, opts) => {
    return async (ctx, next) => {
        // For when you want to call stream() or string() yourself
        //
        // e.g. Maybe you want to cache some html output to disk:
        //
        //     const html = ctx.renderer.string('template')
        //     await writeFile(html, { encoding: 'utf8' })
        //
        ctx.renderer = makeRenderer(root, opts)

        // Convenience function for streaming to the response
        ctx.render = (template, locals, overrides) => {
            ctx.type = 'html'
            ctx.body = ctx.renderer.stream(template, locals, overrides)
        }

        return next()
    }
}

const app = new Koa()

const root = require('path').join(__dirname, 'views')
app.use(middleware(root, { parent: 'layout' }))

app.get('/users/:id', async ctx => {
    const { id } = ctx.params
    const user = await db.getUser(id)
    ctx.assert(user, 404)
    ctx.render('show-user', {
        title: `Profile of ${user.uname}`,
        user,
    })
})

Tips and notes