很重要,因此要普及。css
SEO: 搜索引擎优化(Search Engine Optimization),它是指经过站内优化,如:网站结构调整、网站内容建设、网站代码优化以及站外优化等方法,来进行搜索引擎优化。html
简单说: 经过各类技术(手段)来确保,你的Web内容被搜素引擎最大化收录,最大化提升权重,带来更多流量。前端
**常见关键词:**白帽、黑帽、SEM、Backlink、Linkbait、PageRank、Keyword Stuffing...,总之都围绕着一个核心:SEO;流量是变现的快车道,SEO 是低成本获取流量的最佳方法。vue
目前大部分的搜索引擎仅能抓取URI直接输出的数据资源,对于 Ajax 类的异步请求的数据没法抓取;Google 除外,Google 有本身的Google’s Webmaster AJAX Crawling Guidelines.技术支持。node
**SPA:**单页 Web 应用(single page web application,SPA),就是只有一张 Web 页面的应用,是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的 Web 应用程序。webpack
简单说: Web 再也不是一张张页面,而是一个总体的应用,一个由路由系统、数据系统、页面(组件)系统...组成的应用程序,其中路由系统是非必须的。git
大部分的 Vue 项目,本质是 SPA 应用,Angular.js、Angular、Vue、React...还有最先的"Pjax"均如此。github
SPA 时代,主要是在Web端使用了history
或hash
(主要是为了低版本浏览器的兼容)API,在首次请求经服务端路由输出整个应用程序后,接下来的路由都由前端掌控了,前端经过路由做为中心枢纽控制一系列页面(组件)的渲染加载和数据交互。web
而上面所述的各种框架则是将以:路由、数据、视图为基本结构进行的规范化的封装。ajax
最先的 SPA 应用,由 Gmail、Google Docs、Twitter 等大厂产品实践布道,普遍用于对SEO要求不高的场景中。
SSR: 服务端渲染(Server Side Render),即:网页是经过服务端渲染生成后输出给客户端。
在 SPA 以前的时代,咱们的Web架构大都是 SSR,如:Wordpress(PHP)、JSP技术、JavaWeb...或者 DEDECMS、Discuz! 等这些程序都是传统典型的 SSR 架构, 即:服务端取出数据和模板组合生成 html 输出给前端,前端发生请求时,从新向服务端请求 html 资源,路由也由服务端来控制。
其次,有个概念叫预渲染(Prerendering)。
若是你只是用服务端渲染来改善一个少数的营销页面(如 首页,关于,联系 等等)的 SEO,那你能够用预渲染来实现。 预渲染不像服务器渲染那样即时编译 HTML,它只在构建时为了特定的路由生成特定的几个静态页面,等于咱们能够经过 Webpack 插件将一些特定页面组件 build 时就编译为 html 文件,直接以静态资源的形式输出给搜索引擎。
但实际的商业应用中,大部分时候咱们须要的是即时渲染,这也是咱们今天讨论的主题。
为何要SSR,为了体验,还有SEO。
首先,用户可能在网络比较慢的状况下从远处访问网站 - 或者经过比较差的带宽。 这些状况下,尽可能减小页面请求数量,来保证用户尽快看到基本的内容。 能够用Webpack的代码拆分避免强制用户下载整个单页面应用,可是,这样也远没有下载个单独的预先渲染过的 HTML 文件性能高。
对于世界上的一些地区人,可能只能用1998年产的电脑访问互联网的方式使用计算机。 而 Vue 只能运行在 IE9 以上的浏览器,你可能也想为那些老式浏览器提供基础内容 - 或者是在命令行中使用 Lynx 的时髦的黑客。
在大部分的商业应用中,咱们有 SEO 的需求,咱们须要搜索引擎更多地抓取到咱们的内容,更详细地认识到咱们的网页结构,而不是仅对首页或特定静态页进行索引,这是 SSR 最重要的意义。
简单说就是,咱们须要搜素引擎看到这样的代码:
而不是这样的代码:
且,咱们还须要在 SSR 的基础上实现 SPA,即:首屏渲染。
基本流程是:
在浏览器第一次访问某个 URI 资源的时候(首屏),Web 服务器根据路由拿到对应数据渲染并输出,且输出的数据中包含两部分:
在客户端首屏渲染完成以后,此时咱们看到的其实已是一个和以前的 SPA 相差无几的应用程序了,接下来咱们进行的任何操做都只是客户端的应用进行交互, 页面/组件由Web端渲染,路由也由浏览器控制,用户只须要和当前浏览器内的应用打交道就能够了。
以前在各大 SPA 框架还未正式官方支持 SSR 时,有一些第三方的解决方案,如:prerender.io, 它们作的事情就是创建HTTP一个中间层,在判断到访问来源是蜘蛛时,输出已缓存好的html数据,此数据若不存在,则调用第三方服务对 html 进行缓存,往复进行。
另外一方法是自行构建蜘蛛渲染逻辑,当识别 UA 为搜索引擎时,拿服务端已准备好的模板和数据进行渲染输出 html 数据,反之,则输出 SPA 应用代码;
我当时也考虑过此方法,但有不少弊端,如:
因此,最好的方法是 SPA 能和服务端使用同一套模板,且使用同一个服务端逻辑分支,再简单说:最好 Vue、Ng2... 能直接在服务端跑起来。
因而,陆续诞生了基于 React 的Next.js、基于 Vue 的Nuxt.js、Ng2 诞生之日便支持。
没错,Nuxt.js 就是今天的主角。
Nuxt.js 是一个基于 Vue 的通用应用框架。
经过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI渲染。
咱们的目标是建立一个灵活的应用框架,你能够基于它初始化新项目的基础结构代码,或者在已有 Node.js 项目中使用 Nuxt.js。
Nuxt.js 预设了利用 Vue 开发服务端渲染的应用所须要的各类配置。
除此以外,咱们还提供了一种命令叫:nuxt generate
,为基于 Vue 的应用提供生成对应的静态站点的功能。
咱们相信这个命令所提供的功能,是向开发集成各类微服务(miscroservices)的 Web 应用迈开的新一步。
做为框架,Nuxt.js 为 客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据加载、中间件支持、布局支持等。
Nuxt.js是使用 Webpack 和 Node.js 进行封装的基于Vue的SSR框架,使用它,你能够不须要本身搭建一套 SSR 程序,而是经过其约定好的文件结构和API就能够实现一个首屏渲染的 Web 应用。
之因此叫 Nuxt.js 也是由于受到了 Next.js 的启发。
做者是法国的兄弟俩,EvenYou 在微博屡次提到,也在欧洲见过哥俩。
在此以前,国内有一些对 Vue SSR 的整合尝试,但都没有成功,主要在于 Webpack 和 Node 的结合上没有实践出最佳方案, 当我看到 Nuxt.js 以约束文件夹和配置文件nuxt.config.js
的方式来管理多个程序组件之间的关系时,就以为,很酷!
接下来,我不会提供具体更多的学习资料,由于官方文档已经很是全面和成熟,已经 0.10.5 了(如今是 RC-11),只讲下其架构和原理,和一些生产环境会遇到的问题。
首先,Nuxt.js 是一个 Node 程序,就像上面说的,咱们是要把 Vue 跑在服务端,因此必须使用 Node 环境。
咱们对 Nuxt.js 应用的访问,其实是在访问这个 Node.js 程序的路由,程序输出首屏渲染内容 + 用以从新渲染的 SPA 的脚本代码,而路由是由 Nuxt.js 约定好的 pages 文件夹生成的。
因此,总体上,Nuxt.js 经过各个文件夹和配置文件的约束来管理咱们的程序,而又不失扩展性,其有本身的插件机制。
按照目前的版本,Nuxt.js 的程序的文件结构大概分为如下部分:
nuxt.config.js
对程序的扩展管理可大概分为如下类:
lru-cache
的配置对象,有默认值,可选关闭require
语句webpack.config.js
相关文件中的变量语句generate
命令执行时的行为作一些定制vue-meta
插件的全局配置,vue-meta
用于VUE/SSR程序的文档元信息的管理plugins
文件夹中的插件vue-router
的扩展和定制,其中还包括了中间件的配置,但并不完美(后面说)chokidar
和 Webpack 的相关配置项同时,Nuxt.js 支持以generate
命令将程序直接构建为静态 html ,就像上面说的,能够做为静态资源直接输出。
特殊的异步需求
这是生产环境最多见的问题,没有之一。
拿个人博客右侧 Sidebar 为例,在组件结构中,其属于宿主 layout 下的子组件,不属于页面组件,没法使用页面组件中的fetch
方法, 官方的解释是子组件没法使用阻塞异步请求,即:子组件获得的异步数据没法用于服务端渲染,这对于程序是合理的,避免异常阻塞,简化业务模型;
但实际需求中,我须要这些异步数据加强站内内链 SEO;因而,咱们能够巧妙地使用内置 vuex 中的nuxtServerInit
这个 API,这个 API 是在 Nuxt.js 程序实例化以后第一次执行的方法, 其内部返回一个promise
,咱们能够在这里完成咱们站内的全部子组件异步请求,随后将数据映射至对应子组件便可,这里有实践代码。
内存问题
在阿里云低配机上出现内存膨胀的问题,一个 Blog 程序 Run 起的内存高达 100M+,固然也因为 Node.js 的特殊单线程异步机制,暂不关心。
但在通过一段时间的访问以后,特别是瞬间高并发访问,会致使内存膨胀爆表宕机,经分析,是因为组件缓存引发的,将组件缓存减小至10,问题有所改观,但不明显;
更深缘由是,每次用户访问,程序均会从新渲染组件输出,组件数据即在一段时间内驻存在内存中,直到 V8GC 回收。
最终的解决方案是:
使用官方推荐的"使用编码中的 Nuxt.js "方法,自定义Node.js程序的入口,对程序进行一些优化; 若是你对业务和程序都须要有深度掌控的话,我很推荐此方法,它可使你以管理 Node.js 程序的方式管理应用。
具体的优化方法是使用了一个叫idle-gc
的垃圾回收模块来优化内存管理,
idle-gc
是在node早期版本中被废除的功能,主要负责空闲时的堆内存回收,而后早期被认为有 BUG,常常会致使 CPU 满载,因而从 Node.js 中移除了,此项目做者修复了这个 BUG,并发布了模块。
另外,若是机器配置足够,建议开启缓存,即cache
选项,且适当往大的配置,cache 的意义在于使用内存常驻来减轻 CPU 的计算压力,这对于单线程的 Node.js 是很好的业务实践。
最新更新:已再也不使用此模块,最终靠 [ 优化业务逻辑 ] + [ 优化页面结构和抽象粒度 ] + [ 升级硬件 ] 来解决了问题。
这是 PM2 监控进程的平常数据之一:
移动版本适配问题
几乎全部的搜索引擎对于 PC 和移动端业务都是分开的,因此咱们能够巧妙地使用layouts
布局模块来实现咱们移动端和 PC 端业务的分离; 在个人博客项目里,因为业务逻辑和页面均不够复杂,故使用了 CSS3 媒体查询 + 组件内判断的形式实现了移动端的适配。
Route自定义meta问题
目前 API 中对 router 的支持不够全面,如自定义的配置都还没法实现,不过能够经过宿主组件对应周期的hook
来实现对实例化后的 router 对象进行修改和管理,尽管这不够优雅。
Window问题
因为 Vue 的底层使用 Virtual DOM,因此 Nuxt.js 在 Node.js 环境中的编译其实是对象计算为字符串的过程,并无依赖 Window/Dom,或者说任何基于 Vue 的 SSR 程序均如此。
咱们在实际生产时可能用到一些须要依赖 DOM 的插件/扩展,正确的方法是根据官方文档 - 只在浏览器里使用的插件推荐的方法,经过变量判断插件/扩展的应用环境, 这里有实践代码,或者使用SSR版本的组件,如:vue-awesome-swiper, 或自行封装directive
类型的插件,而非component
, 切记不要使用jsdom
等相似 Node.js 中的 DOM 库,这类库自己是为爬虫或测试诞生的,且自己会占据大量的内存,这不是真正的解决方案!
有关更多经常使用使用问题,能够参考官方解答。
最后:这是个人博客,也是一个完整的 Nuxt.js 程序,源码在这里。
如有差池,期待指正
完