在前端项目需要首屏渲染速度优化或SEO的场景下,大家或多或少都听过到过服务端渲染( SSR ),但大多数人对服务端渲染具体实现和底层原理还是比较陌生的。本文基于公司官网开发时做了服务端渲染改造基础上,系统理解和梳理这套体系的模式和逻辑,并写了一些笔记和Demo(文后链接)便于深入理解。这次我们来以React为例,把服务端渲染彻底讲弄明白。本文主要有以下内容:
服务端渲染, SSR (Server-side Rendering) ,顾名思义,就是在浏览器发起页面请求后由服务端完成页面的HTML结构拼接,返回给浏览器解析后能直接构建出有内容的页面。
我们使用Koa框架来创建node服务:
// demo1
var Koa = require("koa");
var app = new Koa();
// 对于任何请求,app将调用该函数处理请求:
app.use(async (ctx) => {
// 将HTML字符串直接返回
ctx.body = `
<html>
<head>
<title>ssr</title>
</head>
<body>
<div id="root">
<h1>hello server</h1>
<p>word</p>
</div>
</body>
</html>`;
});
//监听
app.listen(3001, () => {
console.log("listen on 3001 port!");
});
启动服务后访问页面,查看网页源代码是这样:
npx create-react-app my-app
上面的例子就是一个简单的服务端渲染,其服务侧直接输出了有内容的HTML,浏览器解析之后就能渲染出页面。与服务端渲染对应的是客户端渲染 ,CSR(Client Side Rendering),通俗的讲就是由客户端完成页面的渲染。其大致渲染流程是这样:在浏览器请求页面时,服务端先返回一个无具体内容的HTML,浏览器还需要再加载并执行JS,动态地将内容和数据渲染到页面中,才能完成页面具体内容的显示。目前主流的React ,Vue, Angular 等SPA页面未经特殊处理均采用客户端渲染。最常见脚手架create-react-app 生成的项目就是客户端渲染:
上面采用客户端渲染的HTML页面中
中无内容,需在浏览器端加载并执行bundle.js后才能构建出有内容页面。相比于客户端渲染,服务端渲染有什么优势?我们可以从下图对比一下这两种不同的渲染模式。
首屏时间更短
采用客户端渲染的页面,要进行JS文件拉取和JS代码执行,动态创建 DOM 结构,客户端逻辑越重,初始化需要执行的 JS 越多,首屏性能就越慢;客户端渲染前置的第三方类库/框架、polyfill 等都会在一定程度上拖慢首屏性能。Code splitting、lazy-load等优化措施能够缓解一部分,但优化空间相对有限。相比而言,服务端渲染的页面直接拉取HTMl就能显示内容,更短的首屏时间创造更多的可能性。
利于 SEO
在别人使用搜索引擎搜索相关的内容时,你的网页排行能靠得更前,这样你的流量就有越高,这就是SEO的意义所在。那为什么服务端渲染更利于爬虫爬你的页面呢?因为对于很多搜索引擎爬虫(非google)HTML返回是什么内容就爬什么内容,而不会动态执行JS代码内容。对客户端渲染的页面来说,简直无能为力,因为返回的HTML是一个空壳。而服务端渲染返回的HTML是有内容的。
SSR的出现,就是为了解决这些CSR的弊端。
并不是所有的WEB应用都必须使用SSR,这需要开发者来权衡,因为服务端渲染会带来以下问题:
代码复杂度增加。为了实现服务端渲染,应用代码中需要兼容服务端和客户端两种运行情况,部分代码只能在客户端运行,需要对其进行特殊处理,才能在服务器渲染应用程序中运行。
需要更多的服务器资源。由于服务器增加了渲染HTML的需求,使得原本只需要输出静态资源文件的nodejs服务,新增了数据获取的IO和渲染HTML的CPU占用,如果流量突然暴增,有可能导致服务器宕机,因此需要使用响应的缓存策略和准备相应的服务器负载。
涉及构建设置和部署的更多要求。与可以部署在任何静态文件服务器上的完全静态单页面应用程序 (SPA) 不同,服务器渲染应用程序,需要处于 Node.js server 运行环境。
因此,在使用服务端渲染SSR之前,需要考虑投入产出比:是否真的需要SEO,是否需要将首屏时间提升到极致。如果都没有,使用SSR反而小题大做了。
其实服务端渲染并不是什么新奇的概念,前后端分层之前很长的一段时间里都是以服务端渲染为主(JSP、PHP),那时后端一把梭哈,在服务端生成完整的 HTML 页面。但那时的服务端渲染和现在还是有本质的区别,存在比较多的弊端,每一个请求都要动态生成HTML,存在大量的重复,服务器机器成本也相对比较高,前后端代码完全掺杂在一起,开发维护难。
随着业务不断发展变化,后端要写的JS逻辑也越发复杂,而且JS有很多潜在的坑使后端越发觉得这是块烫手山芋,于是逐渐出现了前后端分层。伴随AJAX的兴起,浏览器可以做到了不再重现请求页面就可更新局部视图。还可以利用客户端免费的计算资源,后端侧逐渐演变成了提供数据支持。jquery的兴起,良好的客户端兼容性使JS不再受困于各种版本浏览器兼容问题,一统了前端天下。
此后伴随node的兴起,前后端分离越演越烈。前端能摆脱后端的依赖单独起服务,三大框架vue,react,angular也迅势崛起,以操作数据就能更新视图,前端开发人员逐渐摆脱了与烦人的Dom操作打交道,能够专心的关注业务和数据逻辑。前端同时探索出了功能插件,UI库,组件等多种代码复用方案,形成了繁荣的前端生态。
但是三大框架采用客户端渲染模式,随着代码逻辑的加重,首屏时间成了一个很大的问题,同时开发人员也发现SEO也出了问题,大多搜索引擎根本不会去执行JS代码。但是也不可能再回头走老路,于是前端又探索出了一套服务端渲染的框架来解决掉这些问题。此时的服务端渲染是建立在成熟的组组件,模块生态之上,基于Node.js的同构方案成为最佳实践。
React服务端渲染流程
React服务端渲染的基本思路,简单理解就是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。因为要考虑React在服务端的运行情况,故相比之前讲的多了在浏览器端绑定状态与事件的过程。
我们可以结合下面的流程图来一览完整的 React服务端渲染的全貌:当浏览器去请求一个页面,前端服务器端接收到请求并执行 React组件代码,此时React代码中可能包含向后端服务器发起请求,待请求完成返回的数据后,前端服务器组装好有内容的HTML里返给浏览器,浏览器解析HTML后已具备展示内容,但页面并不具备交互能力。
下一阶段,在返回的HTMl中还有script链接,浏览器再拉取JS并执行其包含的React 代码,其能在浏览器端执行完整的生命周期,并通过相关API实现复用此前返回 HTML节点并添加事件的绑定,此时页面才就具备完全交互能力。总的来说,react服务端渲染包含有两个过程:服务端渲染 + 客户端 hydrate 渲染。服务端渲染在服务端渲染出了首屏内容;客户端 hydrate 渲染复用服务端返回的节点,进行一次类似于 render 的 hydrate 渲染过程,把交互事件绑上去(此时页面可交互),并接管页面。
服务端处理后返回的
客户端“浸泡”还原后的
从上面的流程中可以看到,客户端和服务端都要执行React代码完成渲染,那是不是就要写两份代码,供双端使用? 当然不需要,也完全不合理。所谓同构,就是让一份React代码,既可以在服务端中执行,也可以在客户端中执行。
我们这里简单理了一下服务端渲染涉及到的技术栈:
知道了服务端渲染、同构的大概思路之后,下面从头开始,一步一步完成具体实践,深入理解其原理。
按照之前流程的大概思路,我们首先需要将React组件在服务端转换成HTML字符串,那怎么做呢?React 提供的面向服务端的API(react-dom/server),提供了相关方法能够将 React 组件渲染成静态的(HTML)标签。下面我们简单了解下react-dom/server。
react-dom/server有renderToString、renderToStaticMarkup,renderToNodeStream、renderToStaticNodeStream四个方法能够将 React 组件渲染成静态的(HTML)标签,前两者能在客户端和服务端运行,后两者只能在服务端运行。
renderToStaticMarkup VS renderToString:renderToString 方法会在 React 内部创建的额外 DOM 属性,例如 data-reactroot, 在相邻文本节点之间生成\,这些属性是客户端执行hydrate复用节点的关键所在,data-reactroot属性是服务端渲染的标志之一。如果你希望把 React 当作静态页面生成器来使用,renderToStaticMarkup方法会非常有用,因为去除额外的属性可以节省一些字节。
// Home.jsx
import React from "react";
const Home = () => {
return (
<div>
<h2 onClick={() => console.log("hello")}>This is Home Page</h2>
<p>Home is the page ..... more discribe</p>
</div>
);
};
export default Home;
我们使用React-dom/server下提供的renderToString方法,在服务端将其转换为html字符串:
// server.js
import Koa from "koa";
import React from "react";
import { renderToString } from "react-dom/server";
import Home from "./containers/Home";
const app = new Koa();
app.use(async (ctx) => {
// 核心api renderToString 将react组件转化成html字符串
const content = renderToString(<Home />);
ctx.body = `
<html>
<head>
<title>ssr</title>
</head>
<body>
<div id="root">${content}</div>
</body>
</html>
`;
});
app.listen(3002, () => {
console.log("listen:3002");
});
可以看到上面代码里有ES6的import 和jsx语法,不能直接运行在node环境,需要借助webpack打包, 构建目标是commonjs。新建webpack.server.js具体配置如下:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// webpack.server.js<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const path = require(<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"path"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">);<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const nodeExternals = require(<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"webpack-node-externals"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">);<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">module.exports<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> = {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> mode: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"development"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> target: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"node"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> entry: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"./server.js"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> resolve: {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> extensions: [<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">".jsx"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">".js"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">".tsx"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">".ts"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> module: {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> rules: [<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">test<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">: /\.jsx?$/,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> loader: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"babel-loader"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> exclude: /node_modules/,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> options: {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> presets: [<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"@babel/preset-react"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"@babel/preset-env"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> plugins: [<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> [<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"@babel/plugin-transform-runtime"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> absoluteRuntime: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(86, 182, 194);line-height: 26px;">false<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> corejs: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(86, 182, 194);line-height: 26px;">false<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> helpers: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(86, 182, 194);line-height: 26px;">true<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> regenerator: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(86, 182, 194);line-height: 26px;">true<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> version: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"7.0.0-beta.0"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> ],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> ],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> ],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> output: {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> filename: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"bundle.js"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> path: path.resolve(__dirname, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"build"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">),<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> externals: [nodeExternals()],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">};
在webpack构建完成后,可在Node环境运行build/bundle.js,访问页面后查看网页源代码,可以看到,React组件中的内容已经完整地包含在服务端返回到html里面。我们成功迈出了服务端渲染第一步。此时,我们也有必要再深入了解renderToString 到底做了什么,提前踩坑!
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/3c1e339f9929a4a3a46b4c12c79b74e7)
#### **renderToString**
除了将React组件转换成html字符串外,renderToString还有做了下面这些:
1\. 会执行传入的React组件的代码,但是其只执行到React生命周期初始化过程的render及之前,即下面红框的部分,其余大部分生命周期函数在服务端都不执行;这也是服务端渲染的坑点之一。
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/c1e1a6143bee024e45c3ee6d1d5404d3)
2\. **renderToString** 生成的产物中会包含一些额外生成特殊标记,代码体积会有所增大,其中属性data-reactroot是服务端渲染的标志,便于后续客户端通过hydrate复用HTML节点。在React16前后其产物也有差距:在React 16 之前,服务端渲染采用的是基于字符串校验和(string checksum)的 HTML 节点复用方式, 会额外生成生成data-reactid、data-react-checksum等属性;React 16 改用单节点校验来复用(服务端返回的)HTML 节点,不再生成data-reactid、data-react-checksum等体积占用大户,只在空白节点间多了\<!-- --> 这样的标记。
```
renderToString react16前
"" data-reactid="1" data-react-checksum="122239856">
"2">Welcome to React SSR!
Hello There!
// renderToString react16
"">"here">Welcome to React SSR! Hello There!
```
```
3.会被故意忽略掉的on开头的的属性,也就忽略掉了react代码中事件处理,这是也是坑点之一。服务端返回的html里没有处理事件点击,需要靠后续客户端js执行绑定事件。
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="color: rgb(198, 120, 221);line-height: 26px;">function shouldIgnoreAttribute(<br></br> name: string,<br></br> propertyInfo: PropertyInfo | null,<br></br> isCustomComponentTag: boolean,<br></br>): boolean {<br></br> <span style="color: rgb(198, 120, 221);line-height: 26px;">if (propertyInfo !== null) {<br></br> <span style="color: rgb(230, 192, 123);line-height: 26px;">return propertyInfo.type === RESERVED;<br></br> }<br></br> <span style="color: rgb(198, 120, 221);line-height: 26px;">if (isCustomComponentTag) {<br></br> <span style="color: rgb(230, 192, 123);line-height: 26px;">return <span style="color: rgb(86, 182, 194);line-height: 26px;">false;<br></br> }<br></br> <span style="color: rgb(198, 120, 221);line-height: 26px;">if (<br></br> name.length > 2 &&<br></br> (name[0] === <span style="color: rgb(152, 195, 121);line-height: 26px;">'o' || name[0] === <span style="color: rgb(152, 195, 121);line-height: 26px;">'O') &&<br></br> (name[1] === <span style="color: rgb(152, 195, 121);line-height: 26px;">'n' || name[1] === <span style="color: rgb(152, 195, 121);line-height: 26px;">'N')<br></br> ) {<br></br> <span style="color: rgb(230, 192, 123);line-height: 26px;">return <span style="color: rgb(86, 182, 194);line-height: 26px;">true;<br></br> }<br></br> <span style="color: rgb(230, 192, 123);line-height: 26px;">return <span style="color: rgb(86, 182, 194);line-height: 26px;">false;<br></br>}<br></br>
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/0fd84e3f8b1405ddf51f2cabc99ea80b)
上面的例子我们可以看到React的代码里有点击事件,但点击后没有反应。需要靠后续客户端js执行绑定事件。如何实现?这就需要同构了。
### 2.3 实现基础的同构
前文已经大概讲了同构的概念,那为什么需要同构?之前的服务端代码在处理点击事件时故意忽略掉了这类属性,在服务端执行的生命周期也是不完整的,此时的页面是不具备交互能力的。同构,正是解决这些问题的关键,React代码在服务器上执行一遍之后,浏览器再去加载JS后又运行了一遍React代码,完成事件绑定和完整生命周期的执行,从而才能成为完全可交互页面。
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/cb22e7ab5ae29ad66694658e81ed7ed8)
**react-dom:hydrate**
实现同构的另一个核心API是React-dom下的**hydrate,**该方法能在客户端初次渲染的时候去复用服务端返回的原本已经存在的 DOM 节点,于渲染过程中为其附加交互行为(事件监听等),而不是重新创建 DOM 节点。需要注意是,服务端返回的 HTML 与客户端渲染结果不一致时,出于性能考虑,hydrate可以弥补文本内容的差异,但并不能保证修补属性的差异,而是将错就错;只在development模式下对这些不一致的问题报 Warning,因此必须重视 SSR HydrationWarning,要当 Error 逐个解决。
那具体实现同构?
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/3e76085d0f4a305fa310db18d5e4b8ab)
上面这里我们提供了一个基本的架构图,可以看到,服务端运行React生成html代码我们已经基本实现,目前需要做的就是生产出客户端执行的index.js,那么这个index.js我们如何生产出来呢?
**具体实践**
首先新建客户端代码client.js,引入React组件,通过ReactDom.hydrate处理挂载到Dom节点, hydrate是实现复用的关键。
```
// client.js
import React from "react";
import ReactDom from "react-dom";
import Home from "./containers/Home";
const App = () => {
return ;
};
ReactDom.hydrate( , document.getElementById("root"));
```
```
客户端代码也需要webpack打包处理,新建webpack.client.js具体配置如下,需要注意打包输出在public目录下,后续的静态资源服务也起在了这个目录下。
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// webpack.client.js<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const path = require(<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"path"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">);<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const resolve = (dir) => path.resolve(__dirname, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"./src"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">, dir);<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">module.exports = {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> mode: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"development"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> entry: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"./client.js"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> output: {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> filename: <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"index.js"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> path: path.resolve(__dirname, <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"public"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">),<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> module: {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> rules: [<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // babel-loader处理js的一些配置<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> ],<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> },<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">};
服务端的静态资源服务使用koaStatic起在public目录,这样就能通过外链访问到打包出来的客户端js,同时我们在html中嵌入这个链接。
```
// server.js
import koaStatic from "koa-static";
const app = new Koa();
app.use(koaStatic("public"));
app.use(async (ctx) => {
const content = renderToString( );
console.log(content);
ctx.body = `
"root">${content}
`;
});
app.listen(3003, () => {
console.log("listen:3003");
});
```
```
简单看下此时的代码结构是这样:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
├── package.json<br></br>├── webpack.client.js<br></br>├── webpack.server.js<br></br>├── server.js<br></br>├── client.js<br></br>└── containers<br></br> └── Home.jsx<br></br>
通过上面一番操作,简单的同构基本可以跑起来了,点击对应位置后看到有了反应,查看网页源代码如下。可以看到多了script标签的index.js 这段,这是在客户端执行的js代码。
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/a3d9c28228173f15437686944d1e57d6)
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/fb8af2091be11a6b88a87a7246d51744)
以上我们仅仅是就完成了一个React基础的同构,但这还远不够,一个完整的前端页面还包含路由,状态管理,请求服务端数据等,这些也需要进行同构,且看下面为你一一道来。
### 2.4 路由的同构
我们之前页面只是一个页面, 但实际开发的应用用一般都是多个页面的,这就需要加入路由了。服务端渲染加入路由就涉及到同一份路由在不同端的执行,这就是路由的同构。
下面一步步来:首先加入About页面,并书写路由配置routes.js
```
// routes.js
import Home from "./containers/home";
import About from "./containers/about";
export default [
{ path: "/", component: Home, exact: true },
{
path: "/about",
component: About,
exact: true,
},
];
```
```
在客户端侧加入路由的写法还是熟悉的写法,考虑到页面中可能涉及多级路由的渲染,这里直接引入react-router-config中来处理:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
// client.js<br></br>import { BrowserRouter } from <span style="color: rgb(152, 195, 121);line-height: 26px;">"react-router-dom";<br></br>import { renderRoutes } from <span style="color: rgb(152, 195, 121);line-height: 26px;">"react-router-config";<br></br>import Routes from <span style="color: rgb(152, 195, 121);line-height: 26px;">"./routes";<br></br><br></br>const App = () => {<br></br> <span style="color: rgb(230, 192, 123);line-height: 26px;">return (<br></br> <BrowserRouter><br></br> <div>{renderRoutes(Routes)}</div><br></br> </BrowserRouter><br></br> );<br></br>};<br></br>
react-router 为服务端提供了StaticRouter,需显式地向location传path。
```
// server.js
import { StaticRouter } from "react-router-dom";
import { renderToString } from "react-dom/server";
import Routes from "./routes";
import { renderRoutes } from "react-router-config";
const app = new Koa();
app.use(koaStatic("public"));
app.use(async (ctx) => {
const content = renderToString(
{renderRoutes(Routes)}
);
}
```
```
以上就完成了路由的配置,还比较简单吧,此时页面的路由跳转基本没问题了。
2.5 Redux的同构
如何让前端页面的应用状态可控、让协作开发高效也是我们必须考虑的问题。Redux作为React最常见的状态管理方案被很多项目引入来解决这一问题。那引入Redux如何被到同构项目中?这里,我们还是简单回顾一下redux运作流程,不熟悉的可以移步redux熟悉下。接下来开启Redux的同构之旅。
第一步:创建全局STORE
首先我们创建了一个store.js,初始化配置并导出一个函数用来实例化store,以提供给客户端和服务端同时使用。为什么store要导出一个函数?因为这段代码后面服务端使用时,如果下面的store导出的是一个单例,所有的用户用的是同一份store,那将是灾难性的结果。
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">/<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">/ store.js<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">im<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">port { createStore, applyMiddleware, combineReducers } from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"redux"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">i<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">m<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">port<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> thunk from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"redux-thunk"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// 这里提<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">前引入了About组件下的store<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import { r<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">educer as AboutReducer } from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"../containers/store"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">c<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">onst reducer <span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">= combineReducers({<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> a<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">bout: AboutR<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">educer,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">});<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// 导出成<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">函数的原因<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">export<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> def<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">ault (<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">)<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">return<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> crea<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">te<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">St<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">ore(reducer, applyMiddleware(thunk));<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">};
##### 第二步:连接全局STORE
客户端的写法还是熟悉的样子:
```
//client.js
import { Provider } from "react-redux";
import getStore from "./store";
const App = () => {
return (
{renderRoutes(Routes)}
);
};
```
```
服务端server.js的写法也是类似:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
// server.js<br></br>import { Provider } from <span style="color: rgb(152, 195, 121);line-height: 26px;">"react-redux";<br></br>import getStore from <span style="color: rgb(152, 195, 121);line-height: 26px;">"./store";<br></br><br></br>const app = new Koa();<br></br>app.use(koaStatic(<span style="color: rgb(152, 195, 121);line-height: 26px;">"public"));<br></br><br></br>app.use(async (ctx) => {<br></br> const content = renderToString(<br></br> <Provider store={getStore()}><br></br> <StaticRouter location={ctx.request.path}><br></br> <div>{renderRoutes(Routes)}</div><br></br> </StaticRouter><br></br> </Provider><br></br> );<br></br>}<br></br>
##### 第三步:组件的store
新建About 组件使用的store,其action和reducer的写法如下,注意此时我们在action里发起了一个异步请求。
```
// containers/store/reduccer.js
import { CHANGE_LIST } from "./constants";
const defaultState = { name: "panpan", age: 18, list: [] };
export default (state = defaultState, action) => {
switch (action.type) {
case CHANGE_LIST:
return { ...state, list: action.payload };
default:
return state;
}
};
```
```
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// containers/store/action.js<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import axios from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"axios"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import { CHANGE_LIST } from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"./constants"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const changeAction = (payload) => ({<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">type<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">: CHANGE_LIST,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> payload,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">});<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const getHomeList = () => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">return<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> (dispatch) => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">return<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> axios.get(<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"http://localhost:3008/mock/1"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">).<span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(198, 120, 221);line-height: 26px;">then<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">((res) => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> dispatch(changeAction(res.data.data || []));<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> });<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> };<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">};<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">export<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> default {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> getHomeList,<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">};
About组件连接Redux:
```
// containers/About.js
import { connect } from "react-redux";
import { action } from "./store";
const About = () => {
useEffect(() => {
props.getList();
}, []);
// ...
}
const mapStateToProps = (state) => ({
name: state.about.name,
age: state.about.age,
list: state.about.list,
});
const mapDispatchToProps = (dispatch) => ({
getList() {
dispatch(action.getHomeList());
},
});
export default connect(mapStateToProps, mapDispatchToProps)(About);
```
```
经过一番改造后,项目变成了这样:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
├── package.json<br></br>├── mock.server.js<br></br>├── webpack.client.js<br></br>├── webpack.server.js<br></br>├── routes.js<br></br>├── server.js<br></br>├── client.js<br></br>└── store<br></br> └── index.js<br></br>└── containers<br></br> ├── Home.js<br></br> ├── About.js <br></br> └── store<br></br> ├── index.js<br></br> ├── action.js<br></br> ├── reducer.js<br></br> └── constants.js <br></br>
通过上述操作Redux 基本可以跑起来了,可以发现写法跟熟悉的客户端渲染大体差不多,只多了引入server端的步骤。但是目前的redux还存在一定的问题,我们一起再来看。
##### 服务端没数据问题
上面的redux在同构项目中跑起来咋一看是没什么问题,但当我们把js禁用或直接查看源代码时,就会发现About组件内并不存在异步请求的数据列表,换句话说服务器端的store的list始终是空的,服务端并没有发起相应的数据请求。为什么会这样呢?
分析一下:当浏览器发起页面请求后,服务器接收到请求,此时服务器和客户端的store的list都为空, 接着服务端开始渲染执行React代码,根据此前讲rendertostring坑之一,服务端调用React代码时里面的生命周期的只到初始化时的render及之前,而About组件内发起的异步请求是在useEffect内,相当于是在*ComponentDidMount*阶段发起请求,所以服务器端渲染时根本不会执行里面的异步请求,因此服务器端的store的list始终是空的,所以我们看不到列表数据。之后客户端拉取了JS并执行React代码,React在客户端能够执行完整的生命周期,故可以执行useEffect里的函数获取到数据并渲染到页面。换而言之,目前获取异步数据只是进行了后期的客户端渲染阶段。
如何让服务端将获得数据的操作执行一遍,以达到真正的服务端渲染的效果?这就是接下来要讲的服务端渲染异步数据。
### 2.6 服务端渲染异步数据
上文的同构项目中跑起来后,我们是在组件的useEffect中发起的异步请求,服务端并不能执行到这一块。那能不能在其他生命周期获取异步请求数据?答案是不推荐,因为React16采用了Fiber架构后,render之前的生命周期都可能被中断而执行多次,类似getDerivedStateFromProps(静态方法), ComponentWillMount(废弃), UNSAFE\_componentWillMount的生命周期钩子都有可能执行多次,所以不建议在这些生命周期中做有请求数据之类副作用的操作。而componentDidMount在render之后是确定被执行一次的,所以React开发中建议在componentDidMount生命周期函数进行异步数据的获取。那有没有其他的解决方案呢? React Router 恰好也考虑到了这点,提供了这样一种解决方案,需要我们对路由进行一些改造。
**React Router 解决方案**
React Router 解决方案的基本思路:
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/204a0546b3755c6ab6ae721db9b67ed0)
首先,改造原有的路由,配置了一个loadData参数,这个参数代表要在服务端获取数据的函数:
```
// router.js
import Home from "./containers/home";
import About from "./containers/about";
export default [
{ path: "/", component: Home, exact: true },
{
path: "/about",
component: About,
exact: true,
loadData: About.loadData,
},
];
```
```
在服务端匹配路径对应的路由,如果这个路由对应的组件有loadData方法,那么就执行一次,并将store传进loadData里面去,注意loadData函数调用后需要返回Promise对象,等待Promise.all都resolve后,此时传过去的store已经完成了更新,便可以在renderToString时放心使用:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// server.js<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import { renderRoutes, matchRoutes } from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"react-router-config"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import { Provider } from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"react-redux"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import getStore from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"./store"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">app.use(async (ctx) => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> const store = getStore();<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // 匹配到路径对应的路由<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> const matchArr = matchRoutes(Routes, ctx.request.path);<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(230, 192, 123);line-height: 26px;">let<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> promiseArr = [];<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> matchArr.forEach((item) => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // 判断有没有 loadData<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(198, 120, 221);line-height: 26px;">if<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> (item.route.loadData) {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // 要将store传递过去 <br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // item.route.loadData() 返回的是一个promise<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> promiseArr.push(item.route.loadData(store));<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> }<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> });<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // 等待异步完成,store已完成更新<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> await Promise.all(promiseArr);<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> const content = renderToString(<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <Provider store={store}><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <StaticRouter location={ctx.request.path}><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <div>{renderRoutes(Routes)}</div><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> </StaticRouter><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> </Provider><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> );<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">}
接下来是组件内loadData函数,发起异步请求,并返回一个Promise
```
// containers/About.js
import { connect } from "react-redux";
import { action } from "./store";
const About = (props) => {
useEffect(() => {
props.getList();
}, []);
// ...
};
About.loadData = (store) => {
//可能存在多个数据请求,所以用promise.all包一层
return Promise.all([store.dispatch(action.getHomeList())]);
};
const mapStateToProps = (state) => ({
name: state.about.name,
age: state.about.age,
list: state.about.list,
});
const mapDispatchToProps = (dispatch) => ({
getList() {
dispatch(action.getHomeList());
},
});
export default connect(mapStateToProps, mapDispatchToProps)(About);
```
```
通过以上改造,服务端可以获取到异步数据了。但是眼尖的朋友可能注意到,页面此时还存在问题,页面中还不时存在list闪烁问题,这是什么原因导致的呢?这就涉及到数据的同步问题。
数据的注水和脱水
让我们来分析一下客户端和服务端的运行流程:
可以看到客户端和服务端的store 都经历了初始化置空的问题,导致store不同步, 那如何才能让这两个store的数据同步变化呢? 这就涉及到数据的注水和脱水。“注水”:在服务端获取获取之后,在返回的html代码中加入这样一个script标签,这样就将服务端store数据注入到了客户端全局的window.context对象中。
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
// server.js<br></br>app.use(async (ctx) => {<br></br> // ...<br></br> ctx.body = `<br></br> <html><br></br> <head><br></br> <title>ssr</title><br></br> <br></br> </head><br></br> <body><br></br> <div id=<span style="color: rgb(152, 195, 121);line-height: 26px;">"root"><span style="color: rgb(209, 154, 102);line-height: 26px;">${content}</div><br></br> <script><br></br> window.context = {<br></br> state: <span style="color: rgb(209, 154, 102);line-height: 26px;">${JSON.stringify(store.getState())}<br></br> }<br></br> </script><br></br> <script src=<span style="color: rgb(152, 195, 121);line-height: 26px;">"./index.js"></script><br></br> </body><br></br> </html><br></br> `;<br></br>});<br></br>
“脱水”处理:把window上绑定的数据给到客户端的store,因此在store.js区分了客户端和服务端不同的导出函数。
```
// store.js
// 客户端使用
export const getClientStore = () => {
const defaultState = window.context ? window.context.state : {};
return createStore(reducer, defaultState, applyMiddleware(thunk));
};
// 服务端使用
export const getServerSore = () => {
return createStore(reducer, applyMiddleware(thunk));
};
```
```
至此redux 包含异步数据的获取的同构就完成了。
2.7 css 的服务端渲染
为什么需要做css要服务端渲染?主要是解决页面的FOUC 闪屏问题。页面如果没做css的服务服务端渲染,我们一开始拉取到的HTML页面是没有样式的,页面的样式正常显示主要依赖于后面的客户端渲染,我们知道客户端渲染的时间相对要长很多,如果渲染前后存在较大的样式差距,就会引起闪屏。
还是以About组件为例,页面中加入样式:
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
.title {<br></br> color: aqua;<br></br> background: <span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">#999;<br></br> height: 100px;<br></br> line-height: 100px;<br></br> font-size: 40px;<br></br>}<br></br>
```
// containers/About.js
import styles from "./about.css";
const About = (props) => {
// ...
return (
List Content
);
};
```
```
需要webpack中相应的配置处理css,我们先处理客户端打包
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
{<br></br> <span style="color: rgb(230, 192, 123);line-height: 26px;">test: /\.css?$/,<br></br> use: [<br></br> <span style="color: rgb(152, 195, 121);line-height: 26px;">"style-loader",<br></br> {<br></br> loader: <span style="color: rgb(152, 195, 121);line-height: 26px;">"css-loader",<br></br> options: {<br></br> modules: <span style="color: rgb(86, 182, 194);line-height: 26px;">true,<br></br> },<br></br> },<br></br> ],<br></br> }<br></br>
上面的代码跑起来,就会发现有明显的闪烁,复盘一下:页面一开始html是没样式的,待到客户端js执行完成后,页面才突然有了样式显示正常。为了避免这种闪烁带来的不愉快体验,服务端也需要进行css的渲染。
##### 在服务端如何处理css?
客户端webpack采用css-loader处理后,style-loader直接将样式通过DOM操作进行插入,这对于浏览器环境很好很方便,但是对于服务端的Node环境,这就没法愉快的玩耍了。Node环境下可将样式插入到生成的html字符串中,而不是进行DOM操作。这时就需要用到另外一个跨平台的loader:isomorphic-style-loader,在服务端的webpack配置是这样:
```
// webpack.server.js
{
test: /\.css?$/,
use: [
"isomorphic-style-loader",
{
loader: "css-loader",
options: {
modules: true,
},
},
],
},
```
```
通过isomorphic-style-loader处理,我们可以在组件内直接通过styles._getCss即可拿到CSS代码,但这还不够,如何将拿到的css传回到服务端sever.js里从而塞入返回体呢?
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
// containers/About.js<br></br>import styles from <span style="color: rgb(152, 195, 121);line-height: 26px;">"./about.css";<br></br><br></br>const About = (props) => {<br></br> console.log(styles._getCss && styles._getCss());<br></br> // ...<br></br>}<br></br>
##### **CSS的服务端渲染**
CSS服务端渲染还需要借助StaticRouter中已经帮我们准备的一个钩子变量context,传入外部对象变量到StaticRouter到context里。路由配置对象routes中的组件都能在服务端渲染的过程中拿到这个context,这个context对于组件来说相当于props.staticContext。将获取到的css推入到staticContext.css里,这样服务端的context对象就完成了改变,我们便可以拼接css到head中。
![](https://oss-cn-hangzhou.aliyuncs.com/codingsky/cdn/img/2022-09-11/977ff03f1b172a802f5203db45effdde)
```
// server.js
app.use(async (ctx) => {
// 初始化 context
let context = { css: [] };
const content = renderToString(
// StaticRouter 传入context,组件接收到的props为staticContext
{renderRoutes(Routes)}
);
// 将css插入到head里面
ctx.body = `
ssr
...
`;
});
```
```
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">// containers/About.js<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">import styles from <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(152, 195, 121);line-height: 26px;">"./about.css"<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">;<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">const About = (props) => {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // 只有服务端才传过来了context,组件中props为staticContext<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> <span style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(198, 120, 221);line-height: 26px;">if<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> (props.staticContext) {<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // 将css推入数组,改变了传入的context<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> props.staticContext.css.push(styles._getCss());<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> }<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;"> // ...<br style="white-space:pre-wrap;margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"></br><span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">}
通过上面的操作,css的服务端渲染基本能正常工作。需要注意的是React-router传过来的context只有配置对象routes中的组件才能拿到,如果组件里面再嵌入子组件,需要把staticContext透传过去,才能对子组件props.staticContext进行相应操作。当然这里更推荐官方demo里的另一种写法,且看下面。
##### **更推荐写法**
我们可以查看isomorphic-style-loader的demo,更推荐写法是:客户端、服务端都用isomorphic-style-loader,webpack处理客户端css是这样配置的:
```
// webpack.client.js
{
test: /\.css?$/,
use: [
"isomorphic-style-loader",
{
loader: "css-loader",
options: {
modules: true,
},
},
],
},
```
```
组件内的写法也有相应改变,isomorphic-style-loader 提供了hooks:useStyles
<pre style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background-image: url("https://mmbiz.qpic.cn/mmbiz_svg/PFPUMLY8F77hIdjvPZicZQzb8TNT8jd4PrlicHRKxa0R7F7wzABRVXaVdhOdHB5gOaA6Pquh7NMg3H1yacxUX1uiaibCyo76cJjF/640?wx_fmt=svg");height: 30px;width: 764px;background-size: 40px;background-color: rgb(40, 44, 52);margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-repeat: no-repeat;">```
<span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">// containers/About.js<br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">import useStyles from <span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;color: rgb(152, 195, 121);line-height: 26px;">"isomorphic-style-loader/useStyles"<span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">;<br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">import styles from <span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;color: rgb(152, 195, 121);line-height: 26px;">"./about.css"<span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">;<br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">const About = (props) => {<br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;"> useStyles(styles);<br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;"> // ...<br style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;"></br><span style="margin: 0px;padding: 0px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;white-space: pre-wrap;float: none;display: inline !important;">}<span style="white-space:pre-wrap;color: rgb(171, 178, 191);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: left;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(40, 44, 52);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;display: inline !important;float: none;">
在服务端的代码里是这样的:
```
// server.js
import StyleContext from "isomorphic-style-loader/StyleContext";
// ...
app.use(async (ctx) => {
const css = new Set();
const insertCss = (...styles) =>
styles.forEach((style) => css.add(style._getCss()));
const content = renderToString(