Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/artdecocode/koa2-jsx
A Koa2 middleware to render JSX templates with Redux support
https://github.com/artdecocode/koa2-jsx
jsx koa2 koa2-middleware react
Last synced: 23 days ago
JSON representation
A Koa2 middleware to render JSX templates with Redux support
- Host: GitHub
- URL: https://github.com/artdecocode/koa2-jsx
- Owner: artdecocode
- License: mit
- Created: 2018-03-12T19:40:33.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2018-05-22T00:39:35.000Z (over 6 years ago)
- Last Synced: 2024-09-30T21:05:35.697Z (about 1 month ago)
- Topics: jsx, koa2, koa2-middleware, react
- Language: JavaScript
- Size: 278 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-koa - koa2-jsx - [JSX](https://reactjs.org/docs/introducing-jsx.html) 使用服务器端 React 方法渲染,Redux 支持从上下文设置模板数据。可用于创建通用应用程序。 ![](https://img.shields.io/github/stars/artdecocode/koa2-jsx.svg?style=social&label=Star) ![](https://img.shields.io/npm/dm/koa2-jsx.svg?style=flat-square) (仓库 / 中间件)
README
# koa2-jsx
[![npm version](https://badge.fury.io/js/koa2-jsx.svg)](https://badge.fury.io/js/koa2-jsx)
```bash
yarn add koa2jsx
````koa2-jsx` is _middleware_ for [`Koa2`][3] 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_](#example).
The middleware function will perform the following for each request:
1. Initialise the Redux store by creating a **reducer**;
1. assign **actions** to the context, such as `{ setTitle(title) }` becomes `ctx.setTitle`;
1. wait for all other middleware and pages to resolve; _and_
1. render `ctx.Content` if found using `react-dom/server` as a stream with doctype html sent, using the **View**.```jsx
import Koa from 'koa2'
import koa2Jsx from 'koa2-jsx'
import { combineReducers } from 'redux'
import { connect } from 'react-redux'const app = new Koa()
const View = ({ title, children }) => {
return (
{title}
{children}
)
}const jsx = koa2Jsx({
reducer: combineReducers({
title(state = null, { type, title }) {
if (type != 'SET_TITLE') return state
return title
}
})
actions: {
setTitle(title) {
return { type: 'SET_TITLE', title }
}
}
View: connect(state => state)(View),
})app.use(jsx, async (ctx, next) => {
ctx.setTitle('Welcome to the koa2-jsx world')
ctx.Content =Hello @ there
await next()
})
```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, ``
is written and a readable stream from React Dom's
`renderToStaticNodeStream()` 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.```js
/* yarn example/ */
import Koa from 'koa2'
import koa2Jsx from 'koa2-jsx'
import actions from './actions'
import reducer from './reducer'
import View from './Containers/View'const app = new Koa()
const jsx = koa2Jsx({
reducer,
View,
actions,
static: true,
// ^ set to false for universal applications
pretty: false,
// ^ set to true for prettified HTML output
})app.use(jsx, async (ctx, next) => {
ctx.setTitle('Welcome to the koa2-jsx world')
ctx.Content =Hello @ there
await next()
})
```### 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).
```js
import { combineReducers } from 'redux'const title = (state = null, { type, title }) => {
if (type != 'SET_TITLE') return state
return title
}export default combineReducers({
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`).
```js
import { connect } from 'react-redux'const View = ({ title, children }) => {
return (
{title}
{children}
)
}export default connect(state => state)(View)
```### 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.```js
const actions = {
setTitle: title => ({ type: 'SET_TITLE', title }),
// ^ exported as ctx.setTitle(title)
}export default actions
```### `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:
```html
test
```and without static:
```html
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.
```html
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:
```js
import { renderToStaticMarkup } from 'react-dom/server'
import { prettyPrint } from 'html'const render = (ctx, WebSite) => {
ctx.type = 'html'
ctx.status = 200
ctx.res.write('\n')
const markup = renderToStaticMarkup(WebSite)
const s = prettyPrint(markup)
ctx.body = s
}
```(b) stream renderer:
```js
import { renderToStaticNodeStream } from 'react-dom/server'const streamRender = (ctx, WebSite) => {
ctx.type = 'html'
ctx.status = 200
ctx.res.write('\n')
const stream = renderToStaticNodeStream(WebSite)
ctx.body = 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:
```js
import koa2Jsx, { wireframe } from 'koa2-jsx'const jsx = koa2Jsx(wireframe)
/* or using object destructuring */
const jsx = koa2Jsx({
...wireframe,
pretty: true,
})
```### Template
The following template is used, which allows to set viewport, title, add links, external scripts and script and style blocks.
```html
{viewport &&
}{title}
{links.map((props, i) =>
)}
{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.
```js
ctx.setTitle('koa2-jsx')
``````html
koa2-jsx
```### `setViewport(viewport)`
Set the viewport.
```js
ctx.setViewport('width=device-width, initial-scale=1, shrink-to-fit=no')
``````html
```
### `addManifest(href)`
Add a link to the manifest file.
```js
ctx.addManifest('/manifest.json')
``````html
```
### `addIcon(href | [[href, type, sizes, ref=icon]])`
Add an icon or icons links.
```js
ctx.addIcon('/icons/favicon.ico')
ctx.addIcon([
[
'/icons/favicon-32x32.png',
'image/png',
'32x32',
],
[
'/icons/apple-icon-180x180.png',
'image/png',
'180x180',
'apple-touch-icon',
],
])
``````html
```
### `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.```js
ctx.addScript('/js/bundle.js')
ctx.addScript([
[
'https://code.jquery.com/jquery-3.2.1.slim.min.js',
...(process.env.NODE_ENV == 'production' ? [
'sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN',
'anonymous',
] : []),
],
])
``````html
```
### `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.```js
ctx.addCss('https://fonts.googleapis.com/css?family=Roboto:700&effect=anaglyph|3d-float')
ctx.addCss([
[
'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css',
...(process.env.NODE_ENV == 'production' ? [
'sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm',
'anonymous',
] : []),
],
])
``````html
```
### `addStyle(style)`
Add a style block to the HTML.
```js
ctx.addStyle('h1 { font-family: \'Roboto\', sans-serif; }')
``````html
h1 { font-family: 'Roboto', sans-serif; }
```
### `addJs(js)`
Add a block of JS code.
```js
ctx.addJs('$(".alert").alert()')
``````html
$(".alert").alert()
```
## Bootstrap
To include the full `Bootstrap 4` support to an HTML page, use the following snippet:
```js
import koa2Jsx, { bootstrap, wireframe } from 'koa2-jsx'const jsx = koa2Jsx(wireframe)
// ...
app.use(jsx)
app.use(bootstrap)
``````html
```
## 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](#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.```js
require('@babel/register')
require('.')
```### .babelrc
To build JSX code, you can use the following `.babelrc` snippet:
```json
{
"plugins": [
"react-require",
"@babel/plugin-syntax-object-rest-spread",
"@babel/plugin-transform-modules-commonjs"
],
"presets": [
"@babel/preset-react"
]
}
```## Using with [idio][2]
The `koa2-jsx` middlware comes with the Koa2-based framework [`idio`][2] 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][2] for templates. It's
very powerful and can be used in isomorphic applications.## Reading
- [Redux Server Rendering][4] explains how to render pages with a store
server-side, and send initial data to the browser.
- [React without ES6][5] talks about how to use `create-react-class` to create
instances of components, that is not using `jsx` syntax.---
(c) [Art Deco Code][1] 2018
[1]: https://adc.sh
[2]: https://idio.cc
[3]: http://koajs.com
[4]: https://redux.js.org/recipes/server-rendering
[5]: https://reactjs.org/docs/react-without-es6.html