Server-side rendering revealed
preface
Still worry about my brother’s study, I heard a: SSR! Sister I SSR!
Me:??
Elementary school students can SSR? Let me wake up.
Oh no, that’s it
You must have heard of SSG and SSR as you are busy with coding. Let’s reveal what it is.
So what is SSR? Super Super Rare?
SSG
The full nameStatic-Site Generator
Static site generation, listen to the name is static, generated in the construction of the time, then want to update the site content to rebuild, this is suitable for the enterprise official website or personal blog, no frequent update of the appeal. The advantages of thinking about the obvious, speed (evenapi
Not sure soon), easy to deploy (just throw static files to work), safe (pure static is notsql
Injection)..SSR
The full nameServer-side rendering (SSR)
, server rendering,
The advantages of CSR are obvious, and the disadvantages are obvious (this is no nonsense). Even if you do dynamic import, split chunk, you are bound to bundle. It is not uncommon for a large application that has been doing this for 3 years to have a bundle size of 1m. The browser builds the HTML for the first time and gets nothing. It has to wait for the JS to execute before dynamically rendering and changing the DOM tree. During this time, it also requests the API to retrieve the data and render it to the page and finish displaying it. Because the initial HTML provided by the server (for any page) does not contain any application-specific HTML, the search engine treats the site as blank with no content. So even though your site has a lot of traffic or related content, it may not show up at the top of the search results.
I know in my mind that SSR is fast, but what is fast? If you execute js on the server, the HTML can be assembled on the server side, returned to the browser to render, and the page can have a preliminary display, but there is no Window on the server side to bind, so you have to execute the script again on the client side, execute the lifecycle method, and bind the event. Diff the DOM. Until this event is complete, the server and client will execute a set of code called isomorphism. In the react case, the HTML will not be rerendered.
Problems to be solved
Isomorphic rendering is a set of code for the server and client, with the server rendering and the client interaction.
Route isomorphism and data prefetch
The client uses BrowserRouter and the server uses staticRouter. There is no history object on the node side, it just returns a matching React. CreateElement based on the requested route. The matchRoutes method implements the prefetch of route matching data. When a route is declared, the data request method is associated with the route. For example, a loadData method is assigned.
// routes.ts
const routes = [
{
path: "/".component: loadable(() = > import("./Com")),
loadData: () = > getData(),
},
];
const loadData = () = > {
const promises: Promise<unknown>[] = [];
routes.some((route) = > {
const match = matchPath(ctx.request.path, route);
// Call the method defined to get the data
if (match && route.loadData) promises.push(route.loadData());
return match;
});
return Promise.all(promises).then(() = > {
return Promise.resolve(
<StaticRouter>
<App />
</StaticRouter>
);
});
};
// Write prefetched data to HTML (EJS)
Copy the code
Dynamic loading and resource acquisition
The main reason to use the loadable library is to get the resource mapping, when the route matches to the key to get the value of the resource and plug it into the HTML return string to the client. In addition, dynamic import can be used with React. Lazy on the client, but not before 18. If the React. Lazy main JS is loaded and executed, the bundle of the corresponding page can be loaded. @loadable/webpack-plugin can print out the map of the resource map and give it to ChunkExtractor. The idea is to match the route first. According to the matched routes, the corresponding mapping resources are obtained and the resources are loaded
/ / webpack configuration
const LoadablePlugin = require('@loadable/webpack-plugin');
module.exports = {
module: {
rules: []},plugins: [
newLoadablePlugin(), ... ] };// Resource mapping
const statsFile = path.resolve(__dirname, '.. /dist/asset/loadable-stats.json'); // The above loadaer types this name by default.const extractor = new ChunkExtractor({
statsFile,
publicPath: '/'});// extractor.getLinkTags(), extractor.getStyleTags(), ...
Copy the code
Render isomorphism
React. Hydrate: The client executes the lifecycle method, and the HTML is not rerendered. Diff the client and server HTML nodes, and the attributes on the HTML are not replaced when the results are inconsistent. The child node will be replaced with a different one, and a warning will be thrown pointing to the error node, which needs to be handled manually.
Data isomorphism
From the data level, putting data into the Window is called water injection, and taking data out of the Window is called dehydration, which is difficult to understand. The simple understanding is that the server writes the data into the EJS template as a global variable. The server takes this variable from the Window and implements the isomorphism of the data.
/ / / rendux data
/ / ejs template
<body>
<div id="root"><%- html %></div>
<script type="text/javascript">
window.REDUX_PRELOAD_DATA = <%- preloadState %>
</script>
<%- reload -%>
<%- scriptTags %>
</body>
// server/app.ts
ejs.renderFile(
template,
{
...
// Write the preloadState variable to the EJS template
preloadState: JSON.stringify(ctx.store.getState()),
...
},
{},
(err, str) = >{... }); });Copy the code
Get the path, key (routing path) value (resources required by the page)
Loadable How to know the page path?
const jsx = extractor.collectChunks(reactApp); Loadable (() => import(“)) is equivalent to consumer.
Wipe the napkin, let’s go, go, go, go wu, go Tiao.
Performance monitoring
Monitor nodeJS V8 heap memory, degrade services when memory exceeds 80%, and deploy unhealthy containers to other instances within a time frame (maybe half an hour, depending on the business). Process.memoryusage () returns an object describing the memoryUsage, in bytes, of the node.js process.
import { memoryUsage } from "process";
console.log(memoryUsage());
/ / print:
/ / {
// rss: 4935680,
// heapTotal: 1826816,
// heapUsed: 650472,
// external: 49879,
// arrayBuffers: 9386
// }
Copy the code
heapTotal
和heapUsed
Refers to the memory usage of V8.external
Refers to those that are bound to V8 managementJavaScript
The object’sC++
Object memory usage.rss
.Resident Set Size
Is the amount of space occupied by the process on the main memory device (that is, a subset of the total allocated memory), including allC++
和JavaScript
Object and code.arrayBuffers
Refers to asArrayBuffer
和SharedArrayBuffer
Allocated memory, including all Node.js buffers. This is also included inexternal
In the value. When Node.js is used as an embedded library, this value may be 0, as there may be no trace in this caseArrayBuffer
The distribution of.
Throw it all away and let’s use next-.js
Despite a bunch of principles mentioned above, the general-grade SSR solution is still not enough as an enterprise-level solution. There is a large amount of code in nex.js to deal with various compatibility problems. As a react project with a large volume, it is more recommended to choose a general-grade solution.
Hybrid rendering
In our actual business, we often need SSR for some pages and CSR for the rest. For our own simple SSR, we can configure the whitelist, do the matching request, in the whitelist of the empty HTML string (only CSS, JS resources); Or do interception in nGINx layer, whitelist forward to the CSR address. Next. Js provides a much simpler way for this hybrid rendering by providing a statically generated API with getStaticProps, where requests are requested at build time and written to the Window. GetServerSideProps is an API that can only be executed on the server, so getServerSideProps will not be exported during static generation. Here is the statically generated code.
export async function getStaticProps() {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch("https://... /posts");
const posts = await res.json();
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
};
}
Copy the code
Service degradation
innode
When the server is unhealthy, it reaches the millisecond levelCSR
That is, there is no need to rely on our own built framework, can takeserver
和 client
Pack them separately. Here you goclient
Package output plusHTML
File, can be hosted separately. Below isnginx
Configuration sample and elegant degradation schematic, explained below is the user requestnginx
If the server is normal, it will be forwarded tonode
Render server, if the exception returns the exception status code, intercept the exception status code and rewrite200
And forwarded to theHTML
Static file server.
Natural elegant service degradation
Since SSG comes with it, then our service degradation can take its static generation, the official provide next export command, can directly generate SSG output, each route out of an HTML file, which will introduce the required CSS and JS. Note that if you want a set of code, you need to plant the environment variables, because the SSG requirement is that you must not expose getServerSideProps. The compatible handling code is as follows
// .sh
export NEXT_SSG = SSG
// .tsx
let getServerSideProps =
process.env.NEXT_SSG === "SSG"
? undefined
: async() = > {const res = await fetch(`url`);
const post = await res.json();
return { props: { name: post? .data? .token } }; };export { getServerSideProps };
Copy the code
Throw the printed output to nginx as follows
server { root /www/data; location / { try_files $uri ; }}Copy the code
If you get the HTML from the return path, the client gets the HTML string and then hydrate, which is actually a CSR, achieving an elegant degradation without going to the Node server.
Built-in performance analysis
For web application performance analysis, it is always difficult to get around the metrics of Web Vitals. Next. Js Analytics provides us with a very convenient API to obtain these metrics data. For projects deployed on Vercel hosting, visual metrics data can be seen in their Analytics TAB. Web performance analysis is available and possible for self-managed projects. Simply create an _app.js that exposes a method called reportWebVitals.
Next. Js calls this function when any metric is evaluated.
//_app.js
export function reportWebVitals(metric) {
console.log(metric);
}
/ / print
/ / {
// id: "1628518848412-9295257969280",
// label: "web-vital",
// name: "TTFB",
// startTime: 0,
/ / value: 815.5,
// }
Copy the code
id
: Unique identifier for the indicator;label
: Indicates the indicator typeweb-vitals
andcustom
;name
: Index name;startTime
: Indicates the time stamp of the indicator in milliseconds.value
: Indicates the value or duration of an indicator in milliseconds.
web-Vitals
Google is a unified measure of the user experience and quality of web pages. Next. Js provides us with the following five metrics:
- First byte time
TTFB
- First content drawing
FCP
- Measuring loading performance
LCP
- Measure interactivity
FID
- Measuring visual stability
CLS
custom
This is a unique indicator provided by Nex.js to measure the hydrate and Render time
Next.js-hydration
: Page start and finishhydrate
Time required in millisecondsNext.js-route-change-to-render
: The time (in milliseconds) between the time the page started rendering after the routing changeNext.js-render
: The time (in milliseconds) before the page is rendered after the routing change
Using this function, you can create your own performance report.
other
Dynamic loading, such as dynamic routing matching next10 have support, need to document oh ~ www.nextjs.cn/docs/gettin…
In this case, select Serverless
Serverless is basically a simple sequence repeat (SSR) application in a function, serverless has triggers, you use HTTP triggers, A route can be added to the trigger, and the received route is passed to nex.js, which then returns HTML to the client.
Serverless
What problem does it solve?
Serverless Allows applications to be o&M free on the server. When there is no flow, the volume is reduced to 0 to save the flow. We can save a lot of money. It is a cost-effective solution. The use of Serverless+SSR is perfect for landing pages that may increase traffic in certain situations, as well as edge services. What is o&M free? If a service is deployed in the running environment provided by the service provider, we do not need to care about o&m related things, only need to care about business code, and we do not need to maintain Linux such as physical machines and virtual machines. Each major cloud service vendor has a packaged Next. Js service, which can be quickly deployed by simple operation.
Have need to be able to search on their own oh, do not post ~
conclusion
Introduces what SSR and SSG are and what problems they solve, how they work and how they monitor performance, how common level SSR framework Nextjs does elegant service degradation, and how the nextJS framework is still being updated and released a few days ago. Module federation is supported, and the micro front end can also use Nextjs (manual dog head).
One day
I am Xuan Jiang, I am lo niang FE (encourage teacher to cross off), a passing friend gave me three even ba ~ your support is the motivation of Xuan Jiang’s creation (I was touched by what you said), I will keep updating ~