koa2-jsx
yarn add koa2jsx
koa2-jsx
is middleware for Koa2
which provides support for rendering JSX in a server application via react-dom/server
. It also uses Redux
to create a store updatable with actions for a better control of what data needs to be rendered, for example, it is possible to create a reducer with a title
slice, and an action to set that property from ctx
, and then print { title }
in the JSX template.
In addition to the core functionality, the package gives a minimum wireframe View
container and actions to set page title and viewport, add external and inline scripts and styles, icons and a link to the manifest file.
Finally, there's an extra middleware function which can be used after koa2-jsx
and wireframe actions were installed to include links to Bootstrap 4
scripts (including jQuery) and CSS.
API
The module will return a single middleware function which accepts 3 arguments: reducer
, View
and actions
. They are describe below in the Example section.
The middleware function will perform the following for each request:
- Initialise the Redux store by creating a reducer;
- assign actions to the context, such as
{ setTitle(title) }
becomesctx.setTitle
; - wait for all other middleware and pages to resolve; and
- render
ctx.Content
if found usingreact-dom/server
as a stream with doctype html sent, using the View.
import Koa from 'koa2'import koa2Jsx from 'koa2-jsx'import combineReducers from 'redux'import connect from 'react-redux' const app = const View = title children return <html ="en"> <head> <title>title</title> </head> <body> children </body> </html> const jsx = app
When setting up middleware, ensure that the koa2-jsx
middleware function comes
ahead of pages so that the Redux store and render logic are initialised.
If ctx.Content
is set in downstream application middleware, <!doctype html>
is written and a readable stream from React Dom's
renderToStaticNodeStream(<WebPage />)
is be piped into ctx.body
.
koa2Jsx({
reducer: function,
View: Container,
actions: object,
static?: boolean = true,
render?: function,
}): function
This will set up the middleware function and return it. Add it as a usual Koa2
middleware (shown below).
Example
The example shows how to create a reducer, actions and View for a minimum HTML template.
/* yarn example/ */ const app = const jsx = app
reducer
The reducer is either a simple function or a combination of reducers created with combineReducers
from the redux
package. The reducer is used during the initialisation of the middleware to create a store with createStore(reducer)
. The store is used in rendering as a context for the View container. This way, it's possible to pass data to the template by invoking methods on the Koa's context (see actions).
const title = { if type != 'SET_TITLE' return state return title} title
View
The view can be a connected react-redux
component when actions and a reducer are used, or a pure React
component when they're omitted. It follows the same principles as when developing for a browser-side react-redux
application, so that it accepts the state of the reducer as the first argument, with children
property (set to ctx.Content
).
const View = { return <html lang="en"> <head> <title>title</title> </head> <body> children </body> </html> } stateView
actions
Actions map action creators to Koa's context, so that it is possible to dispatch
actions from ctx
to control the state and thus data which goes into the
template.
const actions = type: 'SET_TITLE' title // ^ exported as ctx.setTitle(title)
static: bool = true
Whether to use static rendering, i.e., without React's metadata required for hydration on the client-side. Set to false
when building universal applications.
Results with static:
test
and without static:
test
pretty: bool = false
Prettify HTML output. This will use string rendering to get HTML before formatting, therefore it's slower to display a page.
Test
render: function(ctx: Koa.Context, WebSite: React.Component)
It is possible to pass a custom render function. You should implement your own render for more control when needed. It accepts a Koa's context and a WebSite
arguments. The WebSite
is a View
container wrapped in a state provider.
Examples below show how you can implement (a) markup renderer:
const render = { ctxtype = 'html' ctxstatus = 200 ctxres const markup = const s = ctxbody = s}
(b) stream renderer:
const streamRender = { ctxtype = 'html' ctxstatus = 200 ctxres const stream = ctxbody = stream}
Wireframe
The wireframe provides a reducer
, actions
and View
to be used when creating web pages. It accounts for most common use cases, such as assigning viewport and icons. To include it in your application, use:
const jsx = /* or using object destructuring */ const jsx =
Template
The following template is used, which allows to set viewport, title, add links, external scripts and script and style blocks.
{viewport && } {title} <!-- css, icons, manifest --> {links.map((props, i) => )} <!-- CSS --> {styles.map((style, i) => )} {children} {scripts.map((props, i) => )} {js.map((script, i) => )}
Actions
To update the data to present in the template, the actions API is as follows.
setTitle(title)
Set title of the page.
ctx
koa2-jsx
setViewport(viewport)
Set the viewport.
ctx
addManifest(href)
Add a link to the manifest file.
ctx
addIcon(href | [[href, type, sizes, ref=icon]])
Add an icon or icons links.
ctxctx
addScript(src | [[src, integrity, crossOrigin]])
Add a single, or multiple script tags. If integrity and origin need to be used, an array must be passed.
ctxctx
addCss(href | [[href, integrity, crossOrigin]])
Add a single, or multiple style links. If integrity and origin need to be specified, an array must be passed.
ctxctx
addStyle(style)
Add a style block to the HTML.
ctx
addJs(js)
Add a block of JS code.
ctx
Bootstrap
To include the full Bootstrap 4
support to an HTML page, use the following snippet:
const jsx = // ...appapp
<!-- viewport is assigned --> <!-- css embedded --> <!-- script tags included -->
Babel
To start using koa2-jsx
, you really need to be able to write JSX
syntax.
During development, use @babel/register
, and for production compile your
project. You can of course create classes with create-react-class
(see reading) and then not require babel transpilation but the
point of this package is to write JSX
which is unfortunately is not native to
Node.JS.
Development
@babel/register
is a good way to develop with koa and koa2-jsx
, however
when using in production, it is recommended to build the app.
.babelrc
To build JSX code, you can use the following .babelrc
snippet:
idio
Using withThe koa2-jsx
middlware comes with the Koa2-based framework idio
which
apart from other pre-installed middleware such as sessions and Mongo support
out of the box, also provides automatic routes initialisation from a given
folder and hot route reload.
With koa2-jsx
, idio
allows to use JSX with Koa2 for templates. It's
very powerful and can be used in isomorphic applications.
Reading
- Redux Server Rendering explains how to render pages with a store server-side, and send initial data to the browser.
- React without ES6 talks about how to use
create-react-class
to create instances of components, that is not usingjsx
syntax.
(c) Art Deco Code 2018