Egg React SSR 服务端渲染 构建流程

1. 本地Egg项目启动

  • 首先执行node index.js或者 npm run dev启动 Egg应用
  • 在 Egg Agent 里面启动koa服务, 同时在koa服务里面启动Webpack编译服务
  • 挂载Webpack内存文件读取方法覆盖本地文件读取的逻辑
app.react.render = (name, locals, options) => {
   const filePath = path.isAbsolute(name) ? name : path.join(app.config.view.root[0], name);
   const promise = app.webpack.fileSystem.readWebpackMemoryFile(filePath, name);
   return co(function* () {
     const code = yield promise;
     if (!code) {
       throw new Error(`read webpack memory file[${filePath}] content is empty, please check if the file exists`);
     }
     // dynamic execute javascript
     const wrapper = NativeModule.wrap(code);
     vm.runInThisContext(wrapper)(exports, require, module, __filename, __dirname);
     const reactClass = module.exports;
     if (options && options.markup) {
       return Promise.resolve(app.react.renderToStaticMarkup(reactClass, locals));
     }
     return Promise.resolve(app.react.renderToString(reactClass, locals));
   });
};
  • Worker 监听Webpack编译状态, 检测Webpack 编译是否完成, 如果未完成, 显示Webpack 编译Loading, 如果编译完成, 自动打开浏览器
  • Webpack编译完成, Agent 发送消息给Worker,  Worker检测到编译完成, 自动打开浏览器, Egg服务正式可用

2. 本地服务端渲染页面访问

  • 浏览器输入URL请求地址, 然后 Egg 接收到请求, 然后进入 Controller
  • Node层获取数据后(Node通过http/rpc方式调用Java后端API数据接口), 进入模板render流程
  • 进入render流程后, 通过worker进程通过调用 app.messenger.sendToAgent发送文件名给Agent进程, 同时通过 app.messenger.on启动监听监听agent发送过来的消
  • Agent进程获取到文件名后, 从Webpack编译内存里面获取文件内容, 然后Agent 通过 agent.messenger.sendToApp把文件内容发送给Worker进程
  • Worker进程获取到内容以后, 进行React编译HTML, 编译成HTML后, 进入jss/css资源依赖流程
  • 如果启动代理模式(见easywebpack的setProxy),  HTML直接注入相对路径的JS/CSS, 如下:

页面可以直接使用 /public/client/js/vendor.js相对路径,  /public/client/js/vendor.js由后端框架代理转发到webpack编译服务, 然后返回内容给后端框架, 这里涉及两个应用通信. 如下:

<link rel="stylesheet" href="/public/client/css/home/android/home.css">
<script type="text/javascript" src="/public/client/js/vendor.js"></script>
<script type="text/javascript" src="/public/client/js/home.js"></script>
  • 如果非代理模式(见easywebpack的setProxy),  HTML直接注入必须是绝对路径的JS/CSS, 如下:

页面必须使用 http://127.0.0.1:9000/public/client/js/vendor.js绝对路径

<link rel="stylesheet" href="http://127.0.0.1:9000/public/client/css/home/android/home.css">
<script type="text/javascript" src="http://127.0.0.1:9000/public/client/js/vendor.js"></script>
<script type="text/javascript" src="http://127.0.0.1:9000/public/client/js/home.js"></script>

其中 http://127.0.0.1:9000 是 Agent里面启动的Webpack编译服务地址, 与Egg应用地址是两回事

  • 最后, 模板渲染完成, 服务器输出HTML内容给浏览器.

3. 正式环境发布模式构建流程和运行模式

  • Webpack通过本地构建或者ci直接构建好服务端文件和客户端资源文件到磁盘
  • Egg render直接读取本地文件, 然后渲染成 HTML
  • 根据 manfifest.json文件注入 jss/css资源依赖注入
  • 模板渲染完成, 服务器输出HTML内容给浏览器.

4. 关于 Egg 框架中的 Agent 和 Worker

  • 我们利用本地开发修改Node层代码修复重启时, 只会重启Worker进程, 不会重启Agent进程, 我们可以在Agent里面启动Webpack编译服务解决Webpack compiler实例问题.
  • 因为Egg App进程 和 Agent进程是两个进程, 当url访问时, 我们通过worker发送消息给agent进程, 获取服务端渲染的文件内容, 然后Agent再发送消息给Worker解决文件读取问题.
  • 本地开发webpack热更新内存存储读取和线上应用本机文件读取逻辑分离功能, 我们通过本地开发模式时, 通过读取Webpack内存内容覆盖本地文件读取的逻辑, 这样在开发模式和发布模式可以无缝对接.
  • worker和agent通信机制: https://eggjs.org/zh-cn/core/cluster-and-ipc.html
  • 实现egg项目服务器代码修改项目自动重启的功能可以使用egg-development插件.
原文链接:segmentfault.com

上一篇:npm 发布 ReactNative 阿里 icon-font 插件
下一篇:计算某地点到当前定位的距离,并重新对数组进行排序

相关推荐

  • 高频数据交换下Flutter与ReactNative的对比

    (标题图片来自网络,侵删) 后端使用go写的socketio服务模拟期货行情数据,每10ms推送10条行情数据 ReactNative已经尽力优化了。 Flutter由于没fluttersock...

    2 年前
  • 高性能迷你React框架 anu1.3.0 发布

    anujs1.3.0是一款高性能Reactlike框架,是目前世界上对React16兼容最好的迷你库。 自React16起,相继推出createContext,createPortal, creat...

    2 年前
  • 高德地图 react-amap 实战

    clipboard.png(https://img.javascriptcn.com/5a33946ad8c0ea8ee7870f74f331d0c0 "clipboard.png") reacta...

    9 个月前
  • 高品质 React UI 组件

    (https://img.javascriptcn.com/cca319311c2ea59a2b5cdaa63b997828)(https://link.funteas.com?target=http...

    2 年前
  • 骚操作!在react中使用vuex

    原文地址(https://github.com/zyl1314/blog/issues/12) 前言 笔者最近在学习使用,提到react就绕不过去。redux是一个状态管理架构,被广泛用于rea...

    2 年前
  • 项目文档说明:react + Ant Design 的 blog-react-admin

    效果图(https://img.javascriptcn.com/734ce56fe3a37ab11e9744473f56bae1 "效果图") 前言 此 blogreactadmin 项目是基...

    2 年前
  • 面试题:Hooks 与 React 生命周期的关系

    React 生命周期很多人都了解,但通常我们所了解的都是 单个组件 的生命周期,但针对 Hooks 组件、多个关联组件(父子组件和兄弟组件) 的生命周期又是怎么样的喃?你有思考和了解过吗,接下来我们将...

    10 个月前
  • 面试官:请你在React中引入Vue3的@vue/reactivity,实现响应式。

    前言 React的状态管理是一个缤纷繁杂的大世界,光我知道的就不下数十种,其中有最出名immutable阵营的redux,有mutable阵营的mobx,reacteasystate,在hooks诞生...

    4 个月前
  • 面试官我想做个Reacter(React路由)

    路由的基础用法回顾,源码study,文章首发于docs,求个star 依赖 路由依赖于 reactrouter ,但是一般 pc 路由使用 reactrouterdom ,它依赖于 reactrout...

    3 个月前
  • 面试中React与Vue的比对

    1.virtual dom 用JS模拟DOM结构,DOM变化的对比,放在JS层做,以提高重绘性能 DOM操作昂贵,JS运行效率高,要减少DOM操作 使用:snabbdom的使用 ...

    2 年前

官方社区

扫码加入 JavaScript 社区