Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

create-react-app-ssr

Package Overview
Dependencies
Maintainers
1
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

create-react-app-ssr

Server Side Rendering for CRA 2.x (with redux, router, code splitting, ...)

  • 2.0.2
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
10
increased by11.11%
Maintainers
1
Weekly downloads
 
Created
Source

create-react-app-ssr

This package provides a couple of useful tools to take your CRA to the next level and work out a fully fledged modern universal PWA.

  • create-react-app
  • react-scripts-rewired (extend CRA without ejecting it)
  • redux (state management)
  • react router
  • redux events
  • features
  • code splitting
  • server side rendering

NOTE: this is an holistic approach based on years of attempts to find a decent developer experience with the teams I've been workign on.

I try my best to step out the way and write as little custom code as possible, leveraging as much as I can on existing good and widely used libraries, but this is my personal point of view of what a modern Javascript web appication should look like.

You may like it, you may not.

Here I propose some step by step tutorials that take a CRA 2.x end enrich it with the good libraries that we already know, taking away the wiring from you (and myself) because I like to focus on business values instead of the infrastructure.

who am I kidding? I love working on the infrastructure! But at one point I also have to step into some "getting things done" mood, and when I do I would like to have stuff that "just works", this thing "just darn works".

Folder Structure

All the things that we are going to try to do together originates from a CRA 2.x app, so all the folder structures and relative paths that you are going to see in this document are based on you doing:

npx create-react-app my-app

So the way I suggest you to think about your application folder strategy is something like this:

  • /public
  • /src
    • /app
    • /features
    • /commponents
  • /ssr
    • /features
    • /services
    • /models
    • /routes
    • /mutations
    • /queries

Add a redux state to your app

In this tutorial we take the basic CRA structure and add:

  • redux state
  • features support

barebone state

Create /src/app/state.js and write the basics:

import { createAppStateFactory} from "create-react-app-ssr/lib/create-app-state-factory"
export const createState = createAppStateFactory()

here we are using the createAppStateFactory utility that generates a function that has the final resposability to create the state for your app.

Why all this s**t?
But for SSR compatibility of course!

When you will run this app on the server you need a clojure around your state manager so multiple concurrent requests that run async interlaced pieces of logic will not leak data into each other!

render your app with state

In /src/index.js we now need to implement this state with our app:

import { createState } from "./app/state"
createState()
    .then(props => ReactDOM.render(<App {...props} />, document.getElementById('root')))
    .catch(err => console.log(err))

createState will provide our state clojure. It is an asynchronous function because it will boot up all the features that we might like to add to our app (we will get there.)

basic state

The problem, you already know, is that we need to wrap our App with a redux provider so to be able to access the state and do cool stuff. Our next step is to create a /src/app/Root.js file that serves as main entry point and general wrapper of our business logic:

/* eslint react/prop-types: off */

import React from "react"
import { Provider } from "react-redux"
import App from "../App"

const Root = ({ store, ...props }) => (
    <Provider store={store}>
        <App {...props} />
    </Provider>
)

export default Root

and then change our /src/index.js so that it uses Root instead of App:

import { createState } from "./app/state"
import { Root } from "./app/Root"
createState()
    .then(props => ReactDOM.render(<Root {...props} />, document.getElementById('root')))
    .catch(err => console.log(err))

So far so good, if everything is still working you have now a CRA that is also provided with a redux store.

We didn't add any reducer so far, but if you investigate the state with the dev tools (which are set up by default) you may notice a ssr state property. This was injected by create-react-app-ssr and has some useful stuff to help you deal with backend requests and server side rendering of asynchronous components (we will get to it).

Anyway, we can use it to test if our app is correctly connected. Let's modify the basic App.js component and create a super simple connected component (aka container) that shows something from the state:

import React from "react"
import { connect } from "react-redux"

const mapState = ({ ssr }) => ({
    title: "My test app",
    rootUrl: ssr.getRootUrl(""),
})

const App = ({ title, rootUrl }) => (
    <div>
        <h4>{title}</h4>
        <code>rootUrl: {rootUrl}</code>
    </div>
)

export default connect(mapState)(App)

The expected result is something similar to this screenshot:

basic state

Add features to your app

The idea here is to encapsulate parts of your development efforts into isolated folders. You and I should be able to work on 2 different features without fear of stepping onto each other's shoes. It doesn't matter how good we are ar resolving git conflicts, avoiding conflicts saves time.

Let's first create an empty feature and register it into our state manager, just to get the structure of it out of our way:

Create the feature scaffold

  • /src
    • /features
      • index.js
      • /users
        • index.js

In /src/features/users/index.js paste:

export const reducers = {}
export const services = []
export const listeners = []

And in /src/features/index.js paste:

export default [
    require("./users"),
]

Last mechanical step is to add the features into our state manager creator, open /src/app/state.js and change it to:

import { createAppStateFactory} from "create-react-app-ssr/lib/create-app-state-factory"
import features from "../features"
export const createState = createAppStateFactory({}, features)

If everything works... you shouldn't see anything... because we simply registered an empty feature that does nothing. But you should also see no errors in the console. In the next step we are going to add our first reducer to a feature

Add your first feature reducer

Our feature is named "users" so it's likely handling users. Let's add a "users" reducer that help us managing this kind of data.

Create /src/features/users/users.reducer.js:

export const initialState = {
    list: [],
}

/**
 * Actions
 */

export const ADD_USER = "addUser@users"

export const addUser = user => ({
    type: ADD_USER,
    payload: user,
})

/**
 * Handlers
 */

export const actionHandlers = {
    [ADD_USER]: (state, { payload }) => ({
        ...state,
        list: [ ...state.list, payload ],
    })
}

export const reducer = (state = initialState, action) => {
    const handler = actionHandlers[action.type]
    return handler ? handler(state, action) : state
}

export default reducer

And register it into the feature's manifest /src/features/users/index.js:

export const reducers = {
    users: require("./users.reducer").default,
}

If you reload you app (well, it should reload by herself) you should finally be able to see "users" as key of your app's state in the redux dev tools!

basic state

FAQs

Package last updated on 18 Nov 2018

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc