简体
注 :出 于功能 丰富度 以及可 维护性 考 虑,不 再建 议使用 egg-react-ssr
。现推荐使用 最新 的 ssr
框 架 能 够同时支持 在 React, Vue2/3 场景下 使用 且支持 使用 Vite。我 们强烈 建 议你使用 新 的 升 级版,无论是 渲染机 制 还是功 能 丰富度 以及可 维护性 上 都 有 极大提 升 并经过多个大型 线上项目验证。如果你更喜 欢开箱 即 用 的 体 验且希望 借 助 Serverless能力 一键部署应用或使用 Vue2/Vue3来 做服务端渲染。项目链接 https://github.com/zhangyuang/ssr官 方 文 档 http://doc.ssr-fc.com/我 们将会 持 续更新 维护它
小 :实现方式 简洁,生 产环境 构建出来 的 bundle 为同等 复杂度 的 next.js 项目的 0.7倍 ,生 成文 件数 量 相 比 于 next.js 减少非常 多 全 :支持 HMR,支持 本地 开发以及生 产环境 CSR/SSR 两种渲染模 式 无缝切 换,支持 定 制 组件的 渲染模 式 ,同 时支持 TypeScript版本 美 :基 于React和 Eggjs框 架 ,拥有强大 的 插件生 态,配置 非 黑 盒,方便 加入 当 前 业务的 个性化 逻辑
优酷视频 |
Vmate |
腾讯 |
||||
腾讯 |
极速 |
100 |
(js|ts|antd|dva)
$ npm init ssr-app my-ssr-project --template=ssr-with-js
$ cd my-ssr-project
$ npm install
$ npm start
npm init ssr-app my-ssr-project -- --template=ssr-with-js
1)启动
启动监听 7001
$ npm start # 建 议以本 方式 启动应用,同 时启动服务端渲染 + 客 户端hydrate
2)
$ npm run ssr
3)启动
仅限于本
$ npm run csr
4)
$ npm run prod # 使用 egg-scripts模 拟SSR应用生 产环境 ,如无特殊 定 制 要求 生 产环境 可 以用该方式 启动
$ npm run build # 打 包 服 务端以及客 户端资源文 件
$ npm run analyze # 可 视化分析 客 户端打 包 的 资源详情
该模
-
基 于 cra脚 手 架 开发,由 cra 开发的 React App可 无缝迁移,如果你熟悉 cra的 配置 ,上手 成本 几乎为 0 -
小 而美,相 比 于 beidou,next.js 这样的 高度 封 装 方案 ,我 们的实现原理 和 开发模 式 一 目 了 然 - 推荐
使用 egg作 为 Node.js框 架 但 并不强制 ,事 实上你可以发现几乎无需做任 何 修 改 即 可 迁移到 koa,nest.js等 框 架 -
同 时支持 SSR 以及 CSR 两种开发模 式 ,本地 开发环境以及线上环境皆 可 无缝切 换两种渲染 模 式 - 统一前端路由与服务端路由,无需
重 复编写 路 由 文 件 配置 -
支持 切 换路由 时自动获取数 据 -
支持 本地 开发 HMR - 稳定
性 经过线上大 规模应用验证,可 提供 性能 优化方案 -
支持 tree shaking,优化构建 bundle大小 以及数量 -
支持 csr/ssr自 定 义 layout,无需通 过 path来 手 动区分 -
抛 弃传统模版 引擎,拥抱 React 组件,使用 JSX来 作 为模版 -
配 套结合 antd的 example的 实现 -
配 套结合 react-loadable做路由 分割 的 example的 实现 -
配 套结合 dva做数据 管理 的 example的 实现 -
配 套结合 ssr-with-multipage多 页面应用的 example -
配 套结合 Rax版本 的 实现 -
配 套TypeScript版本 的 实现
function Page(props) {
return <div> {props.name} </div>
}
Page.getInitialProps = async (ctx) => {
return Promise.resolve({
name: 'Egg + React + SSR',
})
}
export default Page
- render
是 React的 视图渲染方法 - getInitialProps
是 获取数 据 方法 ,将 返 回 值赋值给组件状 态- csr
通 过高阶组件 实现 - ssr
通 过 Node 执行
- csr
config.type
getInitialProps
- ctx: Node 应用请求
的 上下 文 (仅在 SSR 阶段可 以获取) - Router Props:
包含 路 由 对象属性 ,包括 pathname 以及 Router params history等 对象,详细信 息 参考 react-router文 档
const commonNode = (props) =>
// 为了同 时兼容 ssr/csr请保留 此判断 ,如果你的layout没 有 内容 请使用 props.children ? { props.children } : ''
props.children ? (
<div className="normal">
<h1 className="title">
<Link to="/">Egg + React + SSR</Link>
<div className="author">by ykfe</div>
</h1>
{props.children}
</div>
) : (
''
)
const Layout = (props) => {
if (__isBrowser__) {
return commonNode(props)
} else {
const { serverData } = props.layoutData
const { injectCss, injectScript } = props.layoutData.app.config
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<title>React App</title>
{injectCss &&
injectCss.map((item) => (
<link rel="stylesheet" href={item} key={item} />
))}
</head>
<body>
<div id="app">{commonNode(props)}</div>
{serverData && (
<script
dangerouslySetInnerHTML={{
__html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(
serverData
)}`,
}}
/>
)}
<div
dangerouslySetInnerHTML={{
__html: injectScript && injectScript.join(''),
}}
/>
</body>
</html>
)
}
}
$ open http://localhost:7001/ # 以SSR模 式 渲染应用
$ open http://localhost:7001/?csr=true # 切 换为CSR模 式 渲染或 者 通 过config.type来 设置渲染模 式
服 务器 Node.js >= 7.6, 为了原生 的 使用 async/await 语法- 浏览
器 版本 大 于等于 IE9, React支持 到 IE9,但 为了更 好 的 在 IE下 使用 ,你可能 需要 引入Polyfill
为了
// config/config.ssr
const resolvePath = (path) => require('path').resolve(process.cwd(), path)
module.exports = {
type: 'ssr', // 指定 运行类型可 设置为csr切 换为客 户端渲染,此时服 务端不 会 做获取数 据 生成 字 符 串 的 操作 以及不 会 使用 hydrate API
static: {
// 设置Node应用的 静 态资源 目 录,为了生 产环境 读取静 态资源 文 件
prefix: '/',
dir: resolvePath('dist')
},
routes: [
// 前 后 端 统一使用的路由配置文件,防止 重 复编写 相 同 的 路 由
{
path: '/', // 请求的 path
exact: true, // 是 否 精 确匹配
Component: () => (require('@/page/index').default), // 这里使用 一 个function包 裹为了 让它延 迟require, 否 则Node环境无法识别前 端 组件中 用 到 的 import关键字 会 报错
controller: 'page', // 需要 调用的 controller
handler: 'index' // 需要 调用的 controller中 具体 的 method
},
{
path: '/news/:id',
exact: true,
Component: () => (require('@/page/news').default),
controller: 'page',
handler: 'index'
}
],
injectCss: [
`/static/css/Page.chunk.css`
], // 客 户端需要 加 载的静 态样式 表
injectScript: [
`<script src='/static/js/runtime~Page.js'></script>`,
`<script src='/static/js/vendor.chunk.js'></script>`,
`<script src='/static/js/Page.chunk.js'></script>`
], // 客 户端需要 加 载的静 态资源 文 件 表
serverJs: resolvePath(`dist/Page.server.js`): string|function, // 打 包 后 的 server端 的 bundle文 件 路 径 支持 传入CDN地 址 , 接受 直接 传入require后 的 function
layout: resolvePath(`dist/Layout.server.js`): string|function // 打 包 后 的 server端 的 bundle文 件 路 径 支持 传入CDN地 址 , 接受 直接 传入require后 的 function
}
webpack-dev-server
// build/webpack.config.client.js
module.epxorts = {
devServer: {
// custom webpack-dev-server config
}
}
├── README.md
├── app # egg核心 目 录
│ ├── controller
│ ├── extend
│ ├── middleware
│ └── router.js # egg路 由 文 件 ,无特殊 需求不 需要 修 改 内容
├── app.js # egg 启动入口 文 件
├── build # webpack配置 目 录
│ ├── paths.js
│ ├── util.js
│ ├── webpack.config.base.js # 通用 的 webpack配置
│ ├── webpack.config.client.js # webpack客 户端打 包 配置
│ └── webpack.config.server.js # webpack服 务端打 包 配置
├── config # egg 配置 文 件 目 录
│ ├── config.daily.js
│ ├── config.default.js
│ ├── config.ssr.js
│ ├── config.local.js
│ ├── config.prod.js
│ ├── plugin.js
│ └── plugin.local.js
├── dist # build生成 静 态资源 文 件 目 录
│ ├── Page.server.js # 服 务端打 包 后 文 件 (即 打 包 后 的 serverRender方法 )
│ └── static # 前 端 打 包 后 静 态资源 目 录
└── web # 前 端 文 件 目 录
├── assets
│ └── common.less
├── entry.js # webpack打 包 入口 文 件 ,分 环境导出不同 配置
├── layout
│ ├── index.js # 页面布 局
│ └── index.less
└── page
├── index
└── news
请查
请查
Thanks goes to these wonderful people (emoji key):
LeonCheung 💻 |
💻 |
Xu Zhiyong 🐛 |
Menteceso 📖 |
jerryYu 💻 |
dydong 💻 |
snoy 📖 |
zhaoxingyue 📖 |
🐛 |
JohannLai 🐛 |
robert.xu 💻 |
zhushijie 💻 |
Cheng Zhongmin 🐛 |
This project follows the all-contributors specification. Contributions of any kind welcome!
如果你想
虽然