这个ssr 开发骨架有点帅

简介: 前段时间一直在研究react ssr 技术,也很想自己写一个 ssr开发骨架,有了自己的骨架后就不需要在用 ejs 模板了,直接用 jsx 就可以了,技术栈也就统一了,那真的很爽。

前段时间一直在研究react ssr 技术,也很想自己写一个 ssr开发骨架,有了自己的骨架后就不需要在用 ejs 模板了,直接用 jsx 就可以了,技术栈也就统一了,那真的很爽。


基于我之前了解的一点点ssr 原理就直开干,在实现的过程中的坑还真不少,但是也没有什么太难得东西,主要是我采用的是 react router5 ,对这个新版的路由使用不太熟悉,又和 react router3的差别较大,导致耗费的时间多了点。另外一个就是动态路由(路由分包)的处理,这个需要在 node 端和浏览器端都需要做处理,才能保证最终渲染的节点对比正确,不然会导致浏览器端会重新渲染。另外一个就是要自己实现工程化,这个也是比较繁琐的。

其他的就是数据脱水注水,组件查找,以及一些基础能力的支持(方便使用者开发)。


从开始想做到现在开发完,都是在不忙的时候写写,差不多过去了2个月了。现在这个 ssr 骨架基本完成,我也写了一个 demo可以看看。


krs - ssr 骨架介绍


这个 ssr 开发骨架是基于 koa2 、react16、webpack4、babel7,所以我把这个项目命名为 krs。


krs几个特性介绍

最清凉(轻量)的 react ssr 应用开发骨架

  • 上手快速: 都是你熟悉的事物,基于 koa2 react16 ssr 搭建
  • 双模式无缝切换: 支持SSR/CSR两种渲染模式,只需更改配置属性即可,也可以对组件设置按需渲染模式
  • 路由分治管理: 你写你的路由,我写我的路由,krs 自动合并,不再需要维护整个路由表
  • 路由动静结合: 支持组件的按需加载设置,A 路由动态吧,B 路由静态
  • 伪 pwa 支持: 访问过的路由中的 state 可按需设置本地缓存,页面二次访问可无接口请求
  • 开放: 代码完全开放,纯白盒,完全可以作为个人的 ssr 学习参考资源



快速开始


如何让krs 在你的机器上快速的跑起来?


在这里我提供了一个脚手架,方便你快速创建项目,并进入开发。


//创建项目$ npm install mmkrs-cli -g$ mmkrs -i ---> select project ---> <Your Project Name>$ cd <Your Project Name>$ npm i$ npm run dev //本地开发监听模式$ open http://<Your local ip>:8808
//快速创建页面$ cd <Your Project Name>$ mmkrs -i -----> select page ----> <Your  pageName>$ open http://<Your local ip>:8808/<Your  pageName>
//结束



路由配置


如果你想配置一个页面的路由地址,那该如何配置呢?

为了方便维护和扩展,krs 把路由进行了分治管理,每个页面的路由都是独立的,只需要单独的配置即可,避免了多人维护带来的冲突和一系列的问题。

  • 在src/pages 目录下创建一个页面目录 如:detail
  • 在 detail/内创建入口组件
  • 在 detail/config内创建 route.js 这就是当前页面的路由配置文件



ff51fadd1f6e381d9b70a4ae0955e7e9_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


import React from 'react';import BaseBundle from '../../../routes/route-base-bundle';
const LazyPageCom = (props) => (    <BaseBundle load={() => import(/*webpackChunkName:"chunk-detail"*/'../index')}>        {(CompIndex) => <CompIndex {...props} />}    </BaseBundle>);
export default [    {        path:'/detail',        component: LazyPageCom,        exact:true    },    {        path:'/detail/:id',        component: LazyPageCom    }]



你只需要修改 webpackChunkName 的名称和 export 导出的参数即可,当然也可以对当前页面配置多个路由,默认已经支持了路由按需,所以如果不需要的话可以直接指向原始组件即可。


数据预取

