未加星标

Respo 文档站点的 isomorphic rendering 方案

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二05 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏
文档站的特点

既是单页面, 又是服务端渲染

正好帮我刷一下访问量... http://respo.site/

注意站点的特别之处, 绝大部分的链接都是触发页面局部渲染的,

而在特殊的 js 无法加载的情况下, 还是以链接的形式刷新页面.

所以, 整个站点既是单页面, 又是服务端渲染... 感受一下.

文档站是基于 React 写的, 用的是自己的 router 和 store 方案

源码看 https://github.com/Respo/resp...

为了做页面局部渲染, 前端运行 React 是必要的,

特殊的无 js 的场景, 对应的主要是爬虫, 方便搜索引擎抓取.

而且为了搜索引擎抓取, 中间的链接需要准确无误,

比如说我浏览页面, 在前端渲染好了 tutorial.html 这个页面

http://respo.site/guide/tutor...

这个页面是从侧边栏的链接点击, 然后修改 url 并且渲染页面的,

那么, 服务器上要保证有对应的 tutorial.html 文件提供内容,

文档实际上有几十个页面, 所以几十个 HTML 都是预先渲染好的.

只不过用户访问时, 从任何一个地址进入, 后续的点击都是局部渲染的.

isomorphic rendering(同构渲染)

Gulp 渲染和前端渲染应该是一致的

这个方案有几个特征:

使用默认 Nginx 即可, 不需要额外的服务器脚本, 更快

访问首屏几乎就是服务端渲染, 内容展示更快

访问后续页面都是客户端渲染, 更快

除了首屏加载的 js 代码没有做分块之外, 总体感觉都比较好,

没有等待服务端渲染的时间, 也没有等待客户端加载 js 再渲染的时间,

初看这是一个比较理想的站点的优化方案.

当然, 这个页面比较简单, 没有通过 Ajax 加载 JSON 再渲染的部分,

对于服务端渲染方案来说, 一个做法是由服务器抓取这部分 JSON 然后渲染,

但是这会消耗两块时间, 1) 抓取数据时间, 2) 渲染页面的时间,

略去动态内容的话, 静态的页面完全可以在 Gulp 建构时渲染完成,

单单考虑这种情况, 我觉得用 Gulp 预渲染页面是比较切实可行的方案.

至于动态内容, 我觉得在客户端通过脚本抓取是更简单的方案,

除了 SEO 之类的场景当中会要求有动态内容, 一般都能满足需要.

实现思路

Model, View 以及路由问题

大致是这样一个过程:

将整个页面看做成是一个 Component, 根据路由渲染对应内容

在浏览器当中, 路由通过地址栏获取, 然后渲染 Component

在 Gulp 环境, 路由通过字符串模拟, 渲染渲染页面为 HTML

建构过程当中, 穷举所有路由和对应的文件名, 存储 HTML 文件

首先就是服务端很容易遇到的 Component 的加载和渲染问题,

需要处理一些浏览器依赖在 Node 环境中报错的问题,

其次是组件通过 ReactDOM API 全部渲染成为 HTML.

这部分在 React 和 Webpack 社区当中已经相对成熟.

这个步骤对路由模块有做了一些要求, 需要能在服务端运行,

原理上说, 服务端解析路由历史悠久, 方案并不存在问题,

麻烦的地方是要把前端路由模块拿到后端, 一致地运行,

而且, 最好是很容易用 Node 脚本直接去操作, 以便处理多个页面,

解耦做得好的话, 都还不错. 但是也要看具体的路由支持怎样.

router-as-view

一个很小众的路由模块

https://github.com/react-chin...

在 router-as-view 当中提供了 parseAddress 函数,

可以根据规则直接将路由 /a/b?c=d 转换为一份数据,

随后被放进 Store 当中, 然后 Component 直接依据 Store 进行渲染.

{parseAddress} = require 'router-as-view/lib/path' routes = Immutable.fromJS home: [] 'discuss.html': [] guide: ['entry'] docs: ['post'] router = parseAddress path, routes initialStore = schema.store.set 'router', router ReactDOM.renderToString(Container(store: store}))

从而很容易进行抽象, 然后再 Gulp 里调用渲染 HTML:

gulp.task 'entries', (cb) -> // ... pages.forEach (pathname) -> // ... fs.writeFileSync "build/#{filename}.html", html(env, routerPath) // ... react-router

很久没用了...

具体实现不清楚, 我只能摘录文档当中的例子:

https://github.com/ReactTrain...

import { renderToString } from 'react-dom/server' import { match, RoutingContext } from 'react-router' import routes from './routes' serve((req, res) => { // Note that req.url here should be the full URL path from // the original request, including the query string. match({ routes, location: req.url }, (error, redirectLocation, renderProps) => { if (error) { res.status(500).send(error.message) } else if (redirectLocation) { res.redirect(302, redirectLocation.pathname + redirectLocation.search) } else if (renderProps) { res.status(200).send(renderToString(<RoutingContext {...renderProps} />)) } else { res.status(404).send('Not found') } }) }) vue-router

Vue 2 文档上没解释服务端路由的问题, 从已经发布的 Demo 看是支持的,

而且像是为了服务端渲染顺带就支持了...

没有文档不好说, 只能看下代码当中的例子来推测一下:

https://github.com/vuejs/vue-...

https://github.com/vuejs/vue-...

结尾

其他的方案, Angular 2 未知... 按说已经支持服务端渲染, 应该能搞定,

Respo 我正在重构, 应该很快就能搞定了...

这只是一个套路, 跟具体的框架应该是无关的, 应该都能完成.

当然, 回到文章的核心观点, 就是要提供一个 Gulp 渲染的方案,

所有的页面入口按照路由在服务端预渲染完成, 作为一个优化,

从而让页面在观感上加载得更快.

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

分页:12
转载请注明
本文标题:Respo 文档站点的 isomorphic rendering 方案
本站链接:http://www.codesec.net/view/480542.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(30)