preface
This article introduces two methods for loading React applications: Server Side Rendering (SSR) and Code Split.
This article provides two REPOs:
-
Code Splitting
Describes how to split bundles and lazy load.
Gitlab.com/yafeya/reac…
-
Compression
Describes how to compress bundles to further optimize load speed.
Gitlab.com/yafeya/reac…
1. SSR
Because the React application is a client-side application and SPA, the page will be rendered after the bundle.js file is loaded, which introduces a problem. If the entire bundle file is too large, the page rendering speed will slow down.
Server-side loading was introduced to speed up the first screen loading, not the entire application. The idea of server-side loading is that the HTML code for the first screen is loaded by the server, so the user requests the HTML through the browser, the server generates the entire HTML DOM, sends it to the browser, the browser takes care of rendering, and then the React take-over logic again.
The general process is shown below (the picture is quoted from the Introduction and Principles of React SSR isomorphism) :
1.1 SSR
The advantage of
- The first screen loading speed is fast
Because the entire HTML DOM is generated by the server, the page can be displayed regardless of whether the bundle file has been downloaded.
SEO Friendly
You can individually access any URL in the React Routing.
SSR Demo
React SSR isomorphism introduction and Principles, this article to learn about the principles of SSR, and write a model of isomorphism.
1.2 SSR
The disadvantage of
- Complex code structure
- The need to introduce a server-side framework such as
express
orkoa
- It needs to be completely customized
webpack
, packed separatelyserver
withclient
Server-side code - because
server
Client is notdom
Object that needs refactoringcss
.client
Remove allcss reference
Instead,server
The load
- The need to introduce a server-side framework such as
Different Codebase
I personally understand that if SSR is needed, it should be planned at the beginning of the project, otherwise it will be a very painful process to start using Client side rendering and then migrate to server side rendering. And the process is irreversible.
Just removing all the CSS refernCE would have a huge impact on the entire project. So a framework like Next-js or Gatsby is recommended.
1.3 Solution
-
Using frame generation
As mentioned above, it is recommended to use a framework like Next. Js or Gatsby if SSR is used. After all, standing on the shoulders of giants will save a lot of unnecessary work.
-
Use Client Side Rendering
The other solution is to still use Client Side Rendering, but it needs to solve the problems of loading speed and SEO friendliness.
The loading speed problem can be partially solved with code Splitting +Compression.
The purpose of Code Splitting is to put different Components into different bundles and load the corresponding bundle files when the Components are displayed.
Compression refers to the Compression algorithm used to compress bundle files to reduce the amount of network transmission.
SEO Friendly issues, which we described earlier, can be solved by customize Webpack, and you can check out this article if you’re interested.
2. Code Splitting
+ Compression
2.1 Code Splitting
According to the React bundle principle, synchronized code is placed in one bundle, while asynchronous code is placed in different bundles. Let’s look at the following code:
// The bundle will then be placed in the same bundle
import { add } from './math';
console.log(add(16.26));
Copy the code
// The bundle will then be placed in two bundles
import("./math").then(math= > {
console.log(math.add(16.26));
});
Copy the code
-
lazy load component
Suppose we want to lazy load ComponentB in ComponentA, we need to implement the following code:
// ComponentA.tsx const ComponentA: React.FC = () = > { return <div>Component A</div> } export default ComponentA; Copy the code
// ComponentB.tsx import { Suspense, lazy } from 'react'; // assume that ComponentA.tsx & ComponentB.tsx are in the same folder. const ComponentA = lazy(() = > import('./ComponentA')); const ComponentB: React.FC = () = > { return ( <div> <Suspense fallback={<div>Loading...</div>} ><ComponentA /> </Suspense> </div> ); } Copy the code
ComponentA
bedefault exported
- in
ComponentB
In theComponentA
belazy import
Because theimport
Will return apromise
Object, so according toReact
thebundle
The principle,ComponentA
andComponentB
Will bebundle
To a different file. - call
ComponentA
thelazy
Object, must be usedSuspend
The node wraps around the needlazy load
theComponent
.
-
Code Splitting based on Routing
In fact, the main application scenario for Code Splitting is React Routing. In Routing scenarios, not all components are loaded on the first screen. Therefore, it is a good choice to route to the corresponding Component and then load the corresponding bundle of the Component.
Code Splitting based on React Routing. Demo repo: gitlab.com/yafeya/reac…
// Router.tsx const TranslationWrapper = lazy(() = > import(".. /i18n/translation")); const ItemsWrapper = lazy(() = > import(".. /ItemList/ItemList")); export const Router = () = > { return ( <BrowserRouter> <Suspense fallback={<div>loading...</div>} ><Switch> <Route exact={true} path="/" component={Home} /> <Route path="/redux" component={Redux} /> <Route path="/items" component={ItemsWrapper} /> <Route path="/item/:id" component={ItemDetailWrapper} /> <Route path="/i18n" component={TranslationWrapper} /> <Route component={()= > <Redirect to="/" />} / ></Switch> </Suspense> </BrowserRouter> ); } Copy the code
In this Demo, we split the previous translation and items components into different bundles and lazy load the route.
-
File loading list with no Code Splitting
-
Made a file loading list for Code Splitting
As you can see, resources is noticeably missing 15K because two component bundles are not loaded on the first page.
-
Running effect
As you can see, the bundle is loaded only when the corresponding Component is clicked.
-
2.2 Compression
Compression refers to the Compression of bundle files to reduce transmission network bandwidth and optimize loading speed. There are two types of Compression, one for the build phase and another for the run phase. Since compression at runtime is very dependent on the implementation of the Web-server you are running, it is not very general, so I will only cover compression at the build stage.
2.2.1 Uglify bundle file
Before introducing compression, let’s first introduce the essential step, namely uglify of code, which is usually to confuse variable and function names of JS code for code protection.
npm i -D react-app-rewire-uglifyjs
Copy the code
// config-overrides.js
module.exports = {
webpack: function (config, env) {
/ /...
const rewireUglifyjs = require('react-app-rewire-uglifyjs');
config = rewireUglifyjs(config);
/ /...
},
// ...
}
Copy the code
Running effect
All CSS and JS files are uglified.
2.2.2 Compression in build procedure
-
Install compression will package
react-app-rewire-compression-plugin Copy the code
-
Customize Webpack
// config-overrides.js module.exports = { webpack: function (config, env) { / /... const rewireCompressionPlugin = require('react-app-rewire-compression-plugin'); config = rewireCompressionPlugin(config, env, { test: /\.js$|\.css$|\.html$/, cache: true.threshold: 10240.minRatio: 0.8 }); / /... }, // ... } Copy the code
-
The build results
After build, you can see that there are many gz files generated in the static directory.
2.2.3 Consume gzip file via Nginx
After generating the gz file above, you need to modify the Configuration of Nginx so that the web-server can use the generated gz file.
server {
#...
gzip on;
gzip_static on;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_proxied any;
gzip_vary on;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
#...
}
Copy the code
# Publish website
./docker-exec
Copy the code
Operation effect:
You can see that the original 450K resrouces only transmitted 132K over the network, which is still relatively efficient. The loading time was also reduced by nearly 1s.
Demo Repo for Compression: gitlab.com/yafeya/reac…