前段时间在知乎上看到一篇提问,说的是为何如今又开始流行服务器端渲染html了。整理了网上一些评论,结合本身的想法,整理出了一段前端发展史。html
早在1989年,HTML的诞生是一个物理学家为了方便学术文档的分享而创造,这个也是前端起始的时间。后来,CSS和Javascript加入前端行列,用来渲染页面样式和处理页面动效逻辑,前端三剑客成立。刚开始的前端程序员,其实就是作切图写样式(CSS)和作页面特效(JS)等一切基础的工做,处于程序员鄙视链的底层。
随着互联网发展与技术进步,静态页面已经远不能知足产品需求,页面上要根据逻辑产生动态的数据,这时,便迎来PHP,JSP等为表明的web1.0时代。此时的服务器渲染,是以“文档”为核心思想。服务器端的逻辑是把HTML,CSS和JS当作一个静态文件,对“文档”而言不存在“指令”和“数据”的区别,一切都是数据。因此咱们能够看到服务器渲染,GET就是请求一个文件,而web 1.0时代的诸多服务端框架最基础的组件之一就是文档模版,好比asp, JSP之类,核心设计理念就是HTML文件里放占位符而后由服务端逻辑替换成实际数据后一股脑返回。不少中小型项目,不分前端后端,你们都是web开发工程师,按如今的说法叫全栈工程师。而在如今来看,这样的模式是存在不少问题的,拿jsp举例,动态资源和静态资源彻底耦合,服务器压力大,并且一旦出现情况,先后台一块儿玩完,用户体验极差;jsp必需要在支持java的web服务器里运行,性能提不上来;若是jsp中内容不少,页面响应会很慢……
1998年,IE5.0引入XMLHttpRequest技术,实现了异步调用服务器的功能,2005年,Google在它著名的交互应用程序中使用了ajax异步通信,web前端引来2.0革命。以后W3C发布XMLHttpRequest标准,为以后的ajax爆发提供技术基础。
2006年,JQuery工具库发布,一经出世凭借其简单易容的特性和解决浏览器兼容性的能力风靡全球。
2010年,Backbone诞生,RequireJS第一个版本发布,前端的模块化开发时代正式来临了。然后,随着前端MVC的兴起,SPA(Single Page Application 单页面应用)开始变成一种项目开发的潮流,先后端分工很是清晰。前端工做在浏览器端,后端工做在服务端。清晰的分工,可让开发并行,测试数据的模拟不难,前端能够本地开发。此时先后端分离的运动在各大公司间兴起,前端自立门户,独立发展。前端程序员们翻身的机会来了。
然而此时,不少本不应被作成SPA的也被作成了SPA。可是,SPA应用存在种种问题,好比SEO,好比首屏加载速度,这让前端开发人员优化愁白了头。
随着Node.js的兴起,Javascript开始有能力运行在服务器端,这意味这有一种新的研发模式:Front-end UI layer 处理浏览器层的展示逻辑,Back-end UI layer 处理路由、模板、数据获取、cookie 等。经过 Node,Web Server 层也是 JavaScript 代码,这意味着部分代码可先后复用,须要 SEO 的场景能够在服务端同步渲染,因为异步请求太多致使的性能问题也能够经过服务端来缓解。前一种模式的不足,经过这种模式几乎都能完美解决掉。
Web 2.0时代最大的思想革命本质不是先后端分离,而是把网页看成独立的应用程序(app)。先后端分离只是实现这一新架构的必然结果。对程序而言指令和数据是分离的。HTTP GET拿到的不是渲染后的网页,而是一个由html和Javascript组成的app, 这个app以浏览器为虚拟机。装载和显示数据是app启动以后的运行逻辑。传统上app叫什么?叫Client,也就是前端。因而先后端就这么分离了,浏览器变成了app的运行环境,后端蜕化成了单纯的业务逻辑和数据接口。写Javascript再也不是给网页添特效的小伎俩,而是正经的和写桌面应用程序同样的工程。因而咱们看到了前端工程化,编译(转译),各类MVC/MVVM框架,依赖工具,等等。前端
使用服务器端渲染,最主要的问题,其实就是为了解决SEO的问题。若是SPA应用也有良好的SEO,就不用服务器端渲染这么麻烦了。固然服务器端渲染能解决的首屏加载速度的问题也是缘由之一。那么,SEO是什么呢?
SEO(Search Engine Optimization),搜索引擎优化。好比谷歌、百度须要抓取你所发布的网站信息来进行天然排序,是经过爬虫进行的。
来看两段代码:
vue
上面是以前很早前写过的两段掘金文章的爬虫代码(写的有点low),大概思路就是使用superagent发送http请求,把整个页面(文档对象)爬下来,包括head, body等,而后用cheerio进行解析,而后抓取页面节点元素以及关键信息。可能你以为,这个简单,我页面上信息都是经过ajax请求到而后插入到dom元素中的。注意,爬虫爬到的页面并无发送ajax请求,就是一个初始化的纯静态页面,若是你用的是spa应用,那可能body中除了一个id为app的节点,什么都没有。因此,咱们须要让页面在服务器端就已经被渲染完成,传给客户端的时候已是一个具备数据信息的静态html文档。固然,如今也有针对SPA应用进行的SEO优化方案,这个不在本文讨论范围以内。
如下总的列举服务器渲染的一些优缺点:java
通用(也称同构)的JavaScript已经成为JavaScript社区很经常使用的一个术语。通用的JavaScript用来形容能够在客户端执行,也可在服务端执行的Javascript代码。 在VUE的官方文档上是这么描述的:webpack
Vue.js 是构建客户端应用程序的框架。默认状况下,能够在浏览器中输出 Vue 组件,进行生成 DOM 和操做 DOM。然而,也能够将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记"混合"为客户端上彻底交互的应用程序。ios
前半句好理解,就是说你能够在服务器(后端)环境中,使用vue.js来构建组件和页面,而后将渲染好的静态html字符串传给客户端展现。后半句感受句子不太通顺,英文版是这样的:git
“Finally "hydrate" the static markup into a fully interactive app on the client.”程序员
大概意思就是说,把应用传给客户端之后,因为一些静态标记,客户端也会具有一样的交互(就是MVVM双向数据绑定)。github
构建服务端渲染的JavaScript程序多少有些无趣,在开始编码以前,须要大量的基础配置。所以,解决vue.js服务端渲染问题的Nuxt.js产生了。 Nuxt.js 是一个基于 Vue.js 的通用应用框架。预设了服务器端渲染所需的各类配置,如异步数据,中间件,路由,只要遵循其中的规则就能轻松实现SSR。。它比如是 Angular Universal 之于 Angular, Next.js 之于 React。 经过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI渲染。web
在安装vue-cli的状况下,快速生成一个nuxt项目的命令以下:
$ vue init nuxt-community/starter-template <project-name>
复制代码
进入项目目录后
$ npm install
复制代码
而后启动项目
$ npm run dev
复制代码
这样项目就能正常运行在http://localhost:3000
了
这里就不详细介绍nuxt.js的一些用法和API了,能够直接看官网的教程:zh.nuxtjs.org/guide 。
我本身作了一个nuxt.js的简单demo(极其简单),Github地址,这里就我本身的的一些体验,对比spa应用,来聊聊这个框架。
nuxt是采用vue-cli来建立的模板,相比常规的vue模板,他们具有很是重要的一点:方便。nuxt.js一样已经将各类项目所需的webpack配置替咱们打理好了,开箱即用,基本不须要做什么改动。并且即便须要自定义一些配置,修改起来也很是简单。咱们来把它的目录结构和SPA应用做一个对比。
pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue
复制代码
Nuxt.js 生成对应的路由配置表为:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'users-id',
path: '/users/:id?',
component: 'pages/users/_id.vue'
},
{
name: 'slug',
path: '/:slug',
component: 'pages/_slug/index.vue'
},
{
name: 'slug-comments',
path: '/:slug/comments',
component: 'pages/_slug/comments.vue'
}
]
}
复制代码
index.js
,而后对外暴露一个Vuex.Store实例便可。可是,通过踩坑,这里的状态树和SPA里有些不同,这个等会说。actions
中的nuxtServerInit函数,这个咱们等会再说。middleware
里的中间件函数,此时,尚未进行数据获取和页面渲染,因此咱们能够在中间件函数中执行一些进入路由前的逻辑,好比用户权限判断。this
。head
部分能够自定义当前页面的头部信息,好比title, meta之类的。固然,若是须要定义全局head能够在nuxt.config.js
中配置。layout
部分能够自定义页面布局,不少页面公用的静态头、尾部分能够统必定义按需引用。scrollToTop
用于页面跳转时将页面滚动置顶。transition
用于页面间跳转的过渡动画。整个demo作下来,目前让我印象最深的就是状态树,它和SPA应用仍是有必定区别的。
当时我须要完成的需求是,保存用户信息,并在任何页面可使用它,若是非登陆页没有获取到用户信息,跳转回登陆页。
起初,个人设计思路是,在用户登陆成功后,调用后台接口获取该用户全部信息,而且存在store中。流程图以下:
nuxtServerInit
。Nuxt.js 调用它的时候会将页面的上下文对象做为第2个参数传给它,上下文对象能够拿到
req
请求对象,那么就存在这么一种逻辑。我能够将用户信息存储在服务器session中,而后经过
req.session.user
来访问当前登陆的用户。将用户登陆信息传给客户端的状态树,代码以下:
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}
复制代码
这样在配合middleware中间件,就能够完成用户信息获取和会话控制,流程以下:
其它还涉及的一些内容,其实看看官网教程,看看官网示例都能搞定,教程仍是很是易懂的。
使用Vue,React等服务器渲染,并非走之前模板式渲染的老路。它已经跨越历史,朝着更优秀的方面发展。 而Nuxt.js,仍是一个很是年轻的框架(如今官网才是0.10.7版本),目前也有不少待改进的问题,但它的出现为 Vue.js 开发者搭建服务端渲染项目提供了巨大的便利。据说Nuxt.js 2.0 即未来临,期待版本发布后,能给咱们带来更多实用的新功能。