typescript版的react服務端渲染

typescript-koa-ssr-react-boilerplate

項目地址:https://github.com/m-Ryan/typ...css

特點

  • 先後端分離
  • typeScript
  • 服務端渲染
  • react-router按需加載
  • redux
  • 使用最新的react v.16.4

服務端渲染實現

router.tsx 路由html

...
    function RouterConfig() {
        return (
            <Switch>
                <Route path="/" exact={true} component={Home} />
                <Route path="/about" component={About} />
                <Route path="/hello" component={Hello} />
            </Switch>
        );
    }

ssr.tsx 匹配路徑前端

...
export default (url: string | Object, context: any,store: any)=>{
   return  <Provider store={store}>
            <StaticRouter location={url} context={context}>
                <Routes/>
              </StaticRouter>
          </Provider>
}

renderFullPage.ts 渲染頁面react

...
const renderFullPage = (ctx : IRouterContext, newState:Object ) => {
    let context  = {}
    const myHtml = fs.readFileSync("app/web/assets/dist/templete.html", 'utf-8');
    // 獲得初始 state 建立新的 Redux store 實例
    const store = createStore(reducers, newState);
    // 從 Redux store 獲得初始 state,注入到window
    const finalState = store.getState()
    let initState = `<script> window.__INITIAL_STATE__ = ${JSON.stringify(finalState)}</script>`;
    //根據路由獲取html並注入到<div id="root"></div>,將 initState 插到該節點後面
    const html = ReactDOMServer.renderToString(ssr(ctx.req.url, context, store));
    let renderPage = myHtml.replace(/(\<div\s+id\="root"\>)(.|\n|\r)*(\<\/div\>)/i, "$1" + html + "$3" + initState);
    ctx.type = 'html';
    ctx.body = renderPage;
}

export default renderFullPage;

index.tsx 前端的路由處理webpack

...
const preloadedState =  window.__INITIAL_STATE__ || {} //
// 使用初始 state 建立 Redux store
const store = createStore(reducers, preloadedState)
render(
  <Provider  store={store}>
    <BrowserRouter>
        <Routes/>
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')  as HTMLElement
)

1..redux方面,先建立新的 Redux store 實例,將咱們須要初始的state合併到 store

2.經過 store.getState() 獲取最終的finalState

3.經過 StaticRouter 能夠獲取路徑匹配的頁面組件,並經過 ReactDOMServer.renderToString 轉化爲HTML元素

ssr.tsx 主要作了兩件事:
1.將初始的 store 注入redux
2.返回帶有 store 數據的路徑匹配的頁面組件,也就是說這個頁面已是有初始數據了git

4.將讀取的html模板注入數據,在這裏咱們須要經過簡單的正則替換一下

在 <div id="root"></div> 中插入咱們的html元素
在 <div id="root"></div> 後面插入 <script> window.__INITIAL_STATE__ = ${JSON.stringify(finalState)}</script>github

5.將這個頁面發送出去

6.js加載的時候會讀取 window.__INITIAL_STATE__ 的數據,合併到 store

注意:這裏 咱們是用 fs模塊 讀取 html模板,而不是直接使用 相似如下函數

export default (html, finalState)=>(
    `
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
        <meta name="renderer" content="webkit">
        <title>typeScript-koa-ssr-antd</title>
        <link href="/dist/index.076a9ad74b9f609c4d81.css" rel="stylesheet">
    </head>

    <body>
        <div id="root">${html}</div>
        window.__INITIAL_STATE__ = ${JSON.stringify(finalState)}</script>
    </body>
    </html>

    `
)

緣由主要是由於打包獲得的 js、css 須要有hash值來管理版本緩存,因此是不能直接寫死的


怎麼使用

git clone git@github.com:m-Ryan/typescript-koa-ssr-react-boilerplate.git
cd typescript-koa-ssr-react-boilerplate

前端

  • cd app/web 首次使用,先 npm install
  • 開發環境 npm start
  • 生產環境 npm run build

後臺(先後端是分離的,使用前,前端要先打包)

  • 首次使用,先 npm install
  • 開發環境 npm start
  • 生產環境 npm run build

考慮到先後端分離,這裏沒有使用 webpack-middleware

打算在以後的項目中使用,但目前還沒開始。不肯定有沒有bug,僅供參考

相關文章
相關標籤/搜索