杰拉斯的博客

React+Webpack 前后端同构(服务端渲染)实践篇

杰拉斯 杰拉斯 | 时间:2016-09-10, Sat | 18,347 views
前端开发, 后台技术 

前言

聊完理论(详见:《React+Webpack 前后端同构(服务端渲染)理论篇》),我们来看看如何把前后端同构运用到实践中。

服务端渲染

react-dom 模块中,包含了两个服务端渲染相关的两个方法:

  • renderToString:将 React 元素渲染为 HTML 字符串,同时为每一个节点带上 data-react-id,而在浏览器端渲染的时候,React 不会重新渲染 DOM 树,而只是单纯为元素添加事件,这就是为什么 React 能够做到高性能的首屏渲染。
  • renderToStaticMarkup :同样将 React 元素渲染为 HTML 字符串,但不带 data-react-id,产生的 HTML 字符串长度更小,适合只在服务端做渲染的页面中使用,这时候 React 的功能相当于一个模板引擎。

为服务端实现 require 魔法

上一篇我们提到过,我们可以通过 Webpack 加载器将样式、图片等前端资源作为模块进行引入,但这些资源如果在 Node 中直接引入,是会报错的,因此,我们需要借助 webpack-isomophic 模块来消除前后端 require 函数的差异。

前端部分

webpack.config.js 中,配置 webpack-isomorphic 插件:

var IsomorphicPlugin = require('webpack-isomorphic/plugin');

// 配置需要同构的文件后缀名
var isomorphicPlugin = new IsomorphicPlugin({
    extensions: ['jpg', 'png', 'gif', 'css']
});

module.exports = {
    // 配置源文件目录
    context: __dirname + '/src',
    // ...
    plugins: [
        //...
        isomorphicPlugin
    ]
};

服务端部分

var webpackIsomorphic = require('webpack-isomorphic');

// 配置构建后的文件目录
webpackIsomorphic.install(__dirname + '/dist', {
    cache: process.env['NODE_ENV'] !== 'development'
});

不得不说 webpack-isomorphic 的使用确实非常的简单方便。

前后端数据同步

前面提到,React 在浏览器端,如果 virtual DOM 的渲染结果与服务端一致,则不需要重新渲染 DOM 树,因此前端的数据也应该与服务端保持一致,那么前端如何得到服务端的数据呢?方法也很简单,向浏览器输出 HTML 的时候,同时把数据以 JSON 的格式置于 <script> 标签中,输出至浏览器。

服务端

输出页面 HTML 时,同时带上原始数据:

var initialData = {foo: 'bar'};
var viewsDir = path.join(__dirname, './views/dist');
var template = path.join(viewsDir, 'index.tpl');
var reactClass = path.join(viewsDir, 'js/index.js');
var factory = React.createFactory(require(reactClass));
gotpl.renderFile(template, {
    initialData: initialData,
    initialHTML: ReactDOMServer.renderToString(factory(initialData))
}, function (err, html) {
    if (err) {
        res.end(err.stack);
    } else {
        res.end(html)
    }
});

HTML模板

将原始数据置于 <script> 标签中,并赋值给 window.initialData

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React+Webpack 前后端同构</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
<div id="root"><%- initialHTML %></div>
<script>window.initialData = <%- JSON.stringify(initialData) %>;</script>
<script src="index.js"></script>
</body>
</html>

JSX 文件

判断是否浏览器环境,若是,将 window.initialData 作为数据进行渲染:

// ...
if (typeof window !== 'undefined') {
    ReactDOM.render(
        React.createElement(IndexPage, initialData),
        document.getElementById('root')
    );
}

搞定,Demo 详见:webpack-isomorphic-example

结语

最后说点不那么相关的题外话,前几天面试一个人的时候,面试者说:『现在前端发展太快了,都不知道要学什么,从哪学起了。』确实,互联网发展速度飞快,前端作为其中重要的一环,发展更是日新月异。语言上有了 HTML5CSS3,ES6,TypeScript;框架上 React,Vue.js,Angular 方兴未艾;工具上 Grunt,Gulp,FIS3;模块管理上 RequireJS,SeaJS,Browserify,Webpack;服务端 Express,koa,koa2。。。

那到底要怎样去学习,才能更上这个时代的脚步呢?其实,技术是永远学不完的,面对这么多新兴的技术,大部分我们只需要做到初步的了解就够了,了解它们的特性,了解他们的应用场景,学习成本,这是视野的广度。然后在其中选择一小部分适用于当前学习或工作场景的,去实践,去探究,拓展技术的深度。不可一业不专,不可只专一业——一个什么都会一些,但什么都做不好的人,其实是没有核心价值的。

这里顺便安利一个 React 实现前后端同构的网站:哔卟TV,一个专注于 LOL 的直播聚合平台,做的很用心,LOLer 的福音。

如需转载请注明出处:杰拉斯的博客

相关文章

7 条评论 »

  1. 确实学不过来… 前端框架现在是五代十国

  2. 网站很干净

    1. 大学时候的设计了。。没有好好兼容移动端= =

  3. jchen jchen

    这个评论做得很新颖啊

  4. 博主代码高亮用的什么插件?

  5. hajcker hajcker

    很棒