前一篇主要記錄了一下SSR配置以及結合Redux的使用。這裏簡單說一下React SSR中樣式處理和更優雅的SEOcss
SSR樣式
在React客戶端渲染,添加樣式很容易。寫一個css樣式文件,在對應組件中引用。標籤上經過className這個屬性調用對應樣式就萬事Ok了。固然咱們須要在webpack中配置loader來解析css文件。通常的配置以下(使用css modules):html
module: { rules: [{ test: /\.css?$/, use: ['style-loader', { loader: 'css-loader', options: { importLoader: 1, modules: true, localIdentName: '[name]_[local]_[hash:base64:5]' } }] }] }
須要先經過css-loader解析css文件,以後再經過style-loader將樣式放在html的style標籤中。node
那麼SSR也這樣行嗎~react
yarn dev
跑一下服務,發現命令行報這個錯誤:webpack
return window && document && document.all && !window.atob; ^ ReferenceError: window is not defined
緣由在於服務器端渲染哪裏有window對象,哪裏有DOM啊。咱們是經過虛擬DOM。renderToString
這個方法生成出來的html字符串。stackoverflow
搜了一下發現了isomorphic-style-loader這個專門用於同構的style-loader。git
話很少少搞起來。客戶端的webpack配置不須要變動仍是使用css-loader+style-loader。服務器端就使用css-loader+isomorphic-style-loader了(和style-loader用法一波同樣)程序員
// webpack.server.js module: { rules: [{ test: /\.css?$/, use: ['isomorphic-style-loader', { loader: 'css-loader', options: { importLoader: 1, modules: true, localIdentName: '[name]_[local]_[hash:base64:5]' } }] }] }
配置好了Run一下,不報錯了可是會閃一下屏。禁用掉js發現server端生成的html並無樣式,當客戶端JS接管程序以後纔會有樣式出現。這樣的體驗至關糟糕。
固然咱們確實沒有向服務器端生成的HTML添加style標籤。
如今服務器返給咱們的html是這樣的github
return ` <html> <head> <title>ssr</title> </head> <body> <div id='root' >${ content }</div> <script> window.context = { state: ${ JSON.stringify(store.getState()) } } </script> <script src='/index.js' ></script> </body> </html>
這時咱們想到了context這個玩意。在server端render以前。咱們設置一個web
let context = { css: [] }
咱們還知道在服務端渲染的時候有this.props.staticContext這樣一個props拿到咱們設置context。另外isomorphic-style-loader提供給咱們了
_getCss()這個方法。能夠在SSR過程當中拿到樣式。有了這兩個必要條件。咱們就能夠在每個用到樣式的Component中經過componentWillMount這個生命週期
添加這樣一段代碼:數組
componentWillMount () { if (this.props.staticContext) { // 只有服務端渲染時候有this.props.staticContext以及_getCss() this.props.staticContext.css.push(styles._getCss()) } }
這樣樣式就存儲在context這個變量的css數組中咯,改造一下server端的html輸出代碼:
const cssStr = context.css.length ? context.css.join('\n') : '' return ` <html> <head> <title>ssr</title> <style>${cssStr}</style> </head> <body> <div id='root' >${content}</div> <script> window.context = { state: ${JSON.stringify(store.getState())} } </script> <script src='/index.js' ></script> </body> </html>
萬事👌,固然咱們能夠進一步優化,把componentWillMount所作的事情提出來搞一個HOC(高階組件)。
withStylesHOC.js
import React, { Component } from 'react' export default (DecoratedComponent, styles) => { return class NewComponent extends Component { componentWillMount () { if (this.props.staticContext) { this.props.staticContext.css.push(styles._getCss()) } } render () { return <DecoratedComponent {...this.props} /> } } }
這樣簡單的封裝一個HOC,以後涉及樣式的時候直接經過withStylesHOC包裹一下就好。例如一個結合Redux的Home組件:
export default connect(mapState, mapDispatch)(withStyle(Home, styles))
SSR-SEO
費大力氣經過一個node中間層去實現首屏的SSR,除開首屏速度以外,就是SEO這一大塊了,對於一個商業網站來說真的很重要。
SEO(Search Engine Optimization)– 經過一些技術手段讓網站在搜索引擎的排名儘可能靠前一點。因爲客戶端渲染出來的網站只有<div id='root'>這樣的html節點。大多數搜索引擎分析不出來網站上有什麼。SSR直接渲染出來HTML,這樣對搜索引擎就友好了不少。
SSR中的SEO
這裏咱們使用github上的一個庫react-helmet首先須要在對應的頁面組件中引入react-helmet,就能夠在Helmet標籤內自由添加title、meta咯
// Home.jax import { Helmet } from 'react-helmet' class Home extends Component { render() { return ( <Fragment> <Helmet> <title>SRR-Home</title> <meta name='description' content='this is a home Component' /> </Helmet> ... ... </<Fragment>> ) } }
以後按照readme所說的。在server端這樣處理
ReactDOMServer.renderToString(<Handler />); const helmet = Helmet.renderStatic();
並在返回的html字符串中 {helmet.meta.toString()}進行填充
<html> <head> ${helmet.title.toString()} ${helmet.meta.toString()} <style>${cssStr}</style> </head> <body> <div id='root' >${content}</div> <script> window.context = { state: ${JSON.stringify(store.getState())} } </script> <script src='/index.js' ></script> </body> </html>
從新跑一下 搞定!
固然SSR-SEO毫不這麼簡單。僅僅在頁面上添加head標籤內加上title 和meta標籤影響是有限的。8102年的搜索爬蟲已經不僅僅去匹配title和 description,而是全穩的匹配(也就是說title和descript有影響可是影響很小)搜索爬蟲會把整個網站全部的文本收集起來進行分析。
那麼如何作好SEO
題外話順便說一下如何作好SEO。一個網站無非三大塊內容,文字、多媒體、連接。要作到的是文字的原創性,圖片的原創性以及高清度還有站內連接儘可能和站內內容相關。
爲了學習工做與休閒娛樂互不衝突,現新建圈【碼農茶水鋪】用於程序員生活,愛好,交友,求職招聘,吐槽等話題交流,但願各位大神工做之餘到茶水鋪來喝茶聊天。瞭解更多