专栏首页前端技术江湖这个ssr 开发骨架有点帅

这个ssr 开发骨架有点帅

写在前面

前段时间一直在研究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 这就是当前页面的路由配置文件
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';//自定义 context
import 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

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

生产环境构建

npm run build

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

生产环境部署

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

pm2 start app.js

更多自定义配置

更多的配置,比如静态资源的 cdn 路径配置,开发端口的配置,是否开启 ssr 等

都可以在 /src/config/project-config.js内进行配置

Demo 演示(有点丑,别介意)

http://demo.krs.bigerfe.com 最好在 pc 上访问

更多使用帮助和实现原理后续文章会发出,同时也会在 github 更新。

krs 做到了现在,基本的功能已完成,但是仍然可能存在一些问题和待改善的空间,所以我会长期的进行维护和更新这个项目。

看到的小伙伴如果有兴趣可以帮助一起改进,提建议。

项目 github 地址:

https://github.com/Bigerfe/koa-react-ssr

本文分享自微信公众号 - 前端技术江湖(bigerfe),作者:张大胖

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 复习下 [1,2,3].map(parseInt)

    首先要理解下 map 这个函数,他会返回一个新的数组,结果是数组每个元素都会调用下传入 map 的这个函数而得到的返回值

    zz_jesse
  • React Router5 感性认知

    本文主要是了解下 react-router 新版本一些理念,为我们以后的开发注入一些感性认知。

    zz_jesse
  • 《大胖 • 小课》- 说说大文件分片和断点续传

    这是《大胖小课》栏目的专题一《说说文件上传那些事儿》的第6节-《大文件分片和断点续传》。

    zz_jesse
  • Angular 2 快速起步 原

    准备学习angularjs2,安装的过程费了不少时间,刚开始为了方便,从官网上下载了现成的包,但是就运行不起来,后来还是老老实实按教程一步步建文件,ng2详细地...

    tianyawhl
  • 自定义控件详解(二):Path类 相关用法

    听着music睡
  • ESA2GJK1DH1K基础篇: 测试APP扫描Air202上面的二维码绑定通过MQTT控制设备(兼容SIM800)

    一,该程序需要的基础知识:  https://www.cnblogs.com/yangfengwu/category/1566194.html   所有源码开源...

    杨奉武
  • Hyperf 初体验-路由

    @Controller 和 @AutoController 都提供了 prefix 和 server 两个参数。

    hedeqiang
  • 北漂你后悔了吗?“失败”的北漂十年经历,真的尽力了...

    在我离开北京的时候,我还依稀记得,十年前我对朋友说过的那句话:我一定要留在北京,因为那里有梦想。

    纯洁的微笑
  • angular4实战(2) router

    版权声明:本文为博主原创文章,未经博主允许不得转载。 ...

    j_bleach
  • Python开发基础-day2

        acclist.insert()  (要插入的位置,插入的内容)  list插入内容

    py3study

扫码关注云+社区

领取腾讯云代金券