React SSR樣式及SEO的實踐
前一篇主要記錄了一下SSR配置以及結(jié)合Redux的使用。這里簡單說一下React SSR中樣式處理和更優(yōu)雅的SEO
SSR樣式
在React客戶端渲染,添加樣式很容易。寫一個css樣式文件,在對應(yīng)組件中引用。標(biāo)簽上通過className這個屬性調(diào)用對應(yīng)樣式就萬事Ok了。當(dāng)然我們需要在webpack中配置loader來解析css文件。一般的配置如下(使用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標(biāo)簽中。
那么SSR也這樣行嗎~
yarn dev
跑一下服務(wù),發(fā)現(xiàn)命令行報這個錯誤:
return window && document && document.all && !window.atob;
^ReferenceError: window is not defined
原因在于服務(wù)器端渲染哪里有window對象,哪里有DOM啊。我們是通過虛擬DOM。renderToString這個方法生成出來的html字符串。stackoverflow搜了一下發(fā)現(xiàn)了isomorphic-style-loader這個專門用于同構(gòu)的style-loader。
話不多少搞起來。客戶端的webpack配置不需要變更還是使用css-loader+style-loader。服務(wù)器端就使用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發(fā)現(xiàn)server端生成的html并沒有樣式,當(dāng)客戶端JS接管程序之后才會有樣式出現(xiàn)。這樣的體驗相當(dāng)糟糕。
當(dāng)然我們確實沒有向服務(wù)器端生成的HTML添加style標(biāo)簽。
現(xiàn)在服務(wù)器返給我們的html是這樣的
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之前。我們設(shè)置一個
let context = {
css: []
}
我們還知道在服務(wù)端渲染的時候有this.props.staticContext這樣一個props拿到我們設(shè)置context。另外isomorphic-style-loader提供給我們了
_getCss()這個方法。可以在SSR過程中拿到樣式。有了這兩個必要條件。我們就可以在每一個用到樣式的Component中通過componentWillMount這個生命周期
添加這樣一段代碼:
componentWillMount () {
if (this.props.staticContext) { // 只有服務(wù)端渲染時候有this.props.staticContext以及_getCss()
this.props.staticContext.css.push(styles._getCss())
}
}
這樣樣式就存儲在context這個變量的css數(shù)組中咯,改造一下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>
`
萬事👌,當(dāng)然我們可以進一步優(yōu)化,把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包裹一下就好。例如一個結(jié)合Redux的Home組件:
export default connect(mapState, mapDispatch)(withStyle(Home, styles))

SSR-SEO
費大力氣通過一個node中間層去實現(xiàn)首屏的SSR,除開首屏速度之外,就是SEO這一大塊了,對于一個商業(yè)網(wǎng)站來講真的很重要。
SEO(Search Engine Optimization)– 通過一些技術(shù)手段讓網(wǎng)站在搜索引擎的排名盡量靠前一點。由于客戶端渲染出來的網(wǎng)站只有<div id='root'>這樣的html節(jié)點。大多數(shù)搜索引擎分析不出來網(wǎng)站上有什么。SSR直接渲染出來HTML,這樣對搜索引擎就友好了很多。
SSR中的SEO
這里我們使用github上的一個庫react-helmet首先需要在對應(yīng)的頁面組件中引入react-helmet,就可以在Helmet標(biāo)簽內(nèi)自由添加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.title.toString()} ${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>
重新跑一下 搞定!
當(dāng)然SSR-SEO絕不這么簡單。僅僅在頁面上添加head標(biāo)簽內(nèi)加上title 和meta標(biāo)簽影響是有限的。8102年的搜索爬蟲已經(jīng)不單單去匹配title和 description,而是全穩(wěn)的匹配(也就是說title和descript有影響但是影響很小)搜索爬蟲會把整個網(wǎng)站所有的文本收集起來進行分析。
那么如何做好SEO
題外話順便說一下如何做好SEO。一個網(wǎng)站無非三大塊內(nèi)容,文字、多媒體、鏈接。要做到的是文字的原創(chuàng)性,圖片的原創(chuàng)性以及高清度還有站內(nèi)鏈接盡量和站內(nèi)內(nèi)容相關(guān)。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ReactNative?狀態(tài)管理redux使用詳解
這篇文章主要介紹了ReactNative?狀態(tài)管理redux使用詳解2023-03-03
使用React Native創(chuàng)建以太坊錢包實現(xiàn)轉(zhuǎn)賬等功能
這篇文章主要介紹了使用React Native創(chuàng)建以太坊錢包,實現(xiàn)轉(zhuǎn)賬等功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07
react?component?function組件使用詳解
這篇文章主要為大家介紹了react?component?function組件的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
React網(wǎng)絡(luò)請求發(fā)起方法詳細(xì)介紹
在編程開發(fā)中,網(wǎng)絡(luò)數(shù)據(jù)請求是必不可少的,這篇文章主要介紹了React網(wǎng)絡(luò)請求發(fā)起方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09

