ssr-plugin-react 6.2.13 → 6.2.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +305 -0
  3. package/cjs/config/base.d.ts +2 -1
  4. package/cjs/config/base.js +6 -5
  5. package/cjs/config/client.d.ts +1 -0
  6. package/cjs/config/client.js +11 -1
  7. package/cjs/config/index.d.ts +1 -0
  8. package/cjs/config/index.js +1 -0
  9. package/cjs/config/server.d.ts +1 -0
  10. package/cjs/config/server.js +1 -0
  11. package/cjs/entry/client-entry.d.ts +1 -0
  12. package/cjs/entry/client-entry.js +3 -6
  13. package/cjs/entry/context.d.ts +1 -0
  14. package/cjs/entry/context.js +1 -0
  15. package/cjs/entry/create-context.d.ts +1 -0
  16. package/cjs/entry/create-context.js +1 -0
  17. package/cjs/entry/create-router.d.ts +1 -0
  18. package/cjs/entry/create-router.js +1 -0
  19. package/cjs/entry/server-entry.d.ts +1 -0
  20. package/cjs/entry/server-entry.js +12 -23
  21. package/cjs/index.d.ts +1 -0
  22. package/cjs/index.js +1 -0
  23. package/cjs/tools/vite.d.ts +1 -0
  24. package/cjs/tools/vite.js +1 -0
  25. package/cjs/tools/webpack.d.ts +1 -0
  26. package/cjs/tools/webpack.js +1 -0
  27. package/esm/config/base.d.ts +2 -1
  28. package/esm/config/base.js +6 -5
  29. package/esm/config/client.d.ts +1 -0
  30. package/esm/config/client.js +11 -1
  31. package/esm/config/index.d.ts +1 -0
  32. package/esm/config/index.js +1 -0
  33. package/esm/config/server.d.ts +1 -0
  34. package/esm/config/server.js +1 -0
  35. package/esm/entry/client-entry.d.ts +1 -0
  36. package/esm/entry/client-entry.js +3 -6
  37. package/esm/entry/context.d.ts +1 -0
  38. package/esm/entry/context.js +1 -0
  39. package/esm/entry/create-context.d.ts +1 -0
  40. package/esm/entry/create-context.js +1 -0
  41. package/esm/entry/create-router.d.ts +1 -0
  42. package/esm/entry/create-router.js +1 -0
  43. package/esm/entry/server-entry.d.ts +1 -0
  44. package/esm/entry/server-entry.js +12 -23
  45. package/esm/index.d.ts +1 -0
  46. package/esm/index.js +1 -0
  47. package/esm/tools/vite.d.ts +1 -0
  48. package/esm/tools/vite.js +1 -0
  49. package/esm/tools/webpack.d.ts +1 -0
  50. package/esm/tools/webpack.js +1 -0
  51. package/package.json +7 -8
  52. package/src/config/base.ts +6 -6
  53. package/src/config/client.ts +11 -1
  54. package/src/entry/client-entry.tsx +2 -6
  55. package/src/entry/server-entry.tsx +10 -22
