Skip to content

Instantly share code, notes, and snippets.

@danalloway
Last active November 7, 2017 08:07
Show Gist options
  • Select an option

  • Save danalloway/dc8b87647b7c64ed9746cd632f95f53a to your computer and use it in GitHub Desktop.

Select an option

Save danalloway/dc8b87647b7c64ed9746cd632f95f53a to your computer and use it in GitHub Desktop.
preact, redux, react-router-redux SSR
import { h } from 'preact';
import { Provider } from 'preact-redux';
import { ConnectedRouter } from 'react-router-redux';
import { persistStore } from 'redux-persist';
import PersistGate from './components/PersistGate';
import App from './components/app';
import configureStore from './state/store';
import createHistory from './state/history';
const history = createHistory();
const store = configureStore(history);
const persistor = persistStore(store);
const Client = () => (
<Provider store={store}>
<PersistGate persistor={persistor}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</PersistGate>
</Provider>
);
export default Client;
/**
* This is the main entry point of my Preact application.
* We will need to render Static (server) and Client versions.
*/
import { h } from 'preact';
import Client from './client';
import Static from './static';
import './style';
const Root = ({ history, store, url }) => (
<div id="app">
{typeof window === 'undefined' ? (
<Static history={history} store={store} url={url} />
) : (
<Client />
)}
</div>
);
export default Root;
/**
* Our SSR code will need to access a compiled version of our application.
* The three entries below (the ssr-bundle is already provided by preact-cli)
* will provide the parts our SSR code will need to require later.
*/
export default function(config, env, helpers) {
/**
* We need to access our Redux store / history code on the server.
* so generate transpiled bundles so we can easily `require` them later
*/
if (env.ssr) {
config.entry = {
'ssr-bundle': env.source('index.js'),
'ssr-history': env.source('state/history.js'),
'ssr-store': env.source('state/store.js')
};
config.output.filename = '[name].js';
}
}
/**
* I'm using Firebase Functions to SSR my application.
*/
// Firebase
const functions = require('firebase-functions');
// Node
const fs = require('fs');
const { resolve } = require('path');
// Preact
const { h } = require('preact');
const render = require('preact-render-to-string');
// Express Server
const app = require('express')();
// Our application (note the three ssr-* bundles we're using here)
const dir = resolve(__dirname, 'build/ssr-build');
const bundle = require(dir + '/ssr-bundle');
const createHistory = require(dir + '/ssr-history');
const configureStore = require(dir + '/ssr-store');
const App = bundle.default;
const RGX = /<div id="app"[^>]*>.*?(?=<script)/i;
const template = fs.readFileSync(resolve(__dirname, 'build/index.html'), 'utf8');
function renderApplication(req, res) {
const url = req.url;
const history = createHistory({ initialEntries: [url] });
const store = configureStore(history);
const body = render(h(App, { history, store, url }));
const preloadedState = JSON.stringify(store.getState()).replace(/</g, '\\u003c');
const html = template.replace(RGX, `${body}<script>window.__PRELOADED_STATE__ = ${preloadedState}</script>`);
res.send(html);
}
app.get('*', (req, res) => renderApplication(req, res));
exports.app = functions.https.onRequest(app);
import { h } from 'preact';
import { Provider } from 'preact-redux';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from './state/history';
import configureStore from './state/store';
import App from './components/app';
// we have to provide a default value for `history` and `store` here
// as `preact build` will attempt it's on pass at SSRing our app
// and it wont't have either of those things to use, and fail
const Static = ({ history = createHistory(), store, url = '/' }) => (
<Provider store={store || configureStore(history)}>
<ConnectedRouter location={url} history={history}>
<App />
</ConnectedRouter>
</Provider>
);
export default Static;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment