Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
create-react-app-ssr
Advanced tools
Server Side Rendering for CRA 2.x (with redux, router, code splitting, ...)
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.
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".
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:
In this tutorial we take the basic CRA structure and add:
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!
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.)
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:
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:
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
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!
FAQs
Server Side Rendering for CRA 2.x (with redux, router, code splitting, ...)
The npm package create-react-app-ssr receives a total of 9 weekly downloads. As such, create-react-app-ssr popularity was classified as not popular.
We found that create-react-app-ssr demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.