package/CHANGELOG.md CHANGED
@@ -1,3 +1,39 @@
1
+ ## [6.2.16](https://github.com/zhangyuang/ssr/compare/plugin-react@6.2.15...plugin-react@6.2.16) (2022-05-04)
2
+
3
+
4
+
5
+ ## [6.2.15](https://github.com/zhangyuang/ssr/compare/plugin-react@6.2.14...plugin-react@6.2.15) (2022-04-27)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * ci ([57e713f](https://github.com/zhangyuang/ssr/commit/57e713f1f96b4ceb893837c15c6032b23a0b1a4c))
11
+ * whitList concat userconfig ([fdd971a](https://github.com/zhangyuang/ssr/commit/fdd971ab11aebc0f348d789e758183b877e791af))
12
+ * whitList concat userconfig ([e2328f8](https://github.com/zhangyuang/ssr/commit/e2328f87f5cfc18c9a30867e4f6e18d0df5c1ba3))
13
+
14
+
15
+ ### Features
16
+
17
+ * add ssr-serialize-javascript code optimize ([41bb14d](https://github.com/zhangyuang/ssr/commit/41bb14d31efd89d4a85d5220544d2f7a3883e1a3))
18
+ * support props.ssrApp in vue3 ([8985037](https://github.com/zhangyuang/ssr/commit/898503753cbe69187d27f91c70dff3f4cd4a0b2a))
19
+
20
+
21
+
22
+ ## [6.2.14](https://github.com/zhangyuang/ssr/compare/plugin-react@6.2.13...plugin-react@6.2.14) (2022-04-20)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * update preinstall ([2b4b869](https://github.com/zhangyuang/ssr/commit/2b4b869c28b83b414bef10260e5561bc3773cea9))
28
+
29
+
30
+ ### Features
31
+
32
+ * optimize customescript ([f374760](https://github.com/zhangyuang/ssr/commit/f3747608d4684576875968394eca6315e2fa8dd1))
33
+ * plugin-react add react-refresh, remove module.hot ([7bee211](https://github.com/zhangyuang/ssr/commit/7bee211ddfefaef688713f505756e1155320b844))
34
+
35
+
36
+
1
37
  ## [6.2.13](https://github.com/zhangyuang/ssr/compare/plugin-react@6.2.12...plugin-react@6.2.13) (2022-04-18)
2
38
 
3
39
 
package/README.md ADDED
@@ -0,0 +1,305 @@
1
+ <div>
2
+ 简体中文 | <a href="./README_EN.md">English</a>
3
+ </div>
4
+
5
+ <h1 align="center"> SSR </h1>
6
+ <div align="center">
7
+ <img src="https://gw.alicdn.com/tfs/TB1ckATCGL7gK0jSZFBXXXZZpXa-540-540.jpg" width="300" />
8
+ </div>
9
+ <br />
10
+
11
+ <div align="center">
12
+ <strong>A most advanced ssr framework on Earth that implemented serverless-side render specification for faas and traditional web server.</strong>
13
+ </div>
14
+ <br />
15
+ <div align="center">
16
+ <a href="https://github.com/zhangyuang/ssr/actions" target="_blank"><img src="https://github.com/zhangyuang/ssr/workflows/CI/badge.svg" alt="githubActions" />
17
+ <a href="https://www.cypress.io/" target="_blank"><img src="https://img.shields.io/badge/cypress-dashboard-brightgreen.svg" alt="cypress" />
18
+ <a href="https://npmcharts.com/compare/ssr" target="_blank"><img src="https://img.shields.io/npm/dm/ssr" alt="download" />
19
+ <a href="https://github.com/zhangyuang/ssr" target="_blank"><img src="https://img.shields.io/badge/node-%3E=12-green.svg?color=4dc71f" alt="Node" ></a>
20
+ <a href="https://github.com/zhangyuang/ssr" target="_blank"><img src="https://img.shields.io/github/stars/zhangyuang/ssr.svg?color=4dc71f" alt="Node" ></a>
21
+ </div>
22
+ <br />
23
+
24
+ `ssr` 框架是为前端框架在服务端渲染的场景下所打造的开箱即用的服务端渲染框架。了解什么是服务端渲染请查看[文档](http://doc.ssr-fc.com/docs/features$ssr)
25
+
26
+ 此框架脱胎于 [egg-react-ssr](https://github.com/zhangyuang/egg-react-ssr) 项目和 `ssr` v4版本`(midway-faas + react ssr)`,在之前的基础上做了诸多演进,通过插件化的代码组织形式,支持任意服务端框架与任意前端框架的组合使用。开发者可以选择通过 `Serverless` 方式部署或是以传统 `Node.js` 的应用形式部署,并且我们专注于提升 `Serverless` 场景下服务端渲染应用的开发体验,打造了一站式的开发,发布应用服务的功能。最大程度提升开发者的开发体验,将应用的开发,部署成本降到最低。
27
+
28
+ 在最新的版本中,同时支持 `React` 和 `Vue2/Vue3` 作为服务端渲染框架且开发工具侧我们同样支持了最流行的 `Vite` 来提升应用的启动速度和 HMR 速度,且提供一键以 `Serverless` 的形式发布上云的功能。我们可以非常有自信说它是地球上最先进的 `ssr` 框架。如果你希望获得开箱即用的体验且能够一键部署上云,请选择 `ssr` 框架。
29
+
30
+ 阅读我们的 [官方文档](http://doc.ssr-fc.com/) 获得更加详细的了解。事实上文档本身便是用 `ssr` 框架开发并通过 `Serverless` 部署到阿里云服务
31
+
32
+ ![](https://res.wx.qq.com/op_res/B9tJE-lFR3gCif92sM4BeeqAcoJSZbJK-auM7MACgomrWm58C1moA3BfatZ5gS-tgZHYyk57e0JQRtgdcgho-g)
33
+
34
+ ## 什么情况下你应该选择 ssr 框架
35
+
36
+ - 需要在 `Node.js` 与前端框架结合的场景使用,与其他纯前端的框架不同 `ssr` 框架是专为服务端渲染场景或者 `Node.js` 与前端结合的场景打造的框架
37
+ - 需要一个开箱即用的服务端渲染能力,不需要手动去组合不同的前端框架与服务端框架之间的联系
38
+ - 需要框架层面的渲染降级能力,在服务端渲染出错时自动降级到客户端渲染
39
+ - 需要一个配置简单逻辑清晰的框架, `ssr` 框架的渲染逻辑和应用构建逻辑是同类型框架中最清晰的
40
+ - 可能会改动技术栈,如从 `Vue2` 升级为 `Vue3`,从 `Vue3` 降级为 `Vue2` 或 `React/Vue` 互相切换
41
+ - 需要在服务端渲染场景下开箱即用使用 `antd` `vant` 等流行 `ui` 库
42
+ - 需要能够同时支持 `Webpack`, `Vite` 两种开发工具,以便同时得到快速的启动速度 `HMR` 速度以及稳定的生产环境代码
43
+ - 需要在 `Vue3` 场景支持 `Script Setup` 以及 [pinia](https://pinia.vuejs.org/) 作为数据管理方案
44
+
45
+ ## 哪些应用在使用
46
+
47
+ 正在使用这个项目的公司(应用), 如果您正在使用但名单中没有列出来的话请提 [issue](https://github.com/zhangyuang/ssr/issues),欢迎推广分享,我们将随时提供技术支持
48
+
49
+ <table>
50
+ <tr>
51
+ <td align="center"><a target="_blank" href="http://youku.com/"><img src="https://img.alicdn.com/tfs/TB17DTuXkH0gK0jSZPiXXavapXa-680-133.svg" width="120"/><br />
52
+ <sub><b>优酷视频
53
+ </b></td>
54
+ <td align="center" style="width: 120px;"><a target="_blank" href="https://yulebao.alibaba.com/"><img src="https://gw.alicdn.com/tfs/TB1CmlIIFT7gK0jSZFpXXaTkpXa-190-46.png" width="120"/><br><sub><b>阿里影业娱乐宝
55
+ </b></sub></a></td>
56
+ <td align="center"><a href="https://www.niuniuda.com/mall" target="_blank"><img src="https://img.alicdn.com/tfs/TB1df_8pBr0gK0jSZFnXXbRRXXa-160-60.png" width="120" alt="牛牛搭"/><br />
57
+ <a href="https://www.niuniuda.com/mall" target="_blank"><sub><b>牛牛搭
58
+ </b></a></td>
59
+ <td align="center"><a href="https://www.gszq.com/" target="_blank"><img src="https://www.gszq.com/static/media/icon-slogan.4d1c7974.png
60
+ " width="120" alt="国盛证券"/><br />
61
+ <a href="https://www.gszq.com/" target="_bvlank"><sub><b>国盛证券
62
+ </b></a></td>
63
+ <td align="center"><a href="https://m.isle.org.cn" target="_blank"><img src="https://res.wx.qq.com/op_res/qzBjcpT1AZDopDDkEJfj5gKFADotYHTgD33lz9xvZUIj7VJaIR_8HE4lfOxwaiYBgi4V2xXm0xLmAcdQxF4IrQ" width="120" alt="三易科技"/><br />
64
+ <a href="https://m.isle.org.cn" target="_bvlank"><sub><b>三易科技
65
+ </b></a></td>
66
+ <td align="center"><a href="https://help.seewo.com/" target="_blank"><img src="https://img.alicdn.com/tfs/TB11Xo3q4v1gK0jSZFFXXb0sXXa-350-55.png" width="120" alt="cvte"/><br /><a href="https://help.seewo.com/" target="_blank"><sub><b>希沃帮助中心
67
+ </b></a></td>
68
+ <td align="center"><a href="https://wecard.qq.com/index/" target="_blank"><img src="https://img.alicdn.com/tfs/TB1pTZGrFT7gK0jSZFpXXaTkpXa-164-164.jpg" width="120" alt="腾讯微卡"/><br />
69
+ <a href="https://wecard.qq.com/index/" target="_blank"><sub><b>腾讯微卡
70
+ </b></a></td>
71
+ <td align="center" style="height: 100px"><a href="https://www.habisummercamp.com/" target="_blank"><img src="https://res.wx.qq.com/op_res/XXUpF56bDue53vZadoCSPSnqKF3bZqPOQnqsPa_ngEARa0OUIW22pX7eKsftPb6pc5ny62cR_wXM4g5xJ7G3DQ
72
+ " width="200px;margin: 20px 0" alt="Happy"/><br />
73
+ <a href="https://www.habisummercamp.com/" target="_bvlank"><b>HappyPC
74
+ </b></a></td>
75
+ <td align="center" style="height: 100px"><a href="https://m.habisummercamp.com/" target="_blank"><img src="https://res.wx.qq.com/op_res/XXUpF56bDue53vZadoCSPSnqKF3bZqPOQnqsPa_ngEARa0OUIW22pX7eKsftPb6pc5ny62cR_wXM4g5xJ7G3DQ
76
+ " width="200px;margin: 20px 0" alt="Happy"/><br />
77
+ <a href="https://m.habisummercamp.com/" target="_bvlank"><b>HappyMobile
78
+ </b></a></td>
79
+ </tr>
80
+ <tr>
81
+ <td align="center"><a href="https://syzs.qq.com/" target="_blank"><img src="images/syzs.png" width="120" alt="腾讯手游助手"/><br />
82
+ <a href="https://syzs.qq.com/" target="_bvlank"><sub><b>腾讯手游助手
83
+ </b></a></td>
84
+ <td align="center"><a href="https://kcmall.b2bwings.com/home" target="_blank"><img src="https://img.alicdn.com/imgextra/i1/O1CN01P7CAop1h7qQ3noefa_!!6000000004231-2-tps-211-79.png" width="120" alt="国家现代农业科技创新中心"/><br />
85
+ <a href="https://kcmall.b2bwings.com/home" target="_bvlank"><sub><b>国家现代农业科技创新中心
86
+ </b></a></td>
87
+ <td align="center"><a target="_blank" href="http://ssr-fc.com/"><img src="https://img.alicdn.com/tfs/TB13DzOjXP7gK0jSZFjXXc5aXXa-212-48.png" width="120"/><br><sub><b>部署于阿里云示例应用
88
+ </b></sub></a></td>
89
+ <td align="center"><a target="_blank" href="http://tx.ssr-fc.com/"><img src="http://s0.60logo.com/uploads/items/images/soft/180126/tengxunyun.svg" width="120"/><br><sub><b>部署于腾讯云示例应用
90
+ </b></sub></a></td>
91
+ <td align="center"><a href="https://www.100.com/" target="_blank"><img src="https://oss.bs2dl.100.com/hippo/config/f13ee98cfca7ce13888752c1261081b44bd356fd.png" width="120" alt="100教育"/><br />
92
+ <a href="https://www.100.com/" target="_bvlank"><sub><b>100教育
93
+ </b></a></td>
94
+ <td align="center" style="height: 100px"><a href="https://m.film.qq.com/x/tva-vip-center/" target="_blank"><img src="https://res.wx.qq.com/op_res/x7sWI9AfUK1QwH0EDhKp4e_bGWxYOQ_1RlZqBFy9JntJzaE4aRzNhVgmxLNloAFpSQ-mBr9X9pux3QlV9QHHvQ" width="200px;margin: 20px 0" alt="腾讯视频"/><br />
95
+ <a href="https://m.film.qq.com/x/tva-vip-center/" target="_bvlank"><b>腾讯视频
96
+ </b></a></td>
97
+ <td align="center" style="height: 100px"><a href="https://blog.dreamer2q.wang/" target="_blank"><img src="https://res.wx.qq.com/op_res/MxxGgjPFRiTgjiReUefs2aMce-SgNvxxTB9U87YYhcOu6KPw9er7r2Lc0ne-b90nFstTUpc8REDwpxfUreKV1g" width="200px;margin: 20px 0" alt="Dream2qBlog"/><br />
98
+ <a href="https://blog.dreamer2q.wang/" target="_bvlank"><b>个人博客
99
+ </b></a></td>
100
+ <td align="center" style="height: 100px"><a href="https://jiawu.dewu.com" target="_blank"><img src="https://cdn.poizon.com/node-common/31116a45953ad8b468c6c832036aac88.png" width="200px;margin: 20px 0" alt="Dream2qBlog"/><br />
101
+ <a href="https://jiawu.dewu.com" target="_bvlank"><b>得物
102
+ </b></a></td>
103
+ <td align="center"><a href="https://www.myweimai.com/#sectionOne" target="_blank"><img src="https://img.alicdn.com/tfs/TB16i3VrQT2gK0jSZPcXXcKkpXa-400-400.jpg" width="120" alt="微脉"/><br />
104
+ <a href="https://www.myweimai.com/#sectionOne" target="_bvlank"><sub><b>微脉
105
+ </b></a></td>
106
+ </tr>
107
+ <tr>
108
+ <td align="center"><a target="_blank" href="https://campaign.vmate.com/vrbollywood"><img src="https://img.alicdn.com/tfs/TB17p6Vhbj1gK0jSZFOXXc7GpXa-512-512.png" width="120" alt="vmate 积分商城"/><br />
109
+ <a target="_blank" href="https://job.alibaba.com/zhaopin/position_detail.htm?trace=qrcode_share&positionCode=GP524819"><sub><b>Vmate短视频
110
+ </b></a></td>
111
+ <td align="center"><a target="_blank" href="https://enjoysales.paat.com/"><img src="https://img.alicdn.com/tfs/TB1Ma0BiEY1gK0jSZFMXXaWcVXa-836-836.png" width="120" alt="火炽星原CRM"/><br />
112
+ <a target="_blank" href="https://enjoysales.paat.com/"><sub><b>火炽星原CRM
113
+ </b></a></td>
114
+ <td align="center" style="height: 100px"><a href="https://www.paixin.com/" target="_blank"><img src="https://www.paixin.com/favicon.ico" width="200px;margin: 20px 0" alt="Happy"/><br />
115
+ <a href="https://www.paixin.com/" target="_bvlank"><b>拍信创意
116
+ </b></a></td>
117
+ <td align="center"><a href="https://www.66tools.com/" target="_blank"><img src="https://cdn.66tools.com/extension/chrome_qrcode_avatar.png" width="120" alt="极速二维码"/><br />
118
+ <a href="https://www.66tools.com/" target="_bvlank"><sub><b>极速二维码
119
+ </b></a></td>
120
+ </tr>
121
+ </table>
122
+
123
+ ## Features
124
+
125
+ - 🌱 极易定制:前端支持 React/Vue2/Vue3 等现代Web框架;
126
+ - 🚀 开箱即用:内置 10+ 脚手架配套扩展,如 [Pinia](https://pinia.vuejs.org/introduction.html#basic-example)、[antd](https://ant.design/components/overview-cn/)、[vant](https://github.com/youzan/vant)、TypeScript、Hooks等;
127
+ - 🧲 插件驱动:基于插件架构,用户更加专注于业务逻辑;
128
+ - 💯 Serverless优先:一键发布到各种Serverless平台,也支持传统Web Server,比如Egg、Midway、Nest等。
129
+ - 🛡 高可用场景,可无缝从SSR降级到CSR,最佳容灾方案。
130
+ - 😄 功能丰富,构建工具支持 Webpack/Vite,全新的 `Vue3 Script Setup` 支持
131
+
132
+ ## 已实现的功能
133
+
134
+ 🚀 表示已经实现的功能
135
+
136
+ | 里程碑 | 状态 |
137
+ | ---------------------------------------------------------------------- | ---- |
138
+ | 支持任意服务端框架与任意前端框架的组合使用。(Serverless/Midway/NestJS) + (React/Vue2/Vue3) | 🚀 |
139
+ | 最丝滑的 [vite](https://vite-design.surge.sh/) [支持](http://doc.ssr-fc.com/docs/features$vite) | 🚀 |
140
+ | 最小而美的实现服务端渲染功能 | 🚀 |
141
+ | 针对Serverless 场景对代码包的大小的严格限制,将生产环境的代码包大小做到极致 | 🚀 |
142
+ | 同时支持约定式前端路由和声明式前端路由 | 🚀 |
143
+ | 摒弃传统模版引擎,所有页面元素统一使用前端组件作为 DSL | 🚀 |
144
+ | 同时支持三种渲染模式,提供服务端渲染一键降级为客户端渲染的能力 | 🚀 |
145
+ | 统一不同框架服务端客户端的数据获取方式,做到高度复用 | 🚀 |
146
+ | 类型友好,全面拥抱 TS | 🚀 |
147
+ | 支持无缝接入 [antd](https://github.com/ant-design/ant-design) [vant](https://vant-contrib.gitee.io/vant/#/) 无需修改任何配置 | 🚀 |
148
+ | 支持使用 less 作为 css 预处理器 | 🚀 |
149
+ | 微前端场景下无缝[使用](http://doc.ssr-fc.com/docs/features$faq#%E4%B8%8E%20micro-app%20%E7%BB%93%E5%90%88%E4%BD%BF%E7%94%A8) | 🚀 |
150
+ | React Hooks 实现极简的[数据管理](http://doc.ssr-fc.com/docs/features$communication#React%20%E5%9C%BA%E6%99%AF)方案,摒弃传统的 redux/dva 等数据管理方案 | 🚀 |
151
+ | Vue3 场景提供 [Pinia](https://pinia.vuejs.org/introduction.html#basic-example) 以及 [Provide/Inject](http://doc.ssr-fc.com/docs/features$communication#Vue%20%E5%9C%BA%E6%99%AF%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88) 代替 `Vuex` 进行跨组件通信 | 🚀 |
152
+ | 支持在阿里云 [云平台](https://zhuanlan.zhihu.com/p/139210473)创建使用 | 🚀 |
153
+ | ssr deploy 一键部署到[阿里云](https://www.aliyun.com/)平台 | 🚀 |
154
+ | ssr deploy --tencent 无需修改任何配置一键部署到[腾讯云](https://cloud.tencent.com/)平台 | 🚀 |
155
+
156
+ ## 方案对比
157
+
158
+ 为什么要选择 `ssr` 框架以及与同类型框架的方案对比请查看[文档](http://doc.ssr-fc.com/docs/why)
159
+
160
+ ## 快速开始
161
+
162
+ 我们提供了 [create-ssr-app](https://github.com/zhangyuang/create-ssr-app) 脚手架来让用户可以迅速的创建不同类型的应用。
163
+
164
+ 目前官方提供了以下类型的模版给开发者直接使用。用户可根据自己的实际技术栈选择不同的模版进行开发。
165
+
166
+ 虽然技术栈不同但开发思想是一致的,在任何技术栈的组合中我们的开发命令, 构建命令以及渲染原理都是完全一致的
167
+
168
+ 注意: 在 `Midway.js` `Nest.js` 场景下我们都已实现了一键部署到 `Serverless` 平台的能力。但底层实现略有差异。更加详细的介绍可以阅读 [Serverless](http://doc.ssr-fc.com/docs/features$serverless) 章节。如需要大量使用 `Serverless` 平台提供的能力,我们建议创建 `Midway.js` 类型的应用。强烈建议阅读我们的 [官方文档](http://doc.ssr-fc.com/) 来获得更加详细的了解
169
+
170
+ - [nestjs-react-ssr](https://github.com/zhangyuang/ssr/tree/dev/example/nestjs-react-ssr)
171
+ - [nestjs-vue-ssr](https://github.com/zhangyuang/ssr/tree/dev/example/nestjs-vue-ssr)
172
+ - [nestjs-vue3-ssr](https://github.com/zhangyuang/ssr/tree/dev/example/nestjs-vue3-ssr)
173
+ - [nestjs-vue3-ssr-pinia](https://github.com/zhangyuang/nestjs-vue3-ssr-pinia)
174
+ - [midway-react-ssr](https://github.com/zhangyuang/ssr/tree/dev/example/midway-react-ssr)
175
+ - [midway-vue-ssr](https://github.com/zhangyuang/ssr/tree/dev/example/midway-vue-ssr)
176
+ - [midway-vue3-ssr](https://github.com/zhangyuang/ssr/tree/dev/example/midway-vue3-ssr)
177
+
178
+ 开发者可根据实际技术栈需要创建不同类型的应用快速开始
179
+
180
+ ### 创建项目
181
+
182
+ 通过 `npm init` 命令我们可以创建上述的任意模版
183
+
184
+ ```bash
185
+ $ npm init ssr-app my-ssr-project
186
+ $ cd my-ssr-project
187
+ $ yarn # 建议使用 yarn, 也可以 npm install
188
+ $ yarn start
189
+ $ open http://localhost:3000 # 访问应用
190
+ $ yarn build # 资源构建,等价于 npx ssr build
191
+ $ yarn start:vite # 以 vite 模式启动,等价于 npx ssr start --vite
192
+ ```
193
+
194
+ ![](images/start-vite3.gif)
195
+
196
+ ## 线上案例
197
+
198
+ 通过访问以下链接来预览该框架通过 Serverless 一键部署到阿里云/腾讯云服务的应用详情。
199
+ 通过使用 queryParams `csr=true` 来让 SSR 服务端渲染模式一键降级为 CSR 客户端渲染模式,也可以通过 `config.js` 来进行配置。
200
+
201
+ - http://ssr-fc.com/ 部署到阿里云的 React SSR 应用
202
+ - http://ssr-fc.com?csr=true 部署到阿里云的 React SSR 应用, 以 CSR 模式访问
203
+ - http://tx.ssr-fc.com 部署到腾讯云的 React SSR 应用
204
+ - http://tx.ssr-fc.com?csr=true 部署到腾讯云的 React SSR 应用, 以 CSR 模式访问
205
+ - http://vue.ssr-fc.com 部署到阿里云的 Vue SSR 应用
206
+ - http://vue3.ssr-fc.com 部署到阿里云的 Vue3 SSR 应用
207
+ - http://vue.ssr-fc.com?csr=true 部署到阿里云的 Vue SSR 应用, 以 CSR 模式访问
208
+ - http://vue3.ssr-fc.com?csr=true 部署到阿里云的 Vue3 SSR 应用, 以 CSR 模式访问
209
+
210
+ ## 生态系统
211
+
212
+ | Project | Status | Description |
213
+ |---------|--------|-------------|
214
+ | [ssr] | [![ssr-status]][ssr] | cli for ssr framework |
215
+ | [ssr-core-vue] | [![ssr-core-vue-status]][ssr-core-vue] | core render for vue |
216
+ | [ssr-core-react] | [![ssr-core-react-status]][ssr-core-react] | core render for react |
217
+ | [ssr-plugin-midway] | [![ssr-plugin-midway-status]][ssr-plugin-midway] | provide start and build fetature by [midway@2.0](https://midwayjs.org/) |
218
+ | [ssr-plugin-nestjs] | [![ssr-plugin-nestjs-status]][ssr-plugin-nestjs] | provide start and build feature by [NestJS](https://docs.nestjs.com/) |
219
+ | [ssr-plugin-react] | [![ssr-plugin-react-status]][ssr-plugin-react] | develop react application only be used in development |
220
+ | [ssr-plugin-vue] | [![ssr-plugin-vue-status]][ssr-plugin-vue] | develop vue2 application only be used in development |
221
+ | [ssr-plugin-vue3] | [![ssr-plugin-vue3-status]][ssr-plugin-vue3] | develop vue3 application only be used in development |
222
+ | [ssr-server-utils] | [![ssr-server-utils-status]][ssr-server-utils] | server utils in Node.js environment |
223
+ | [ssr-client-utils] | [![ssr-client-utils-status]][ssr-client-utils] | client utils in browser environment |
224
+ | [ssr-hoc-react] | [![ssr-hoc-react-status]][ssr-hoc-react] | provide hoc component for react |
225
+ | [ssr-hoc-vue3] | [![ssr-hoc-vue3-status]][ssr-hoc-vue3] | provide hoc component for vue3 |
226
+ | [ssr-types] | [![ssr-types-status]][ssr-types] | provide common types |
227
+ | [ssr-types-react] | [![ssr-types-react-status]][ssr-types-react] | provide react scene types |
228
+ | [ssr-webpack] | [![ssr-webpack-status]][ssr-webpack] | start local server and build production bundle by webpack |
229
+
230
+
231
+ [ssr-status]: https://img.shields.io/npm/v/ssr.svg
232
+ [ssr-client-utils-status]: https://img.shields.io/npm/v/ssr-client-utils.svg
233
+ [ssr-core-react-status]: https://img.shields.io/npm/v/ssr-core-react.svg
234
+ [ssr-core-vue-status]: https://img.shields.io/npm/v/ssr-core-vue.svg
235
+ [ssr-hoc-react-status]: https://img.shields.io/npm/v/ssr-hoc-react.svg
236
+ [ssr-hoc-vue3-status]: https://img.shields.io/npm/v/ssr-hoc-vue3.svg
237
+ [ssr-plugin-midway-status]: https://img.shields.io/npm/v/ssr-plugin-midway.svg
238
+ [ssr-plugin-nestjs-status]: https://img.shields.io/npm/v/ssr-plugin-nestjs.svg
239
+ [ssr-plugin-react-status]: https://img.shields.io/npm/v/ssr-plugin-react.svg
240
+ [ssr-plugin-vue-status]: https://img.shields.io/npm/v/ssr-plugin-vue.svg
241
+ [ssr-plugin-vue3-status]: https://img.shields.io/npm/v/ssr-plugin-vue3.svg
242
+ [ssr-server-utils-status]: https://img.shields.io/npm/v/ssr-server-utils.svg
243
+ [ssr-types-status]: https://img.shields.io/npm/v/ssr-types.svg
244
+ [ssr-types-react-status]: https://img.shields.io/npm/v/ssr-types-react.svg
245
+ [ssr-webpack-status]: https://img.shields.io/npm/v/ssr-webpack.svg
246
+
247
+ [ssr]: https://github.com/zhangyuang/ssr/tree/dev/packages/cli
248
+ [ssr-client-utils]: https://github.com/zhangyuang/ssr/tree/dev/packages/client-utils
249
+ [ssr-core-react]: https://github.com/zhangyuang/ssr/tree/dev/packages/core-react
250
+ [ssr-core-vue]: https://github.com/zhangyuang/ssr/tree/dev/packages/core-vue
251
+ [ssr-hoc-react]: https://github.com/zhangyuang/ssr/tree/dev/packages/hoc-react
252
+ [ssr-hoc-vue3]: https://github.com/zhangyuang/ssr/tree/dev/packages/hoc-vue3
253
+ [ssr-plugin-midway]: https://github.com/zhangyuang/ssr/tree/dev/packages/plugin-midway
254
+ [ssr-plugin-nestjs]: https://github.com/zhangyuang/ssr/tree/dev/packages/plugin-nestjs
255
+ [ssr-plugin-react]: https://github.com/zhangyuang/ssr/tree/dev/packages/plugin-react
256
+ [ssr-plugin-vue]: https://github.com/zhangyuang/ssr/tree/dev/packages/plugin-vue
257
+ [ssr-plugin-vue3]: https://github.com/zhangyuang/ssr/tree/dev/packages/plugin-vue3
258
+ [ssr-server-utils]: https://github.com/zhangyuang/ssr/tree/dev/packages/server-utils
259
+ [ssr-types]: https://github.com/zhangyuang/ssr/tree/dev/packages/types
260
+ [ssr-types-react]: https://github.com/zhangyuang/ssr/tree/dev/packages/types-react
261
+ [ssr-webpack]: https://github.com/zhangyuang/ssr/tree/dev/packages/webpack
262
+ ## CONTRIBUTING
263
+
264
+ 如果你想为本应用贡献代码,请阅读[贡献文档](./CONTRIBUTING.md),我们为你准备了丰富的脚本用于 bootstrap
265
+
266
+ ## License
267
+
268
+ [MIT](LICENSE)
269
+
270
+ ## 答疑群
271
+
272
+ 虽然我们已经尽力检查了一遍应用,但仍有可能有疏漏的地方,如果你在使用过程中发现任何问题或者建议,欢迎提[issue](https://github.com/zhangyuang/ssr/issues)或者[PR](https://github.com/zhangyuang/ssr/pulls)
273
+
274
+ `注: 由于微信交流群人数限制,进群请添加私人二维码并备注进入 ssr 交流群,由于是私人微信,拉群后将会自行删除好友,敬请谅解。我们更加鼓励通过 issue 和 discussion 来交流问题`
275
+
276
+ <div style="display:flex">
277
+ <!-- <img src="https://res.wx.qq.com/op_res/7F1t4Z8yCHWilehbcFGjAj0yVn0URMiWBGVJa-TVu_eqw5IwUXA2kPYBnfX6YRHy0FVBB-yC6l0IEL02QTJkLg" width="300"> -->
278
+ <img src="https://res.wx.qq.com/op_res/Nv12X2und927FEOvJ5iflzX-WBW07GSC22kumTCiShZnudKpG0jMuRs70ecHQb3Hy1QjjaASNzyOuMgHr43Wpw" width="300">
279
+ </div>
280
+
281
+ ## 代码行数
282
+
283
+ ```bash
284
+ $ cloc packages --include-ext=ts
285
+ 984 text files.
286
+ 668 unique files.
287
+ 823 files ignored.
288
+
289
+ github.com/AlDanial/cloc v 1.90 T=0.57 s (284.6 files/s, 10042.8 lines/s)
290
+ -------------------------------------------------------------------------------
291
+ Language files blank comment code
292
+ -------------------------------------------------------------------------------
293
+ TypeScript 161 480 197 5004
294
+ -------------------------------------------------------------------------------
295
+ SUM: 161 480 197 5004
296
+ -------------------------------------------------------------------------------
297
+ ```
298
+
299
+ ## 前端开发手册
300
+
301
+ [如何打造舒适高效的前端开发环境](http://fe.ssr-fc.com/)
302
+
303
+ ## 项目 Star 数增长趋势
304
+
305
+ [![Stargazers over time](https://starchart.cc/zhangyuang/ssr.svg)](https://starchart.cc/zhangyuang/ssr)
@@ -1,3 +1,4 @@
1
1
  import * as WebpackChain from 'webpack-chain';
2
- declare const getBaseConfig: (chain: WebpackChain, isServer: boolean) => IConfig;
2
+ declare const getBaseConfig: (chain: WebpackChain, isServer: boolean) => import("ssr-types-react").IConfig;
3
3
  export { getBaseConfig };
4
+ //# sourceMappingURL=base.d.ts.map
@@ -7,9 +7,9 @@ const webpack = require("webpack");
7
7
  const MiniCssExtractPlugin = require((0, ssr_server_utils_1.loadModuleFromFramework)('mini-css-extract-plugin'));
8
8
  const WebpackBar = require('webpackbar');
9
9
  const loadModule = ssr_server_utils_1.loadModuleFromFramework;
10
- const addBabelLoader = (chain, envOptions) => {
10
+ const addBabelLoader = (chain, envOptions, isServer) => {
11
11
  var _a, _b;
12
- const { babelOptions } = (0, ssr_server_utils_1.loadConfig)();
12
+ const { babelOptions, isDev } = (0, ssr_server_utils_1.loadConfig)();
13
13
  chain.use('babel-loader')
14
14
  .loader(loadModule('babel-loader'))
15
15
  .options({
@@ -41,7 +41,7 @@ const addBabelLoader = (chain, envOptions) => {
41
41
  [loadModule('@babel/plugin-proposal-private-methods'), { loose: true }],
42
42
  [loadModule('@babel/plugin-proposal-private-property-in-object'), { loose: true }],
43
43
  ...(_b = babelOptions === null || babelOptions === void 0 ? void 0 : babelOptions.plugins) !== null && _b !== void 0 ? _b : []
44
- ]
44
+ ].concat((!isServer && isDev) ? loadModule('react-refresh/babel') : [])
45
45
  })
46
46
  .end();
47
47
  };
@@ -98,8 +98,8 @@ const getBaseConfig = (chain, isServer) => {
98
98
  else {
99
99
  babelForExtraModule = module.end().exclude.add(/core-js/).end();
100
100
  }
101
- addBabelLoader(babelModule, envOptions);
102
- addBabelLoader(babelForExtraModule, envOptions);
101
+ addBabelLoader(babelModule, envOptions, isServer);
102
+ addBabelLoader(babelForExtraModule, envOptions, isServer);
103
103
  (0, ssr_server_utils_1.setStyle)(chain, /\.css$/, {
104
104
  rule: 'css',
105
105
  isServer,
@@ -138,3 +138,4 @@ const getBaseConfig = (chain, isServer) => {
138
138
  return config;
139
139
  };
140
140
  exports.getBaseConfig = getBaseConfig;
141
+ //# sourceMappingURL=base.js.map
@@ -2,3 +2,4 @@
2
2
  import * as WebpackChain from 'webpack-chain';
3
3
  declare const getClientWebpack: (chain: WebpackChain) => import("webpack").Configuration;
4
4
  export { getClientWebpack };
5
+ //# sourceMappingURL=client.d.ts.map
@@ -8,11 +8,12 @@ const base_1 = require("./base");
8
8
  const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
9
9
  const safePostCssParser = require('postcss-safe-parser');
10
10
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
11
+ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
11
12
  const generateAnalysis = Boolean(process.env.GENERATE_ANALYSIS);
12
13
  const loadModule = ssr_server_utils_1.loadModuleFromFramework;
13
14
  let asyncChunkMap = {};
14
15
  const getClientWebpack = (chain) => {
15
- const { isDev, chunkName, getOutput, cwd, useHash, chainClientConfig } = (0, ssr_server_utils_1.loadConfig)();
16
+ const { isDev, chunkName, getOutput, cwd, useHash, chainClientConfig, host, fePort } = (0, ssr_server_utils_1.loadConfig)();
16
17
  const shouldUseSourceMap = isDev || Boolean(process.env.GENERATE_SOURCEMAP);
17
18
  const publicPath = (0, ssr_server_utils_1.getOutputPublicPath)();
18
19
  (0, base_1.getBaseConfig)(chain, false);
@@ -89,6 +90,14 @@ const getClientWebpack = (chain) => {
89
90
  chain.when(generateAnalysis, chain => {
90
91
  chain.plugin('analyze').use(BundleAnalyzerPlugin);
91
92
  });
93
+ chain.when(isDev, chain => {
94
+ chain.plugin('fast-refresh').use(new ReactRefreshWebpackPlugin({
95
+ overlay: {
96
+ sockHost: host,
97
+ sockPort: fePort
98
+ }
99
+ }));
100
+ });
92
101
  chain.plugin('WriteAsyncManifest').use(class WriteAsyncChunkManifest {
93
102
  apply(compiler) {
94
103
  compiler.hooks.watchRun.tap('thisCompilation', async () => {
@@ -105,3 +114,4 @@ const getClientWebpack = (chain) => {
105
114
  return chain.toConfig();
106
115
  };
107
116
  exports.getClientWebpack = getClientWebpack;
117
+ //# sourceMappingURL=client.js.map
@@ -1,2 +1,3 @@
1
1
  export * from './client';
2
2
  export * from './server';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./client"), exports);
18
18
  __exportStar(require("./server"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -2,3 +2,4 @@ import * as WebpackChain from 'webpack-chain';
2
2
  import * as webpack from 'webpack';
3
3
  declare const getServerWebpack: (chain: WebpackChain) => webpack.Configuration;
4
4
  export { getServerWebpack };
5
+ //# sourceMappingURL=server.d.ts.map
@@ -35,3 +35,4 @@ const getServerWebpack = (chain) => {
35
35
  return chain.toConfig();
36
36
  };
37
37
  exports.getServerWebpack = getServerWebpack;
38
+ //# sourceMappingURL=server.js.map
@@ -1,2 +1,3 @@
1
1
  declare const clientRender: () => Promise<void>;
2
2
  export { clientRender };
3
+ //# sourceMappingURL=client-entry.d.ts.map
@@ -8,14 +8,13 @@ const ssr_client_utils_1 = require("ssr-client-utils");
8
8
  const ssr_hoc_react_1 = require("ssr-hoc-react");
9
9
  const create_router_1 = require("./create-router");
10
10
  const context_1 = require("./context");
11
- const { FeRoutes, layoutFetch, App, PrefixRouterBase } = create_router_1.Routes;
11
+ const { FeRoutes, layoutFetch, App } = create_router_1.Routes;
12
12
  const clientRender = async () => {
13
- var _a, _b, _c, _d;
14
13
  const IApp = App !== null && App !== void 0 ? App : function (props) {
15
14
  return props.children;
16
15
  };
17
16
  // 客户端渲染||hydrate
18
- const baseName = (_b = (_a = (window.microApp && window.clientPrefix)) !== null && _a !== void 0 ? _a : window.prefix) !== null && _b !== void 0 ? _b : PrefixRouterBase;
17
+ const baseName = window.microApp ? window.clientPrefix : window.prefix;
19
18
  const routes = await (0, ssr_client_utils_1.preloadComponent)(FeRoutes, baseName);
20
19
  ReactDOM[window.__USE_SSR__ ? 'hydrate' : 'render'](React.createElement(react_router_dom_1.BrowserRouter, { basename: baseName },
21
20
  React.createElement(context_1.AppContext, null,
@@ -30,9 +29,6 @@ const clientRender = async () => {
30
29
  const WrappedComponent = (0, ssr_hoc_react_1.wrapComponent)(component);
31
30
  return (React.createElement(react_router_dom_1.Route, { exact: true, key: path, path: path, render: () => React.createElement(WrappedComponent, { key: location.pathname }) }));
32
31
  })))))), document.getElementById('app'));
33
- if (!window.__USE_VITE__) {
34
- (_d = (_c = module === null || module === void 0 ? void 0 : module.hot) === null || _c === void 0 ? void 0 : _c.accept) === null || _d === void 0 ? void 0 : _d.call(_c); // webpack 场景下的 hmr
35
- }
36
32
  };
37
33
  exports.clientRender = clientRender;
38
34
  if (!window.__disableClientRender__) {
@@ -40,3 +36,4 @@ if (!window.__disableClientRender__) {
40
36
  // 可用于微前端场景下自定义什么时候进行组件渲染的逻辑调用
41
37
  clientRender();
42
38
  }
39
+ //# sourceMappingURL=client-entry.js.map
@@ -1,3 +1,4 @@
1
1
  /// <reference types="react" />
2
2
  import { IProps } from 'ssr-types-react';
3
3
  export declare function AppContext(props: IProps): JSX.Element;
4
+ //# sourceMappingURL=context.d.ts.map
@@ -29,3 +29,4 @@ function AppContext(props) {
29
29
  return (React.createElement(create_context_1.STORE_CONTEXT.Provider, { value: { state, dispatch } }, props.children));
30
30
  }
31
31
  exports.AppContext = AppContext;
32
+ //# sourceMappingURL=context.js.map
@@ -2,3 +2,4 @@ import { Context } from 'react';
2
2
  import { IContext } from 'ssr-types-react';
3
3
  declare let STORE_CONTEXT: Context<IContext>;
4
4
  export { STORE_CONTEXT };
5
+ //# sourceMappingURL=create-context.d.ts.map
@@ -17,3 +17,4 @@ else {
17
17
  state: {}
18
18
  });
19
19
  }
20
+ //# sourceMappingURL=create-context.js.map
@@ -1,3 +1,4 @@
1
1
  import { ReactRoutesType } from 'ssr-types-react';
2
2
  declare const Routes: ReactRoutesType;
3
3
  export { Routes };
4
+ //# sourceMappingURL=create-router.d.ts.map
@@ -24,3 +24,4 @@ if (ManualRoutesWithType.FeRoutes) {
24
24
  });
25
25
  Routes.FeRoutes = combineRoutes;
26
26
  }
27
+ //# sourceMappingURL=create-router.js.map
@@ -2,3 +2,4 @@ import * as React from 'react';
2
2
  import { ISSRContext, IConfig } from 'ssr-types-react';
3
3
  declare const serverRender: (ctx: ISSRContext, config: IConfig) => Promise<React.ReactElement>;
4
4
  export { serverRender };
5
+ //# sourceMappingURL=server-entry.d.ts.map
@@ -4,23 +4,15 @@ exports.serverRender = void 0;
4
4
  const React = require("react");
5
5
  const react_router_dom_1 = require("react-router-dom");
6
6
  const ssr_server_utils_1 = require("ssr-server-utils");
7
- // @ts-expect-error
8
- const serializeWrap = require("serialize-javascript");
7
+ const ssr_serialize_javascript_1 = require("ssr-serialize-javascript");
9
8
  // @ts-expect-error
10
9
  const create_context_1 = require("_build/create-context");
11
- // @ts-expect-error
12
- const index_tsx_1 = require("@/components/layout/index.tsx");
13
10
  const create_router_1 = require("./create-router");
14
- const { FeRoutes, layoutFetch, PrefixRouterBase, state } = create_router_1.Routes;
15
- const serialize = serializeWrap.default || serializeWrap;
11
+ const { FeRoutes, layoutFetch, state, Layout } = create_router_1.Routes;
16
12
  const serverRender = async (ctx, config) => {
17
13
  var _a;
18
14
  const { mode, parallelFetch, disableClientRender, prefix, isVite, isDev, clientPrefix } = config;
19
- let path = ctx.request.path; // 这里取 pathname 不能够包含 queryString
20
- const base = prefix !== null && prefix !== void 0 ? prefix : PrefixRouterBase; // 以开发者实际传入的为最高优先级
21
- if (base) {
22
- path = (0, ssr_server_utils_1.normalizePath)(path, base);
23
- }
15
+ const path = (0, ssr_server_utils_1.normalizePath)(ctx.request.path, prefix);
24
16
  const routeItem = (0, ssr_server_utils_1.findRoute)(FeRoutes, path);
25
17
  if (!routeItem) {
26
18
  throw new Error(`
@@ -36,11 +28,7 @@ const serverRender = async (ctx, config) => {
36
28
  if (isVite && isDev) {
37
29
  injectCss.push(React.createElement("script", { src: "/@vite/client", type: "module", key: "vite-client" }));
38
30
  injectCss.push(React.createElement("script", { key: "vite-react-refresh", type: "module", dangerouslySetInnerHTML: {
39
- __html: ` import RefreshRuntime from "/@react-refresh"
40
- RefreshRuntime.injectIntoGlobalHook(window)
41
- window.$RefreshReg$ = () => {}
42
- window.$RefreshSig$ = () => (type) => type
43
- window.__vite_plugin_react_preamble_installed__ = true`
31
+ __html: ssr_server_utils_1.reactRefreshFragment
44
32
  } }));
45
33
  }
46
34
  else {
@@ -57,11 +45,11 @@ const serverRender = async (ctx, config) => {
57
45
  } }));
58
46
  }
59
47
  const injectScript = [
60
- isVite && React.createElement("script", { key: "viteWindowInit", dangerouslySetInnerHTML: {
61
- __html: 'window.__USE_VITE__=true'
62
- } }),
63
- (isVite && isDev) && React.createElement("script", { type: "module", src: '/node_modules/ssr-plugin-react/esm/entry/client-entry.js', key: "vite-react-entry" }),
64
- ...dynamicJsOrder.map(js => manifest[js]).map(item => item && React.createElement("script", { key: item, src: item, type: isVite ? 'module' : '' }))
48
+ ...(isVite ? [React.createElement("script", { key: "viteWindowInit", dangerouslySetInnerHTML: {
49
+ __html: 'window.__USE_VITE__=true'
50
+ } })] : []),
51
+ ...((isVite && isDev) ? [React.createElement("script", { type: "module", src: '/node_modules/ssr-plugin-react/esm/entry/client-entry.js', key: "vite-react-entry" })] : []),
52
+ ...dynamicJsOrder.map(js => manifest[js]).filter(item => !!item).map(item => React.createElement("script", { key: item, src: item, type: isVite ? 'module' : '' }))
65
53
  ];
66
54
  const staticList = {
67
55
  injectCss,
@@ -90,11 +78,12 @@ const serverRender = async (ctx, config) => {
90
78
  }
91
79
  const combineData = isCsr ? null : Object.assign(state !== null && state !== void 0 ? state : {}, layoutFetchData !== null && layoutFetchData !== void 0 ? layoutFetchData : {}, fetchData !== null && fetchData !== void 0 ? fetchData : {});
92
80
  const injectState = isCsr ? null : React.createElement("script", { dangerouslySetInnerHTML: {
93
- __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(combineData)}; ${base && `window.prefix="${base}"`};${clientPrefix && `window.clientPrefix="${clientPrefix}"`}`
81
+ __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${(0, ssr_serialize_javascript_1.serialize)(combineData)}; window.prefix="${prefix}";${clientPrefix && `window.clientPrefix="${clientPrefix}"`}`
94
82
  } });
95
83
  return (React.createElement(react_router_dom_1.StaticRouter, { location: ctx.request.url },
96
84
  React.createElement(create_context_1.STORE_CONTEXT.Provider, { value: { state: combineData } },
97
- React.createElement(index_tsx_1.default, { ctx: ctx, config: config, staticList: staticList, injectState: injectState },
85
+ React.createElement(Layout, { ctx: ctx, config: config, staticList: staticList, injectState: injectState },
98
86
  React.createElement(Component, null)))));
99
87
  };
100
88
  exports.serverRender = serverRender;
89
+ //# sourceMappingURL=server-entry.js.map
package/cjs/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export declare function clientPlugin(): {
4
4
  build: () => Promise<void>;
5
5
  };
6
6
  export * from './tools/vite';
7
+ //# sourceMappingURL=index.d.ts.map
package/cjs/index.js CHANGED
@@ -44,3 +44,4 @@ function clientPlugin() {
44
44
  }
45
45
  exports.clientPlugin = clientPlugin;
46
46
  __exportStar(require("./tools/vite"), exports);
47
+ //# sourceMappingURL=index.js.map
@@ -4,3 +4,4 @@ declare const clientConfig: UserConfig;
4
4
  declare const viteStart: () => Promise<void>;
5
5
  declare const viteBuild: () => Promise<void>;
6
6
  export { viteBuild, viteStart, serverConfig, clientConfig };
7
+ //# sourceMappingURL=vite.d.ts.map
package/cjs/tools/vite.js CHANGED
@@ -97,3 +97,4 @@ const viteBuild = async () => {
97
97
  await (0, vite_1.build)({ ...serverConfig, mode: 'production' });
98
98
  };
99
99
  exports.viteBuild = viteBuild;
100
+ //# sourceMappingURL=vite.js.map
@@ -1,2 +1,3 @@
1
1
  export declare const webpackStart: () => Promise<void>;
2
2
  export declare const webpackBuild: () => Promise<void>;
3
+ //# sourceMappingURL=webpack.d.ts.map
@@ -20,3 +20,4 @@ const webpackBuild = async () => {
20
20
  await Promise.all([startServerBuild(getServerWebpack(serverConfigChain)), startClientBuild(getClientWebpack(clientConfigChain))]);
21
21
  };
22
22
  exports.webpackBuild = webpackBuild;
23
+ //# sourceMappingURL=webpack.js.map
@@ -1,3 +1,4 @@
1
1
  import * as WebpackChain from 'webpack-chain';
2
- declare const getBaseConfig: (chain: WebpackChain, isServer: boolean) => IConfig;
2
+ declare const getBaseConfig: (chain: WebpackChain, isServer: boolean) => import("ssr-types-react").IConfig;
3
3
  export { getBaseConfig };
4
+ //# sourceMappingURL=base.d.ts.map
@@ -4,9 +4,9 @@ import * as webpack from 'webpack';
4
4
  const MiniCssExtractPlugin = require(loadModuleFromFramework('mini-css-extract-plugin'));
5
5
  const WebpackBar = require('webpackbar');
6
6
  const loadModule = loadModuleFromFramework;
7
- const addBabelLoader = (chain, envOptions) => {
7
+ const addBabelLoader = (chain, envOptions, isServer) => {
8
8
  var _a, _b;
9
- const { babelOptions } = loadConfig();
9
+ const { babelOptions, isDev } = loadConfig();
10
10
  chain.use('babel-loader')
11
11
  .loader(loadModule('babel-loader'))
12
12
  .options({
@@ -38,7 +38,7 @@ const addBabelLoader = (chain, envOptions) => {
38
38
  [loadModule('@babel/plugin-proposal-private-methods'), { loose: true }],
39
39
  [loadModule('@babel/plugin-proposal-private-property-in-object'), { loose: true }],
40
40
  ...(_b = babelOptions === null || babelOptions === void 0 ? void 0 : babelOptions.plugins) !== null && _b !== void 0 ? _b : []
41
- ]
41
+ ].concat((!isServer && isDev) ? loadModule('react-refresh/babel') : [])
42
42
  })
43
43
  .end();
44
44
  };
@@ -95,8 +95,8 @@ const getBaseConfig = (chain, isServer) => {
95
95
  else {
96
96
  babelForExtraModule = module.end().exclude.add(/core-js/).end();
97
97
  }
98
- addBabelLoader(babelModule, envOptions);
99
- addBabelLoader(babelForExtraModule, envOptions);
98
+ addBabelLoader(babelModule, envOptions, isServer);
99
+ addBabelLoader(babelForExtraModule, envOptions, isServer);
100
100
  setStyle(chain, /\.css$/, {
101
101
  rule: 'css',
102
102
  isServer,
@@ -135,3 +135,4 @@ const getBaseConfig = (chain, isServer) => {
135
135
  return config;
136
136
  };
137
137
  export { getBaseConfig };
138
+ //# sourceMappingURL=base.js.map
@@ -2,3 +2,4 @@
2
2
  import * as WebpackChain from 'webpack-chain';
3
3
  declare const getClientWebpack: (chain: WebpackChain) => import("webpack").Configuration;
4
4
  export { getClientWebpack };
5
+ //# sourceMappingURL=client.d.ts.map
@@ -5,11 +5,12 @@ import { getBaseConfig } from './base';
5
5
  const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
6
6
  const safePostCssParser = require('postcss-safe-parser');
7
7
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
8
+ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
8
9
  const generateAnalysis = Boolean(process.env.GENERATE_ANALYSIS);
9
10
  const loadModule = loadModuleFromFramework;
10
11
  let asyncChunkMap = {};
11
12
  const getClientWebpack = (chain) => {
12
- const { isDev, chunkName, getOutput, cwd, useHash, chainClientConfig } = loadConfig();
13
+ const { isDev, chunkName, getOutput, cwd, useHash, chainClientConfig, host, fePort } = loadConfig();
13
14
  const shouldUseSourceMap = isDev || Boolean(process.env.GENERATE_SOURCEMAP);
14
15
  const publicPath = getOutputPublicPath();
15
16
  getBaseConfig(chain, false);
@@ -86,6 +87,14 @@ const getClientWebpack = (chain) => {
86
87
  chain.when(generateAnalysis, chain => {
87
88
  chain.plugin('analyze').use(BundleAnalyzerPlugin);
88
89
  });
90
+ chain.when(isDev, chain => {
91
+ chain.plugin('fast-refresh').use(new ReactRefreshWebpackPlugin({
92
+ overlay: {
93
+ sockHost: host,
94
+ sockPort: fePort
95
+ }
96
+ }));
97
+ });
89
98
  chain.plugin('WriteAsyncManifest').use(class WriteAsyncChunkManifest {
90
99
  apply(compiler) {
91
100
  compiler.hooks.watchRun.tap('thisCompilation', async () => {
@@ -102,3 +111,4 @@ const getClientWebpack = (chain) => {
102
111
  return chain.toConfig();
103
112
  };
104
113
  export { getClientWebpack };
114
+ //# sourceMappingURL=client.js.map
@@ -1,2 +1,3 @@
1
1
  export * from './client';
2
2
  export * from './server';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1,3 @@
1
1
  export * from './client';
2
2
  export * from './server';
3
+ //# sourceMappingURL=index.js.map
@@ -2,3 +2,4 @@ import * as WebpackChain from 'webpack-chain';
2
2
  import * as webpack from 'webpack';
3
3
  declare const getServerWebpack: (chain: WebpackChain) => webpack.Configuration;
4
4
  export { getServerWebpack };
5
+ //# sourceMappingURL=server.d.ts.map
@@ -32,3 +32,4 @@ const getServerWebpack = (chain) => {
32
32
  return chain.toConfig();
33
33
  };
34
34
  export { getServerWebpack };
35
+ //# sourceMappingURL=server.js.map
@@ -1,2 +1,3 @@
1
1
  declare const clientRender: () => Promise<void>;
2
2
  export { clientRender };
3
+ //# sourceMappingURL=client-entry.d.ts.map
@@ -5,14 +5,13 @@ import { preloadComponent } from 'ssr-client-utils';
5
5
  import { wrapComponent } from 'ssr-hoc-react';
6
6
  import { Routes } from './create-router';
7
7
  import { AppContext } from './context';
8
- const { FeRoutes, layoutFetch, App, PrefixRouterBase } = Routes;
8
+ const { FeRoutes, layoutFetch, App } = Routes;
9
9
  const clientRender = async () => {
10
- var _a, _b, _c, _d;
11
10
  const IApp = App !== null && App !== void 0 ? App : function (props) {
12
11
  return props.children;
13
12
  };
14
13
  // 客户端渲染||hydrate
15
- const baseName = (_b = (_a = (window.microApp && window.clientPrefix)) !== null && _a !== void 0 ? _a : window.prefix) !== null && _b !== void 0 ? _b : PrefixRouterBase;
14
+ const baseName = window.microApp ? window.clientPrefix : window.prefix;
16
15
  const routes = await preloadComponent(FeRoutes, baseName);
17
16
  ReactDOM[window.__USE_SSR__ ? 'hydrate' : 'render'](React.createElement(BrowserRouter, { basename: baseName },
18
17
  React.createElement(AppContext, null,
@@ -27,9 +26,6 @@ const clientRender = async () => {
27
26
  const WrappedComponent = wrapComponent(component);
28
27
  return (React.createElement(Route, { exact: true, key: path, path: path, render: () => React.createElement(WrappedComponent, { key: location.pathname }) }));
29
28
  })))))), document.getElementById('app'));
30
- if (!window.__USE_VITE__) {
31
- (_d = (_c = module === null || module === void 0 ? void 0 : module.hot) === null || _c === void 0 ? void 0 : _c.accept) === null || _d === void 0 ? void 0 : _d.call(_c); // webpack 场景下的 hmr
32
- }
33
29
  };
34
30
  if (!window.__disableClientRender__) {
35
31
  // 如果服务端直出的时候带上该记号,则默认不进行客户端渲染,将处理逻辑交给上层
@@ -37,3 +33,4 @@ if (!window.__disableClientRender__) {
37
33
  clientRender();
38
34
  }
39
35
  export { clientRender };
36
+ //# sourceMappingURL=client-entry.js.map
@@ -1,3 +1,4 @@
1
1
  /// <reference types="react" />
2
2
  import { IProps } from 'ssr-types-react';
3
3
  export declare function AppContext(props: IProps): JSX.Element;
4
+ //# sourceMappingURL=context.d.ts.map
@@ -25,3 +25,4 @@ export function AppContext(props) {
25
25
  const [state, dispatch] = useReducer(combineReducer, initialState);
26
26
  return (React.createElement(STORE_CONTEXT.Provider, { value: { state, dispatch } }, props.children));
27
27
  }
28
+ //# sourceMappingURL=context.js.map
@@ -2,3 +2,4 @@ import { Context } from 'react';
2
2
  import { IContext } from 'ssr-types-react';
3
3
  declare let STORE_CONTEXT: Context<IContext>;
4
4
  export { STORE_CONTEXT };
5
+ //# sourceMappingURL=create-context.d.ts.map
@@ -14,3 +14,4 @@ else {
14
14
  });
15
15
  }
16
16
  export { STORE_CONTEXT };
17
+ //# sourceMappingURL=create-context.js.map
@@ -1,3 +1,4 @@
1
1
  import { ReactRoutesType } from 'ssr-types-react';
2
2
  declare const Routes: ReactRoutesType;
3
3
  export { Routes };
4
+ //# sourceMappingURL=create-router.d.ts.map
@@ -21,3 +21,4 @@ if (ManualRoutesWithType.FeRoutes) {
21
21
  Routes.FeRoutes = combineRoutes;
22
22
  }
23
23
  export { Routes };
24
+ //# sourceMappingURL=create-router.js.map
@@ -2,3 +2,4 @@ import * as React from 'react';
2
2
  import { ISSRContext, IConfig } from 'ssr-types-react';
3
3
  declare const serverRender: (ctx: ISSRContext, config: IConfig) => Promise<React.ReactElement>;
4
4
  export { serverRender };
5
+ //# sourceMappingURL=server-entry.d.ts.map
@@ -1,23 +1,15 @@
1
1
  import * as React from 'react';
2
2
  import { StaticRouter } from 'react-router-dom';
3
- import { findRoute, getManifest, logGreen, normalizePath, getAsyncCssChunk, getAsyncJsChunk } from 'ssr-server-utils';
4
- // @ts-expect-error
5
- import * as serializeWrap from 'serialize-javascript';
3
+ import { findRoute, getManifest, logGreen, normalizePath, getAsyncCssChunk, getAsyncJsChunk, reactRefreshFragment } from 'ssr-server-utils';
4
+ import { serialize } from 'ssr-serialize-javascript';
6
5
  // @ts-expect-error
7
6
  import { STORE_CONTEXT as Context } from '_build/create-context';
8
- // @ts-expect-error
9
- import Layout from '@/components/layout/index.tsx';
10
7
  import { Routes } from './create-router';
11
- const { FeRoutes, layoutFetch, PrefixRouterBase, state } = Routes;
12
- const serialize = serializeWrap.default || serializeWrap;
8
+ const { FeRoutes, layoutFetch, state, Layout } = Routes;
13
9
  const serverRender = async (ctx, config) => {
14
10
  var _a;
15
11
  const { mode, parallelFetch, disableClientRender, prefix, isVite, isDev, clientPrefix } = config;
16
- let path = ctx.request.path; // 这里取 pathname 不能够包含 queryString
17
- const base = prefix !== null && prefix !== void 0 ? prefix : PrefixRouterBase; // 以开发者实际传入的为最高优先级
18
- if (base) {
19
- path = normalizePath(path, base);
20
- }
12
+ const path = normalizePath(ctx.request.path, prefix);
21
13
  const routeItem = findRoute(FeRoutes, path);
22
14
  if (!routeItem) {
23
15
  throw new Error(`
@@ -33,11 +25,7 @@ const serverRender = async (ctx, config) => {
33
25
  if (isVite && isDev) {
34
26
  injectCss.push(React.createElement("script", { src: "/@vite/client", type: "module", key: "vite-client" }));
35
27
  injectCss.push(React.createElement("script", { key: "vite-react-refresh", type: "module", dangerouslySetInnerHTML: {
36
- __html: ` import RefreshRuntime from "/@react-refresh"
37
- RefreshRuntime.injectIntoGlobalHook(window)
38
- window.$RefreshReg$ = () => {}
39
- window.$RefreshSig$ = () => (type) => type
40
- window.__vite_plugin_react_preamble_installed__ = true`
28
+ __html: reactRefreshFragment
41
29
  } }));
42
30
  }
43
31
  else {
@@ -54,11 +42,11 @@ const serverRender = async (ctx, config) => {
54
42
  } }));
55
43
  }
56
44
  const injectScript = [
57
- isVite && React.createElement("script", { key: "viteWindowInit", dangerouslySetInnerHTML: {
58
- __html: 'window.__USE_VITE__=true'
59
- } }),
60
- (isVite && isDev) && React.createElement("script", { type: "module", src: '/node_modules/ssr-plugin-react/esm/entry/client-entry.js', key: "vite-react-entry" }),
61
- ...dynamicJsOrder.map(js => manifest[js]).map(item => item && React.createElement("script", { key: item, src: item, type: isVite ? 'module' : '' }))
45
+ ...(isVite ? [React.createElement("script", { key: "viteWindowInit", dangerouslySetInnerHTML: {
46
+ __html: 'window.__USE_VITE__=true'
47
+ } })] : []),
48
+ ...((isVite && isDev) ? [React.createElement("script", { type: "module", src: '/node_modules/ssr-plugin-react/esm/entry/client-entry.js', key: "vite-react-entry" })] : []),
49
+ ...dynamicJsOrder.map(js => manifest[js]).filter(item => !!item).map(item => React.createElement("script", { key: item, src: item, type: isVite ? 'module' : '' }))
62
50
  ];
63
51
  const staticList = {
64
52
  injectCss,
@@ -87,7 +75,7 @@ const serverRender = async (ctx, config) => {
87
75
  }
88
76
  const combineData = isCsr ? null : Object.assign(state !== null && state !== void 0 ? state : {}, layoutFetchData !== null && layoutFetchData !== void 0 ? layoutFetchData : {}, fetchData !== null && fetchData !== void 0 ? fetchData : {});
89
77
  const injectState = isCsr ? null : React.createElement("script", { dangerouslySetInnerHTML: {
90
- __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(combineData)}; ${base && `window.prefix="${base}"`};${clientPrefix && `window.clientPrefix="${clientPrefix}"`}`
78
+ __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(combineData)}; window.prefix="${prefix}";${clientPrefix && `window.clientPrefix="${clientPrefix}"`}`
91
79
  } });
92
80
  return (React.createElement(StaticRouter, { location: ctx.request.url },
93
81
  React.createElement(Context.Provider, { value: { state: combineData } },
@@ -95,3 +83,4 @@ const serverRender = async (ctx, config) => {
95
83
  React.createElement(Component, null)))));
96
84
  };
97
85
  export { serverRender };
86
+ //# sourceMappingURL=server-entry.js.map
package/esm/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export declare function clientPlugin(): {
4
4
  build: () => Promise<void>;
5
5
  };
6
6
  export * from './tools/vite';
7
+ //# sourceMappingURL=index.d.ts.map
package/esm/index.js CHANGED
@@ -26,3 +26,4 @@ export function clientPlugin() {
26
26
  };
27
27
  }
28
28
  export * from './tools/vite';
29
+ //# sourceMappingURL=index.js.map
@@ -4,3 +4,4 @@ declare const clientConfig: UserConfig;
4
4
  declare const viteStart: () => Promise<void>;
5
5
  declare const viteBuild: () => Promise<void>;
6
6
  export { viteBuild, viteStart, serverConfig, clientConfig };
7
+ //# sourceMappingURL=vite.d.ts.map
package/esm/tools/vite.js CHANGED
@@ -91,3 +91,4 @@ const viteBuild = async () => {
91
91
  await build({ ...serverConfig, mode: 'production' });
92
92
  };
93
93
  export { viteBuild, viteStart, serverConfig, clientConfig };
94
+ //# sourceMappingURL=vite.js.map
@@ -1,2 +1,3 @@
1
1
  export declare const webpackStart: () => Promise<void>;
2
2
  export declare const webpackBuild: () => Promise<void>;
3
+ //# sourceMappingURL=webpack.d.ts.map
@@ -15,3 +15,4 @@ export const webpackBuild = async () => {
15
15
  const clientConfigChain = new WebpackChain();
16
16
  await Promise.all([startServerBuild(getServerWebpack(serverConfigChain)), startClientBuild(getClientWebpack(clientConfigChain))]);
17
17
  };
18
+ //# sourceMappingURL=webpack.js.map
package/package.json CHANGED
@@ -1,15 +1,13 @@
1
1
  {
2
2
  "name": "ssr-plugin-react",
3
- "version": "6.2.13",
3
+ "version": "6.2.16",
4
4
  "description": "plugin-react for ssr",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
7
7
  "sideEffects": false,
8
8
  "scripts": {
9
- "build": "concurrently \"tsc -p ./tsconfig.cjs.json --inlineSourceMap false\" \" tsc -p ./tsconfig.esm.json --inlineSourceMap false\"",
10
- "build:only": "concurrently \"tsc-transpile-only --skipLibCheck -p ./tsconfig.cjs.json --inlineSourceMap false\" \" tsc-transpile-only --skipLibCheck -p ./tsconfig.esm.json --inlineSourceMap false\"",
11
- "watch": "concurrently \"tsc -w -p ./tsconfig.cjs.json \" \"tsc -w -p ./tsconfig.esm.json \"",
12
- "watch:cjs": "tsc -w -p ./tsconfig.cjs.json"
9
+ "build": "concurrently \"tsc -p ./tsconfig.cjs.json \" \" tsc -p ./tsconfig.esm.json\"",
10
+ "watch": "concurrently \"tsc -w -p ./tsconfig.cjs.json \" \"tsc -w -p ./tsconfig.esm.json \""
13
11
  },
14
12
  "repository": {
15
13
  "type": "git",
@@ -34,6 +32,7 @@
34
32
  "@babel/plugin-proposal-optional-chaining": "^7.16.5",
35
33
  "@babel/plugin-transform-runtime": "^7.9.6",
36
34
  "@babel/preset-env": "^7.5.5",
35
+ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
37
36
  "@vitejs/plugin-react": "^1.0.0",
38
37
  "babel-loader": "^8.0.4",
39
38
  "babel-plugin-import": "1.13.3",
@@ -54,11 +53,12 @@
54
53
  "postcss-preset-env": "^7.0.0",
55
54
  "postcss-safe-parser": "^6.0.0",
56
55
  "react": "^17.0.1",
56
+ "react-dev-utils": "^11.0.4",
57
57
  "react-dom": "^17.0.0",
58
+ "react-refresh": "^0.12.0",
58
59
  "react-router": "^5.2.1",
59
60
  "react-router-dom": "^5.1.2",
60
- "react-dev-utils": "^11.0.4",
61
- "serialize-javascript": "^6.0.0",
61
+ "ssr-serialize-javascript": "^6.0.0",
62
62
  "ssr-client-utils": "^6.2.7",
63
63
  "ssr-hoc-react": "^6.2.7",
64
64
  "ssr-server-utils": "^6.2.10",
@@ -79,7 +79,6 @@
79
79
  "@types/react-router-dom": "^5.1.3",
80
80
  "@types/webpack": "^4.41.10",
81
81
  "concurrently": "^5.1.0",
82
- "ssr-types": "^6.2.3",
83
82
  "ssr-types-react": "^6.2.7"
84
83
  }
85
84
  }
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { join } from 'path'
3
- import { Mode } from 'ssr-types'
3
+ import { Mode } from 'ssr-types-react'
4
4
  import { getCwd, loadConfig, getLocalNodeModules, setStyle, addImageChain, loadModuleFromFramework } from 'ssr-server-utils'
5
5
  import * as WebpackChain from 'webpack-chain'
6
6
  import * as webpack from 'webpack'
@@ -9,8 +9,8 @@ const MiniCssExtractPlugin = require(loadModuleFromFramework('mini-css-extract-p
9
9
  const WebpackBar = require('webpackbar')
10
10
  const loadModule = loadModuleFromFramework
11
11
 
12
- const addBabelLoader = (chain: WebpackChain.Rule<WebpackChain.Module>, envOptions: any) => {
13
- const { babelOptions } = loadConfig()
12
+ const addBabelLoader = (chain: WebpackChain.Rule<WebpackChain.Module>, envOptions: any, isServer: boolean) => {
13
+ const { babelOptions, isDev } = loadConfig()
14
14
  chain.use('babel-loader')
15
15
  .loader(loadModule('babel-loader'))
16
16
  .options({
@@ -42,7 +42,7 @@ const addBabelLoader = (chain: WebpackChain.Rule<WebpackChain.Module>, envOption
42
42
  [loadModule('@babel/plugin-proposal-private-methods'), { loose: true }],
43
43
  [loadModule('@babel/plugin-proposal-private-property-in-object'), { loose: true }],
44
44
  ...babelOptions?.plugins ?? []
45
- ]
45
+ ].concat((!isServer && isDev) ? loadModule('react-refresh/babel') : [])
46
46
  })
47
47
  .end()
48
48
  }
@@ -106,8 +106,8 @@ const getBaseConfig = (chain: WebpackChain, isServer: boolean) => {
106
106
  babelForExtraModule = module.end().exclude.add(/core-js/).end()
107
107
  }
108
108
 
109
- addBabelLoader(babelModule, envOptions)
110
- addBabelLoader(babelForExtraModule, envOptions)
109
+ addBabelLoader(babelModule, envOptions, isServer)
110
+ addBabelLoader(babelForExtraModule, envOptions, isServer)
111
111
 
112
112
  setStyle(chain, /\.css$/, {
113
113
  rule: 'css',
@@ -7,12 +7,13 @@ import { getBaseConfig } from './base'
7
7
  const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin')
8
8
  const safePostCssParser = require('postcss-safe-parser')
9
9
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
10
+ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
10
11
  const generateAnalysis = Boolean(process.env.GENERATE_ANALYSIS)
11
12
  const loadModule = loadModuleFromFramework
12
13
  let asyncChunkMap: Record<string, string[]> = {}
13
14
 
14
15
  const getClientWebpack = (chain: WebpackChain) => {
15
- const { isDev, chunkName, getOutput, cwd, useHash, chainClientConfig } = loadConfig()
16
+ const { isDev, chunkName, getOutput, cwd, useHash, chainClientConfig, host, fePort } = loadConfig()
16
17
  const shouldUseSourceMap = isDev || Boolean(process.env.GENERATE_SOURCEMAP)
17
18
  const publicPath = getOutputPublicPath()
18
19
  getBaseConfig(chain, false)
@@ -92,6 +93,15 @@ const getClientWebpack = (chain: WebpackChain) => {
92
93
  chain.when(generateAnalysis, chain => {
93
94
  chain.plugin('analyze').use(BundleAnalyzerPlugin)
94
95
  })
96
+ chain.when(isDev, chain => {
97
+ chain.plugin('fast-refresh').use(new ReactRefreshWebpackPlugin({
98
+ overlay: {
99
+ sockHost: host,
100
+ sockPort: fePort
101
+ }
102
+ }))
103
+ })
104
+
95
105
  chain.plugin('WriteAsyncManifest').use(
96
106
  class WriteAsyncChunkManifest {
97
107
  apply (compiler: any) {
@@ -7,9 +7,8 @@ import { IWindow, LayoutProps, ReactRoutesType } from 'ssr-types-react'
7
7
  import { Routes } from './create-router'
8
8
  import { AppContext } from './context'
9
9
 
10
- const { FeRoutes, layoutFetch, App, PrefixRouterBase } = Routes as ReactRoutesType
10
+ const { FeRoutes, layoutFetch, App } = Routes as ReactRoutesType
11
11
 
12
- declare const module: any
13
12
  declare const window: IWindow
14
13
 
15
14
  const clientRender = async (): Promise<void> => {
@@ -17,7 +16,7 @@ const clientRender = async (): Promise<void> => {
17
16
  return props.children!
18
17
  }
19
18
  // 客户端渲染||hydrate
20
- const baseName = (window.microApp && window.clientPrefix) ?? window.prefix ?? PrefixRouterBase
19
+ const baseName = window.microApp ? window.clientPrefix : window.prefix
21
20
  const routes = await preloadComponent(FeRoutes, baseName)
22
21
  ReactDOM[window.__USE_SSR__ ? 'hydrate' : 'render'](
23
22
  <BrowserRouter basename={baseName}>
@@ -44,9 +43,6 @@ const clientRender = async (): Promise<void> => {
44
43
  </BrowserRouter>
45
44
  , document.getElementById('app'))
46
45
 
47
- if (!window.__USE_VITE__) {
48
- module?.hot?.accept?.() // webpack 场景下的 hmr
49
- }
50
46
  }
51
47
  if (!window.__disableClientRender__) {
52
48
  // 如果服务端直出的时候带上该记号,则默认不进行客户端渲染,将处理逻辑交给上层
@@ -1,25 +1,17 @@
1
1
  import * as React from 'react'
2
2
  import { StaticRouter } from 'react-router-dom'
3
- import { findRoute, getManifest, logGreen, normalizePath, getAsyncCssChunk, getAsyncJsChunk } from 'ssr-server-utils'
3
+ import { findRoute, getManifest, logGreen, normalizePath, getAsyncCssChunk, getAsyncJsChunk, reactRefreshFragment } from 'ssr-server-utils'
4
4
  import { ISSRContext, IConfig, ReactRoutesType, ReactESMFeRouteItem } from 'ssr-types-react'
5
- // @ts-expect-error
6
- import * as serializeWrap from 'serialize-javascript'
5
+ import { serialize } from 'ssr-serialize-javascript'
7
6
  // @ts-expect-error
8
7
  import { STORE_CONTEXT as Context } from '_build/create-context'
9
- // @ts-expect-error
10
- import Layout from '@/components/layout/index.tsx'
11
8
  import { Routes } from './create-router'
12
9
 
13
- const { FeRoutes, layoutFetch, PrefixRouterBase, state } = Routes as ReactRoutesType
14
- const serialize = serializeWrap.default || serializeWrap
10
+ const { FeRoutes, layoutFetch, state, Layout } = Routes as ReactRoutesType
15
11
 
16
12
  const serverRender = async (ctx: ISSRContext, config: IConfig): Promise<React.ReactElement> => {
17
13
  const { mode, parallelFetch, disableClientRender, prefix, isVite, isDev, clientPrefix } = config
18
- let path = ctx.request.path // 这里取 pathname 不能够包含 queryString
19
- const base = prefix ?? PrefixRouterBase // 以开发者实际传入的为最高优先级
20
- if (base) {
21
- path = normalizePath(path, base)
22
- }
14
+ const path = normalizePath(ctx.request.path, prefix)
23
15
  const routeItem = findRoute<ReactESMFeRouteItem>(FeRoutes, path)
24
16
 
25
17
  if (!routeItem) {
@@ -39,11 +31,7 @@ const serverRender = async (ctx: ISSRContext, config: IConfig): Promise<React.Re
39
31
  if (isVite && isDev) {
40
32
  injectCss.push(<script src="/@vite/client" type="module" key="vite-client"/>)
41
33
  injectCss.push(<script key="vite-react-refresh" type="module" dangerouslySetInnerHTML={{
42
- __html: ` import RefreshRuntime from "/@react-refresh"
43
- RefreshRuntime.injectIntoGlobalHook(window)
44
- window.$RefreshReg$ = () => {}
45
- window.$RefreshSig$ = () => (type) => type
46
- window.__vite_plugin_react_preamble_installed__ = true`
34
+ __html: reactRefreshFragment
47
35
  }} />)
48
36
  } else {
49
37
  dynamicCssOrder.forEach(css => {
@@ -61,11 +49,11 @@ const serverRender = async (ctx: ISSRContext, config: IConfig): Promise<React.Re
61
49
  }
62
50
 
63
51
  const injectScript = [
64
- isVite && <script key="viteWindowInit" dangerouslySetInnerHTML={{
52
+ ...(isVite ? [<script key="viteWindowInit" dangerouslySetInnerHTML={{
65
53
  __html: 'window.__USE_VITE__=true'
66
- }} />,
67
- (isVite && isDev) && <script type="module" src='/node_modules/ssr-plugin-react/esm/entry/client-entry.js' key="vite-react-entry" />,
68
- ...dynamicJsOrder.map(js => manifest[js]).map(item => item && <script key={item} src={item} type={isVite ? 'module' : ''}/>)
54
+ }} />] : []),
55
+ ...((isVite && isDev) ? [<script type="module" src='/node_modules/ssr-plugin-react/esm/entry/client-entry.js' key="vite-react-entry" />] : []),
56
+ ...dynamicJsOrder.map(js => manifest[js]).filter(item => !!item).map(item => <script key={item} src={item} type={isVite ? 'module' : ''}/>)
69
57
  ]
70
58
  const staticList = {
71
59
  injectCss,
@@ -96,7 +84,7 @@ const serverRender = async (ctx: ISSRContext, config: IConfig): Promise<React.Re
96
84
  }
97
85
  const combineData = isCsr ? null : Object.assign(state ?? {}, layoutFetchData ?? {}, fetchData ?? {})
98
86
  const injectState = isCsr ? null : <script dangerouslySetInnerHTML={{
99
- __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(combineData)}; ${base && `window.prefix="${base}"`};${clientPrefix && `window.clientPrefix="${clientPrefix}"`}`
87
+ __html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(combineData)}; window.prefix="${prefix}";${clientPrefix && `window.clientPrefix="${clientPrefix}"`}`
100
88
  }} />
101
89
 
102
90
  return (