1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
      <output id="hzk7v"></output>
    2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
    3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

      详解超简单的react服务器渲染(ssr)入坑指南

       更新时间£º2019年02月28日 09:54:42   作者£º馒头   我要评论

      这篇文章主要介绍了详解超简单的react服务器渲染(ssr)入坑指南£¬小编觉得挺不错的£¬现在分享给大家£¬也给大家做个参考¡£一起跟随小编过来看看吧

      前言

      本文是基于react ssr的入门教程£¬在?#23548;?#39033;目中使用还需要做更多的?#28210;?#21644;优化£¬比较适?#31995;?#19968;次尝试react ssr的小伙伴们¡£技术涉及到 koa2 + react£¬案例使用create-react-app创建

      SSR 介绍

      Server Slide Rendering£¬缩写为 ssr 即服务器端渲染£¬这个要从SEO说起£¬目前react单页应用HTML代码是下面这样的

      <!DOCTYPE html>
      <html lang="en">
       <head>
        <meta charset="utf-8" />
        <link rel="shortcut icon" href="favicon.ico" rel="external nofollow" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
        <meta name="theme-color" content="#000000" />
        <title>React App</title>
       </head>
       <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root"></div>
        <script src="/js/main.js"></script>
       </body>
      </html>
      1. 如果main.js 加载比?#19979;ý£?#20250;出现白屏一闪的现象¡£
      2. 传统的搜索引擎爬虫因为不能抓取JS生成后的内容£¬遇到单页web项目£¬抓取到的内容啥也没?#23567;?#22312;SEO上会吃很多亏£¬很难排搜索引擎到前面去¡£

      React SSR£¨react服务器渲染£©正好解决了这2个问题¡£

      React SSR介绍

      这里通过一个例子来带大家入坑£¡先使用create-react-app创建一个react项目¡£因为要修改webpack£¬这里我们使用react-app-rewired启动项目¡£根目录创建一个server目?#21363;?#25918;服务端代码£¬服务端代码我们这里使用koa2¡£目录结构如下£º

      这里先来看看react ssr是怎么工作的¡£

      这个业务流程图比较清晰了£¬服务端只生成HTML代码£¬?#23548;?#19978;前端会生成一份main.js提供给服务端的HTML使用¡£这就是react ssr的工作流程¡£有了这个图会更好的理解£¬如果这个业务没理解清楚£¬后面的估计很难理解¡£

      react提供的SSR方法有两个renderToString 和 renderToStaticMarkup£¬区别如下£º
      • renderToString 方法渲染的时候带有 data-reactid 属性. 在浏览器访问页面的时候£¬main.js能识别到HTML的内容£¬不会执行React.createElement二次创建DOM¡£
      • renderToStaticMarkup 则没有 data-reactid 属性£¬页面看上去干净点¡£在浏览器访问页面的时候£¬main.js不能识别到HTML内容£¬会执行main.js里面的React.createElement方法重新创建DOM¡£

      实现流程

      好了£¬我们都知道原理了£¬可以开始coding了,目录结构如下£º

      create-react-app 的demo我没动过£¬直接用这个做案例了£¬前端项目基本上就没改了,等会儿我们服务器端要使用这个模块¡£代码如下£º

       render() {
        return (
         <div className="App">
          <header className="App-header">
           <img src={logo} className="App-logo" alt="logo" />
           <p>
            Edit <code>src/App.js</code> and save to reload.
           </p>
           <a
            className="App-link"
            href="https://reactjs.org" rel="external nofollow" 
            target="_blank"
            rel="noopener noreferrer"
           >
            Learn React
           </a>
          </header>
         </div>
        );
       }
      }
      
      export default App;

      在项目中新建server目录£¬用于存放服务端代码¡£为了简化£¬我这里只有2个文件£¬项目中我们用的ES6£¬所以还要?#28210;?#19979;.babelrc

      .babelrc ?#28210;ã?#22240;为要使用到ES6
      {
        "presets": [
          "env",
          "react"
        ],
        "plugins": [
          "transform-decorators-legacy",
          "transform-runtime",
          "react-hot-loader/babel",
          "add-module-exports",
          "transform-object-rest-spread",
          "transform-class-properties",
          [
            "import",
            {
              "libraryName": "antd",
              "style": true
            }
          ]
        ]
      }
      index.js 项目入口做一些预处理£¬使用asset-require-hook过?#35828;?#19968;些类似 import logo from "./logo.svg"; 这样的资源代码¡£因为我们服务端只需要纯的HTML代码£¬不过?#35828;?#20250;报错¡£这里的name£¬我们是去掉了hash值的
      require("asset-require-hook")({
       extensions: ["svg", "css", "less", "jpg", "png", "gif"],
       name: '/static/media/[name].[ext]'
      });
      require("babel-core/register")();
      require("babel-polyfill");
      require("./app");
      public/index.html html模版代码要做个调整£¬{{root}} 这个可以是任何可以替换的字符串£¬等下服务端会替换这段字符串¡£
      <!DOCTYPE html>
      <html lang="en">
       <head>
        <meta charset="utf-8" />
        <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" rel="external nofollow" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
        <meta name="theme-color" content="#000000" />
        <link rel="manifest" href="%PUBLIC_URL%/manifest.json" rel="external nofollow" />
        <title>React App</title>
       </head>
       <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root">{{root}}</div>
       </body>
      </html>
      app.js 服务端渲染的主要代码£¬加载App.js£¬使用renderToString 生成html代码£¬去替换掉 index.html 中的 {{root}} 部分
      import App from '../src/App';
      import Koa from 'koa';
      import React from 'react';
      import Router from 'koa-router';
      import fs from 'fs';
      import koaStatic from 'koa-static';
      import path from 'path';
      import { renderToString } from 'react-dom/server';
      
      // ?#28210;?#25991;件
      const config = {
       port: 3030
      };
      
      // 实例化 koa
      const app = new Koa();
      
      // 静态资源
      app.use(
       koaStatic(path.join(__dirname, '../build'), {
        maxage: 365 * 24 * 60 * 1000,
        index: 'root' 
        // 这里?#28210;?#19981;要写成'index'就可以了£¬因为在访问localhost:3030时£¬不能让服务默认去加载index.html文件£¬这里很容易掉进坑¡£
       })
      );
      
      // 设置路由
      app.use(
       new Router()
        .get('*', async (ctx, next) => {
         ctx.response.type = 'html'; //指定content type
         let shtml = '';
         await new Promise((resolve, reject) => {
          fs.readFile(path.join(__dirname, '../build/index.html'), 'utfa8', function(err, data) {
           if (err) {
            reject();
            return console.log(err);
           }
           shtml = data;
           resolve();
          });
         });
         // 替换掉 {{root}} 为我?#24039;?#25104;后的HTML
         ctx.response.body = shtml.replace('{{root}}', renderToString(<App />));
        })
        .routes()
      );
      
      app.listen(config.port, function() {
       console.log('服务器启动£¬监听 port£º ' + config.port + ' running~');
      });
      config-overrides.js 因为我们用的是create-react-app£¬这里使用react-app-rewired去?#21335;Âwebpack的?#28210;Ö™?#22240;为执行npm run build的时候会自动给资源加了hash值£¬而这个hash值£¬我们在asset-require-hook的时候去掉了hash值£¬?#28210;?#37324;面需要?#21335;”n?#19981;然会出现?#35745;?#19981;显示的问题£¬这里也是一个坑£¬要注意下¡£
      module.exports = {
       webpack: function(config, env) {
        // ...add your webpack config
        // console.log(JSON.stringify(config));
        // 去掉hash值£¬解决asset-require-hook资源问题
        config.module.rules.forEach(d => {
         d.oneOf &&
          d.oneOf.forEach(e => {
           if (e && e.options && e.options.name) {
            e.options.name = e.options.name.replace('[hash:8].', '');
           }
          });
        });
        return config;
       }
      };

      好了£¬所有的代码就这些了£¬是不是很简单了£¿我们koa2读取的静态资源是 build目录下面的¡£先执行npm run build打包项目£¬再执行node ./server 启动服务端项目¡£看下http://localhost:3030页面的HTML代码检查下£º



      没有{{root}}了£¬服务器渲染成功£¡

      总结

      相信这篇文章是最简单的react服务器渲染案例了£¬这里交出github地址£ºhttps://github.com/mtsee/react-koa2-ssr

      以上就是本文的全部内容£¬希望对大家的学习有所帮助£¬也希望大家多多支持脚本之家¡£

      您可能?#34892;?#36259;的文章:

      相关文章

      最新评论

      3dÊÔ»úºÅÖвÊÍø

        1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
          <output id="hzk7v"></output>
        2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
        3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

            1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
              <output id="hzk7v"></output>
            2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
            3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>