前段時間一直在研究react ssr 技術,也很想本身寫一個 ssr開發骨架,有了本身的骨架後就不須要在用 ejs 模板了,直接用 jsx 就能夠了,技術棧也就統一了,那真的很爽。html
基於我以前瞭解的一點點ssr 原理就直開幹,在實現的過程當中的坑還真很多,可是也沒有什麼太可貴東西,主要是我採用的是 react router5 ,對這個新版的路由使用不太熟悉,又和 react router3的差異較大,致使耗費的時間多了點。另一個就是動態路由(路由分包)的處理,這個須要在 node 端和瀏覽器端都須要作處理,才能保證最終渲染的節點對比正確,否則會致使瀏覽器端會從新渲染。另一個就是要本身實現工程化,這個也是比較繁瑣的。前端
其餘的就是數據脫水注水,組件查找,以及一些基礎能力的支持(方便使用者開發)。node
從開始想作到如今開發完,都是在不忙的時候寫寫,差很少過去了2個月了。如今這個 ssr 骨架基本完成,我也寫了一個 demo能夠看看。react
這個 ssr 開發骨架是基於 koa2 、react1六、webpack四、babel7,因此我把這個項目命名爲 krs。webpack
krs幾個特性介紹git
最清涼(輕量)的 react ssr 應用開發骨架github
如何讓krs 在你的機器上快速的跑起來?web
在這裏我提供了一個腳手架,方便你快速建立項目,並進入開發。npm
//建立項目 $ 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> //結束
若是你想配置一個頁面的路由地址,那該如何配置呢?api
爲了方便維護和擴展,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內進行配置
http://demo.krs.bigerfe.com 最好在 pc 上訪問
更多使用幫助和實現原理後續文章會發出,同時也會在 github 更新。
krs 作到了如今,基本的功能已完成,可是仍然可能存在一些問題和待改善的空間,因此我會長期的進行維護和更新這個項目。
看到的小夥伴若是有興趣能夠幫助一塊兒改進,提建議。
項目 github 地址:
https://github.com/Bigerfe/ko...
更多精彩內容歡迎關注個人公衆號-前端張大胖*