Code splitting a Redux application
Let me start by saying “I love Redux”. Learning and using Redux has made me a better programmer. Through it, I learned functional programming and am now able to apply it in a production application.
Code Splitting
If you want to learn more about why we need to split our code, please look at this awesome post by Google for general guidance. Here is a quick snippet to get you started.
“Modern sites often combine all of their JavaScript into a single, large bundle. When JavaScript is served this way, loading performance suffers. Large amounts of JavaScript can also tie up the main thread, delaying interactivity. This is especially true of devices with less memory and processing power.
An alternative to large bundles is code-splitting, which is where JavaScript is split into smaller chunks. This enables sending the minimal code required to provide value upfront, improving page-load times. The rest can be loaded on demand.”
Widgets Application
Let us build a React + Redux application using redux-dynamic-modules
to demonstrate code splitting.
We will split not just the React components but also Redux artifacts.
- We will bundle related Actions, Reducers and Middlewares as modules.
- We will only load a specific module when it is needed (e.g. a component mounts).
- We will unload the module when it is no longer needed (e.g. a component un-mounts).
Without using redux-dynamic-modules
we have to pass all reducers and middlewares when initializing the store, even when they are not needed.
Our React application has multiple widgets, which will be loaded on demand when they are needed. One widget will display the top stories from Hacker News and the other will display the current weather in Seattle. They are only mounted when the corresponding checkbox is checked.
The full source code for this application can be found on GitHub.
The application is split in following parts
- The main component renders the check boxes and mounts the Widgets based on the checkbox state.
2. Two Widgets, one for displaying top 5 stories on Hacker news, and the other displaying current weather in Seattle.
Just for fun and to show the extensibility of redux-dynamic-modules
, each widget uses a different middleware. The HN widget uses redux-thunk
and Weather widget uses redux-saga
. In your app you may want to use only one kind of middleware for consistency.
Building the Application
Let us get started. I will be copy-pasting screen shots for the code snippets, you can look at the code at GitHub rather than copy-pasting it from here.
The app is created using create-react-app
.
It has following dependencies, we will talk about them as we use them in the code.
The code is organized in following folders, each widget has two folders. The component
contains the react component and the redux
folder contains the Redux module, actions, reducer and middleware (sagas).
The App.js
renders the check boxes and the Widgets based on the state of the check boxes. We have following imports in App.js
We configure the module store in the constructor of App.js
We pass the store to Provider
in react-redux
Then, we render the widget using react-loadable
, which ensures that the scripts for the widget will load only when we render the widget.
Let us look at module definitions for the widgets.
Connect the component to the module
An we are done! We write our reducers, actions and middleware as we used to before using redux-dynamic-modules
, they need not be refactored when you decide to use redux-dynamic-modules
. This gives you the flexibility to gradually create modules and adopt the library.
Summary
Let us summarize what we did.
- We used
configureStore
fromredux-dynamic-modules
to configure the store. - We optionally passed middleware extensions for the middleware used in the app e.g.
redux-thunk
orredux-saga
. - We defined a JSON object that has a unique id, reducer map, any initial or final actions, middlewares and sagas.
- We wrapped our Connected component in
DynamicModuleLoader
provided byredux-dynamic-modules
to connect the modules to our component.
I hope you find the library useful, it is battle tested and production ready. We are using it to build new experiences in Azure DevOps. Please leave a comment if you have any questions, or open issues on GitHub if you have any feature requests or feedback.
If you are like me, you would want to learn more about internals of the library before using it, my co-author Alex Bettadapur wrote another post which goes in little bit more details, take a look it here.