前一篇主要記錄了一下SSR配置以及結合Redux的使用。愛掏網 - it200.com這里簡單說一下React SSR中樣式處理和更優雅的SEO
SSR樣式
在React客戶端渲染,添加樣式很容易。愛掏網 - it200.com寫一個css樣式文件,在對應組件中引用。愛掏網 - it200.com標簽上通過className這個屬性調用對應樣式就萬事Ok了。愛掏網 - it200.com當然我們需要在webpack中配置loader來解析css文件。愛掏網 - it200.com一般的配置如下(使用css modules):
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標簽中。愛掏網 - it200.com
那么SSR也這樣行嗎~
yarn dev
跑一下服務,發現命令行報這個錯誤:
return window && document && document.all && !window.atob; ^ ReferenceError: window is not defined
原因在于服務器端渲染哪里有window對象,哪里有DOM啊。愛掏網 - it200.com我們是通過虛擬DOM。愛掏網 - it200.comrenderToString
這個方法生成出來的html字符串。愛掏網 - it200.comstackoverflow
搜了一下發現了isomorphic-style-loader這個專門用于同構的style-loader。愛掏網 - it200.com
話不多少搞起來。愛掏網 - it200.com客戶端的webpack配置不需要變更還是使用css-loader+style-loader。愛掏網 - it200.com服務器端就使用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一下,不報錯了但是會閃一下屏。愛掏網 - it200.com禁用掉js發現server端生成的html并沒有樣式,當客戶端JS接管程序之后才會有樣式出現。愛掏網 - it200.com這樣的體驗相當糟糕。愛掏網 - it200.com
當然我們確實沒有向服務器端生成的HTML添加style標簽。愛掏網 - it200.com
現在服務器返給我們的html是這樣的
return `ssr ${ content }
這時我們想到了context這個玩意。愛掏網 - it200.com在server端render之前。愛掏網 - it200.com我們設置一個
let context = { css: [] }
我們還知道在服務端渲染的時候有this.props.staticContext這樣一個props拿到我們設置context。愛掏網 - it200.com另外isomorphic-style-loader提供給我們了
_getCss()這個方法。愛掏網 - it200.com可以在SSR過程中拿到樣式。愛掏網 - it200.com有了這兩個必要條件。愛掏網 - it200.com我們就可以在每一個用到樣式的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 `ssr ${content}
萬事