经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » React » 查看文章
React SSR样式及SEO的实践
来源:jb51  时间:2018/10/24 9:33:21  对本文有异议

前一篇主要记录了一下SSR配置以及结合Redux的使用。这里简单说一下React SSR中样式处理和更优雅的SEO

SSR样式

在React客户端渲染,添加样式很容易。写一个css样式文件,在对应组件中引用。标签上通过className这个属性调用对应样式就万事Ok了。当然我们需要在webpack中配置loader来解析css文件。一般的配置如下(使用css modules):

  1. module: {
  2. rules: [{
  3. test: /\.css?$/,
  4. use: ['style-loader', {
  5. loader: 'css-loader',
  6. options: {
  7. importLoader: 1,
  8. modules: true,
  9. localIdentName: '[name]_[local]_[hash:base64:5]'
  10. }
  11. }]
  12. }]
  13. }

需要先通过css-loader解析css文件,之后再通过style-loader将样式放在html的style标签中。

那么SSR也这样行吗~

  1. yarn dev

跑一下服务,发现命令行报这个错误:

return window && document && document.all && !window.atob;
^

ReferenceError: window is not defined

原因在于服务器端渲染哪里有window对象,哪里有DOM啊。我们是通过虚拟DOM。renderToString这个方法生成出来的html字符串。stackoverflow搜了一下发现了isomorphic-style-loader这个专门用于同构的style-loader。

话不多少搞起来。客户端的webpack配置不需要变更还是使用css-loader+style-loader。服务器端就使用css-loader+isomorphic-style-loader了(和style-loader用法一波一样)

  1. // webpack.server.js
  2. module: {
  3. rules: [{
  4. test: /\.css?$/,
  5. use: ['isomorphic-style-loader', {
  6. loader: 'css-loader',
  7. options: {
  8. importLoader: 1,
  9. modules: true,
  10. localIdentName: '[name]_[local]_[hash:base64:5]'
  11. }
  12. }]
  13. }]
  14. }

配置好了Run一下,不报错了但是会闪一下屏。禁用掉js发现server端生成的html并没有样式,当客户端JS接管程序之后才会有样式出现。这样的体验相当糟糕。

当然我们确实没有向服务器端生成的HTML添加style标签。

现在服务器返给我们的html是这样的

  1. return `
  2. <html>
  3. <head>
  4. <title>ssr</title>
  5. </head>
  6. <body>
  7. <div id='root' >${ content }</div>
  8. <script>
  9. window.context = {
  10. state: ${ JSON.stringify(store.getState()) }
  11. }
  12. </script>
  13. <script src='/index.js' ></script>
  14. </body>
  15. </html>
  16. `

这时我们想到了context这个玩意。在server端render之前。我们设置一个

  1. let context = {
  2. css: []
  3. }

我们还知道在服务端渲染的时候有this.props.staticContext这样一个props拿到我们设置context。另外isomorphic-style-loader提供给我们了

_getCss()这个方法。可以在SSR过程中拿到样式。有了这两个必要条件。我们就可以在每一个用到样式的Component中通过componentWillMount这个生命周期

添加这样一段代码:

  1. componentWillMount () {
  2. if (this.props.staticContext) { // 只有服务端渲染时候有this.props.staticContext以及_getCss()
  3. this.props.staticContext.css.push(styles._getCss())
  4. }
  5. }

这样样式就存储在context这个变量的css数组中咯,改造一下server端的html输出代码:

  1. const cssStr = context.css.length ? context.css.join('\n') : ''
  2. return `
  3. <html>
  4. <head>
  5. <title>ssr</title>
  6. <style>${cssStr}</style>
  7. </head>
  8. <body>
  9. <div id='root' >${content}</div>
  10. <script>
  11. window.context = {
  12. state: ${JSON.stringify(store.getState())}
  13. }
  14. </script>
  15. <script src='/index.js' ></script>
  16. </body>
  17. </html>
  18. `

万事👌,当然我们可以进一步优化,把componentWillMount所做的事情提出来搞一个HOC(高阶组件)。

withStylesHOC.js

  1. import React, {
  2. Component
  3. } from 'react'
  4.  
  5. export default (DecoratedComponent, styles) => {
  6. return class NewComponent extends Component {
  7. componentWillMount () {
  8. if (this.props.staticContext) {
  9. this.props.staticContext.css.push(styles._getCss())
  10. }
  11. }
  12.  
  13. render () {
  14. return <DecoratedComponent {...this.props} />
  15. }
  16. }
  17. }
  18.  

这样简单的封装一个HOC,之后涉及样式的时候直接通过withStylesHOC包裹一下就好。例如一个结合Redux的Home组件:

  1. 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咯

  1. // Home.jax
  2. import { Helmet } from 'react-helmet'
  3. class Home extends Component {
  4. render() {
  5. return (
  6. <Fragment>
  7. <Helmet>
  8. <title>SRR-Home</title>
  9. <meta name='description' content='this is a home Component' />
  10. </Helmet>
  11. ...
  12. ...
  13. </<Fragment>>
  14. )
  15. }
  16. }

之后按照readme所说的。在server端这样处理

  1. ReactDOMServer.renderToString(<Handler />);
  2. const helmet = Helmet.renderStatic();

并在返回的html字符串中 ${helmet.title.toString()} ${helmet.meta.toString()}进行填充

  1. <html>
  2. <head>
  3. ${helmet.title.toString()}
  4. ${helmet.meta.toString()}
  5. <style>${cssStr}</style>
  6. </head>
  7. <body>
  8. <div id='root' >${content}</div>
  9. <script>
  10. window.context = {
  11. state: ${JSON.stringify(store.getState())}
  12. }
  13. </script>
  14. <script src='/index.js' ></script>
  15. </body>
  16. </html>

重新跑一下 搞定!

当然SSR-SEO绝不这么简单。仅仅在页面上添加head标签内加上title 和meta标签影响是有限的。8102年的搜索爬虫已经不单单去匹配title和 description,而是全稳的匹配(也就是说title和descript有影响但是影响很小)搜索爬虫会把整个网站所有的文本收集起来进行分析。

那么如何做好SEO

题外话顺便说一下如何做好SEO。一个网站无非三大块内容,文字、多媒体、链接。要做到的是文字的原创性,图片的原创性以及高清度还有站内链接尽量和站内内容相关。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号