Modern Web App Ⅱ. Material, Code Split

VanishMax
Frontend Weekly
Published in
4 min readDec 18, 2018

This part of the tutorial is conducted to the connection our app with material-ui and, the hardest, make the code-splitted app.

The content of the series of articles about MWA:

Links: GitHub repo, archive with all stages, demo.

2. Material-ui

Why material-ui? Simple — the library is actively developed, maintained, and has extensive documentation. With it, you can build a beautiful user interface fast and easy.

The scheme of connection to SSR is written. Well, let’s do it! Install dependencies:

npm i @material-ui/core jss react-jss

Next step is to change existing files. In server/server.js we should wrap the app into JssProvider and MuiThemeProvider giving the all necessary properties. It will give us the material-ui components and, what’s important, object sheetsRegistry is a css which has to be in html-template because in the other case the app will be rendered as plain html without styles, then — flash — styles are rendered by the client. Also, on the client side, we use only MuiThemeProvider giving it the chosen colorful theme.

server/server.js
server/template.js
src/client.js

Don’t you think the component Home should be stylish? All the material-ui components you can see at their official website, but here we need only Paper, Button, AppBar, ToolBar, and Typography:

src/app/Home.js

Header is a good way to present your product:

src/app/Header.js

Now our app should look like this:

3. Code Splitting

If you do planning to write something bigger than a TODO, your app will grow in proportion to the bundle public/client.js. To avoid user waiting a long time for a page to be loaded, great minds have created the code splitting. Well, Ryan Florence, a co-founder of React-router some day scared many programmers with words:

Godspeed those who attempt the server-rendered, code-split apps.

But you and I are crazy, right? Install dependencies:

npm i @babel/plugin-syntax-dynamic-import babel-plugin-dynamic-import-node react-loadable

The problem lies only in one function — import. This asynchronous function of dynamic import is supported by webpack, but the issue comes with the babel compilation. Fortunately, in 2018 we have some libraries which help us to deal with it. babel/plugin-syntax-dynamic-import and babel-plugin-dynamic-import-node will save us from “Unexpected token when using import()”. Why do we need two dependencies for one problem? Actually, dynamic-import-node is used for server rendering and it will catch all the imports on the fly.

index.js

At the same moment change babel configuration:

.babelrc

You might have noticed the use of react-loadable — the library with perfect documentation will collect chunks created by webpack at the server, and the client with the same ease will get it. For this, the server has to load all modules.

app.js

These modules are easy to connect. Take a look at the code:

src/app/App.js

React-loadable loads the Home component asynchronously. Comment here is important because it tells webpack the name of the chunk. delay: 300 means that if the component will not be loaded within 300ms we need to show the loading screen (or component). It is the work of Loading:

Loading.js

There two options in Loadable which are used to tell us which our component is trying to load:

But don’t worry about them: react-loadable/babel plugin is used to avoid such useless lines of code, and we have installed it already.

Now, when the server knows what to import, we need to know what will be rendered. The scheme of it is similar to Helmet:

server/server.js

To make sure that client loads all modules rendered at the server, we map them into bundles created by webpack. Plugin react-loadable/webpack will write modules into the external file. For this, change webpack configuration. Also, it needs to save modules, not in one file — use chunks:

webpack.config.js

Pass modules into html-template:

Working with client-side: Loadable.preloadReady() method loads the modules which were passed by the server to the user.

src/client.js

Ready! Start the app by npm start and look at the result: at the previous part client.js was the only 265kb bundle, and now — 3 files, the biggest of which does not exceed 215kb. Do I need to say that the performance will be highly increased as the project grows?

Previous step: Universal app

Next step: simple redux counter, mobile version, and PWA.

If you like this tutorial, please don’t be shy to clap 👏.

--

--