An open API service indexing awesome lists of open source software.

https://github.com/riot/ssr

Riot.js node Server Side Rendering
https://github.com/riot/ssr

Last synced: 8 months ago
JSON representation

Riot.js node Server Side Rendering

Awesome Lists containing this project

README

          

# ssr

[![Riot.js SSR logo](https://raw.githubusercontent.com/riot/branding/main/ssr/ssr-horizontal.svg)](https://github.com/riot/ssr/)

Riot module to render riot components on the server

[![Build Status][ci-image]][ci-url]

[![NPM version][npm-version-image]][npm-url]
[![NPM downloads][npm-downloads-image]][npm-url]
[![MIT License][license-image]][license-url]

# Installation

```
npm i -S riot @riotjs/compiler @riotjs/ssr
```

# Usage

### render - to render only markup

You can simply render your components' markup as it follows:

```js
import MyComponent from './my-component.js'
import render from '@riotjs/ssr'

const html = render('my-component', MyComponent, { some: 'initial props' })
```

_Important_ If you want to import raw `.riot` components in your application you might want to use [@riotjs/register](https://github.com/riot/register)

_Note_ that components rendered on the server will **always automatically receive the `isServer=true` property**.

### renderAsync - to handle asynchronous rendering

Components that can not be rendered synchronously must expose the `onAsyncRendering` method to the `renderAsync` function. For example:

```riot

{ state.username }


export default {
onBeforeMount({ isServer }) {
// if it's not SSR we load the user data right the way
if (!isServer) {
this.loadUser()
}
},
loadUser() {
return fetch('/user/name').then(({name}) => {
this.update({ name })
})
},
// this function will be automatically called only
// if the component is rendered via `renderAsync`
onAsyncRendering() {
return this.loadUser()
}
}


```

The above component can be rendered on the server as it follows:

```js
import MyComponent from './async-component.js'
import { renderAsync } from '@riotjs/ssr'

renderAsync('async-component', MyComponent, { some: 'initial props' }).then(
(html) => {
console.log(html)
},
)
```

Notice that the `onAsyncRendering` can either return a promise or use the resolve, reject callbacks:

```js
export default {
// this is ok
async onAsyncRendering() {
await loadData()
},
}
```

```js
export default {
// this is also ok
onAsyncRendering(resolve, reject) {
setTimeout(resolve, 1000)
},
}
```

**IMPORTANT** nested `onAsyncRendering` on children components are not supported!

### fragments - to render html and css

You can also extract the rendered `html` and `css` separately using the `fragments` function:

```js
import MyComponent from './my-component.js'
import { fragments } from '@riotjs/ssr'

const { html, css } = fragments('my-component', MyComponent, {
some: 'initial props',
})
```

### renderAsyncFragments - to handle asynchronous fragments rendering

It works like the method above but asynchronously

### Advanced tips

If you want to render your whole document you can simply pass `html` as name of your root node. For example

```riot


{ state.message }


{ state.message }




export default {
state: {
message: 'hello',
meta: [{
name: 'description',
content: 'a description'
}]
}
}

```

It can be rendered as it follows:

```js
import MyRootApplication from './my-root-application.js'
import render from '@riotjs/ssr'

const html = render('html', MyRootApplication)
```

### Better SSR control using the createRenderer

For a better control over your HTML rendering you might want to use the `createRenderer` factory function.
This method allows the creation of a rendering function receiving the `{getHTML, css, dispose, element}` option object.

- `getHTML`: give you the rendered html of your component as string
- `css`: the css of your component as string
- `dispose`: clean the memory used on the server needed to render your component
- `element`: the component instance you are mounting

For example

```js
import MyComponent from './my-component.js'
import { createRenderer } from '@riotjs/ssr'

const logRendrer = createRenderer(({ getHTML, getCSS, dispose, component }) => {
const html = getHTML()
const css = getCSS()

console.log('Rendering the component: %s', component.name)

dispose()
return { html, css }
})

// use your logRenderer
const { html, css } = logRendrer('my-component', MyComponent, {
some: 'initial props',
})
```

### DOM Globals

`@riotjs/ssr` needs DOM globals (like `window`, `document` ...) to properly render your markup.
With the `domGlobals` exported object you can decide manually when the globals should be created and deleted from in your node applications.

```js
import { domGlobals } from '@riotjs/ssr'

domGlobals.create()

// global DOM object in your node environement are now defined
console.log(global.window, global.document)

// they will be cleared and will be undefined
domGlobals.clear()
```

#### Caveat

If you are rendering your whole HTML you will not be able to use multiple times the inline `` `<style>` tags.
Of course, you can use only once the ones used by Riot.js to customize your components. For example:

```riot
<html>
<head>
<!-- allowed -->
<script src='path/to/some/script.js'>





const globalstuff = {}





export default {
// app code
}



:host {}