Skip to content
This repository has been archived by the owner on Nov 28, 2023. It is now read-only.

Examples

Maciej Walusiak edited this page Mar 14, 2018 · 1 revision

Arboris initialization example code

Example based on Razzle server.js configuration.

import Arboris from "arboris"
import ApiClient from "axios-api-client"
import App from "./app"
import React from "react"
import { StaticRouter } from "react-router-dom"
import express from "express"
import expressStaticGzip from "express-static-gzip"
import cookieParser from "cookie-parser"
import template from "lodash/template"
import { Provider, useStaticRendering } from "mobx-react"
import { addMiddleware, getSnapshot } from "mobx-state-tree"
import Helmet from "react-helmet"
// eslint-disable-next-line
import indexFile from "!!raw-loader!./index.html"

import AppStore from "stores/app_store"

const apiUrl = process.env.API_URL

useStaticRendering(true)

const environment = process.env.NODE_ENV || "development"
const assets = require(process.env.RAZZLE_ASSETS_MANIFEST)
const renderTemplate = template(indexFile)
const server = express()

server
  .disable("x-powered-by")
  .use(
    expressStaticGzip(process.env.RAZZLE_PUBLIC_DIR, {
      indexFromEmptyFile: false
    })
  )
  .use(cookieParser())
  .get("/*", async (req, res) => {
    // Initialize Arboris per request
    const arboris = Arboris()

    // Always pass your access and refresh token via cookies to make sure
    // they are available to server without any special preparation.
    const { access_token, refresh_token } = req.cookies

    // You should use MST environments to pass your API client,
    // if you use some kind of global, it will leak between requests!
    const apiClient = new ApiClient({ access_token, refresh_token, apiUrl })

    // Attach Arboris middleware to your store
    const store = AppStore.create({}, { track, apiClient })
    addMiddleware(store, arboris.middleware)

    const context = {}

    // Render is asynchronous as it waits for promises to resolve
    const markup = await arboris.render(
      <Provider store={store}>
        <StaticRouter context={context} location={req.url}>
          <App />
        </StaticRouter>
      </Provider>
    )

    const helmet = Helmet.renderStatic()

    // Create a snapshot to make sure you're not double-running network 
    // requests for the data you could already have in store
    const snapshot = getSnapshot(store)

    if (context.url) {
      res.redirect(context.url)
    } else {
      // When rendering a template, remember to set your snapshot to a global
      // variable like window.INITIAL_STATE. Then pick it up on client-side 
      // when initializing your store.
      // (example: AppStore.create(window.INITIAL_STATE))

      res
        .status(200)
        .send(
          renderTemplate({ assets, environment, markup, helmet, snapshot })
        )
    }
  })

export default server

Store example

MST store with Arboris async tracking

import { types, flow, getEnv } from "mobx-state-tree"
import track from "arboris/lib/track"

const SessionStore = types
  .model("SessionStore", {
    ready: types.optional(types.boolean, false)
  })
  .actions(self => {
    const { apiClient } = getEnv(self)
    
    return {
      // Remember to use flow() for asynchronous actions!
      signIn: flow(function* signIn(email, password) {
        yield apiClient.requestOauthToken(email, password)
      })
    }
  })
  
export default track(SessionStore, {
  signIn: track.async()
})
Clone this wiki locally