什么是数据预取?


csr 模式下我们的数据都是在浏览器端请求和渲染的,但是 ssr 模式需要在 node 端进行数据的获取和渲染,这个渲染是指生成 html 内容。这样浏览器端拿到 html 后,直接渲染html,就不再需要浏览器自己去请求数据了。


上一步已经创建了一个页面的入口组件和路由的配置,那页面入口组件也没什么奇怪的,和平时创建组件差不多。

  • 需要继承一个 krs 的基础组件,为我们封装了一些基础数据获取和存储功能

需要设置 static contextType = RootContext 为的是让组件可以获得全局的数据

  • 声明静态数据预取方法 static async getInitialProps,数据的获取就是从这个方法拿到的,这是一个同构方法 node 端和浏览器端都会调用
  • 设置 static async getInitialProps 的返回数据,返回数据有一个固定的格式,下面代码会说明
  • componentDidMount内是否需要做数据的更新,如果需要更新可以调用getInitialProps方法


import React,{useContext} from 'react';import { Link } from 'react-router-dom';import RootContext from '../../app/route-context';//自定义 contextimport KrsPageBase from '../../krs-base/common/components/krs-page-base';//基础组件 页面组件都需要继承import fetch from '../../common/fetch';//内置的 fech 模块
export default class Index extends KrsPageBase{
    constructor(props,context){        super(props,context);    }
    enableSpaDataCache=true;//开启 伪 pwa 数据缓存
    //得到 context 对象    static contextType = RootContext;
    //基础参数的带入    //opt={query:{},params:{}}      static async getInitialProps(krsOpt){//数据预取        
        if(__SERVER__){            //如果是服务端渲染的话  可以做的处理        }
       const fetch1= fetch.postForm('/fe_api/a', {            data: { a: 4000 }        });
       const fecth2= fetch.postForm('/fe_api/b', {            data: { c: 2000 }        });
        const resArr =await fetch.multipleFetch(fetch1, fecth2);               //返回数据固定格式  page 代表页面信息,支持 seo 的设置        //fetchData是接口返回的数据         return {            page:{                tdk: {                    title: 'ksr 框架',                    keyword: 'ssr react',                    description: '我是描述'                }            },            fetchData: resArr        }     }
    componentDidMount(){              //数据更新 参考       //this.isSSR 标识当前页面是否是 ssr 输出       //this.hasSpaCacheData标识是否有伪 pwa 的缓存数据
        if (!this.isSSR && !this.hasSpaCacheData){// 页面如果是客户端的需要重新获取数据            Index.getInitialProps(this.props.krsOpt).then(data=>{                this.setState({                    ...data                },()=>{                    document.title=this.state.page.tdk.title;                });            });        }    }
    render(){             const {page,fetchData}=this.state;//获得数据             //参考代码,需要对数据做边界容错处理
        return <div className="detailBox">                     <div>           {                    page && <div><span>title:{page.tdk.title}</span>                    <span>ky:{page.tdk.keyword}</span>                    </div>            }           </div>           {              res && res.data.map(item=>{                   return <div key={item.id}>{item.keyId}:{item.keyName}---{item.setContent}</div>               })           }        </div>    }}



快捷键

上面已经将两个非常重要的内容说完了。但是每次手动需要创建这么多文件夹和页面也是很浪费时间的。所以这里在脚手架工具里提供了一个快捷命令,方便我们创建页面,通过命令代替手动创建.

cd 项目目录mmkrs-cli -i --->select page ---> 输入 pagename


操作完后就可以看到你配置的页面路由已生效。

9a5732b1de6bd11af409a9adbe0fefb7_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

生产环境构建

npm run build

然后可以本地模拟查看:npm run build:start

生产环境部署

这个很简单,只需要运行 根目录的 app.js 即可

pm2 start app.js

更多自定义配置

更多的配置,比如静态资源的 cdn 路径配置,开发端口的配置,是否开启 ssr 等都可以在 /src/config/project-config.js内进行配置


目录
相关文章
|
SQL 关系型数据库 数据库
C/S系统快速开发框架(C#+Winform+SQL)
开发框架集成大量的通用开发包与工具实用类,提供丰富的例子,借助技术文档、网站资源、演示源码以及在线技术指导,用户能快速投入研发自己的项目, 适用开发:制造、服务、零售、商贸等行业的ERP、MRP、MES、CRM、MIS、HIS、POS数据管理应用系统。
8895 0
|
3月前
|
机器学习/深度学习 算法 机器人
10类可食用蘑菇检测4000张YOLO农业采摘数据集分享
本数据集含4000张YOLO格式标注图像,覆盖木耳、香菇、金针菇等10类可食用蘑菇,兼顾干鲜形态、色泽差异与品种变种,专为农业采摘、食品安全、智能厨房等场景的目标检测任务设计,支持YOLOv5/v8/v10等主流模型训练。
|
4月前
|
数据采集 人工智能 API
AI 智能体项目的费用
AI智能体项目费用结构迥异于传统开发:研发成本递减,而算力与运营成本持续攀升,核心在于工程化编排。费用分两块——前期研发(8万–100万+,依单任务/目标导向/多智能体分级)与动态运行(Tokens消耗、向量库、沙箱等)。避坑关键:少微调、重提示词+RAG,严控循环次数。
|
5月前
|
程序员 API
初级程序员必备的十大技能之规范编码与团队协作(一)
教程来源 http://tmywi.cn/ 本文探讨程序员从“我能写”到“我们一起写”的成长跃迁,聚焦编码规范、代码审查、文档编写、协作沟通与工程化工具实践,助力个体迈向专业、可信赖的团队成员。
|
12月前
|
缓存 资源调度 算法
《3D端游开放世界场景流式加载的资源调度优化实践》
本文聚焦灵墟纪元苍梧山脉场景流式加载问题,针对传统方案因预加载策略僵化、资源分块不合理等导致的“地形透明”“内存过载”等问题,提出五大优化方案:动态预加载半径+行为预测、自适应资源分块+优先级排序、内存冷热数据动态置换+池化复用、多核线程池调度+异步资源传输、纹理LOD渐进加载+Mipmap链动态生成。优化后,飞行时“地形透明”概率降至2%,内存稳定在5GB内,加载线程CPU耗时降5ms,纹理弹出率低于0.5%,各设备帧率稳定58-60帧,为开放世界场景加载优化提供可行路径。
696 9
|
人工智能 运维 安全
|
6月前
|
缓存 算法 Java
别再无效刷题了!2026校招笔试高频考点权重排序(附大厂内部评分标准)
刷题≠高分!2026校招笔试60分真相:80%时间花在仅占15%分值的低频考点上。本文独家揭秘阿里、腾讯等大厂笔试真实权重分布(高频考点占60%),拆解LRU缓存、字符串模拟、场景系统设计等必考题型,并曝光内部评分标准——正确性、代码规范、异常处理等维度缺一不可。高效备考,从聚焦刀刃开始。
|
12月前
|
数据采集 存储 监控
Python爬虫定时任务:自动化抓取豆瓣每日最新短评
Python爬虫定时任务:自动化抓取豆瓣每日最新短评
|
自然语言处理 数据可视化 Python
如何用通义灵码实现文本分析:以《红楼梦》人物出场统计为例
我们将分析一部红楼梦中关键角色出场次数前10位有哪些,并生成一个饼图。
948 23
|
SQL 缓存 Java
乐观锁
乐观锁是一种轻量级并发控制机制,假设数据通常不会被其他线程修改,因此在读取时不加锁,仅在更新时检查是否发生冲突。它通过版本号或CAS(Compare-and-Swap)实现,避免线程阻塞,提高并发性能,适用于读多写少的场景,如缓存、数据库更新等。相比悲观锁,乐观锁减少锁竞争,但频繁写冲突可能导致重试成本较高。
570 0

热门文章

最新文章