自JavaScript诞生以来,前端技术发展很是迅速。移动端白屏优化是前端界面体验的一个重要优化方向,Web 前端诞生了 SSR 、CSR、预渲染等技术。css
十年前,几乎全部网站都使用 ASP、Java、PHP 这类作后端渲染,但后来随着 jQuery、Angular、React、Vue 等 JS 框架的崛起,开始转向了前端渲染。2014年起又兴起了同构渲染,号称是将来,集成了先后端渲染的优势,当真如此?html
咱们先明确三个概念:前端
后端渲染:后端渲染指传统的 ASP、Java 或 PHP 的渲染机制;vue
CSR:前端渲染 指使用 JS 来渲染页面大部份内容,表明是如今流行的 SPA 单页面应用;node
同构渲染:指先后端共用 JS,首次渲染时使用 Node.js 来直出 HTML。通常来讲同构渲染是介于先后端中的共有部分webpack
以及经常使用性能测试时间点ios
在前端渲染领域,主要有如下几种方式可供选择:git
CSR | 预渲染 | SSR | 同构 | |
---|---|---|---|---|
优势 |
|
|
|
|
缺点 |
|
|
|
|
由上表格可得知,各类渲染模式优缺点各异,看起来并无那么完美的解决方案,咱们只能依据自身产品需求,选择最适合咱们的渲染方案。github
一、一个优秀的产品 ,离不开SEO,它包含了不少方面的知识,通常公司都会配置专门的SEO职位, 毕竟有太多事情要作了。而咱们做为一个有追(破 )求(不)完(得)美(已)的前端,在开发的时候,须要作好页面结构科学、标签语义化、站点路由精简、提供必要的爬虫信息(如 Robot.txt,Sitemap,标签 role,ref 等等);然而在现实中CSR大行其道,SPA站点更是数不胜数,用户体验获得了质的提高,然而,然而,为了兼顾SEO,开发者不得不为爬虫提供专门的shadowsite,或者本身顶起下载本身的页面提供给爬虫,或者使用SSR,刀耕火种的年代。。。web
二、首屏渲染速度
目前先后端的分离的前端项目须要先加载静态资源,再异步获取数据,最后渲染页面,在这个过程当中的前两部页面都是没有数据的,影响了首屏的渲染速度,也就影响了用户的体验。 目前对于首屏渲染速度的提高有许多方案,在ssr以外还有龙骨,墓碑,数据直出。相比于这些方案ssr方案实现是最复杂的,但效果也是最好的。
三、方案选择
vue 中作同构,有两种,一种是基于官方Vue SSR指南推荐的SSR,一种是vueJS通用应用框架 NUXT.
官网方案,能够更直接的控制应用程序,更深刻底层,也比较灵活。NUXT,你懂得,就是那种你拿来即用的效果,提供了部分额外功能,e.g. 静态站点,可用于快速实现Vue SSR
SSR和预渲染的使用场景仍是有比较明显的区别的,预渲染的使用场景更多的是咱们所说的静态页面的形式。而SSR适用于大型的。页面数据处理较多且较为复杂、与服务端有数据交互的功能性网站,一个明显的使用场景就是电商网站
今天为你们介绍的这个,是部分同构方案,开始。。。
从官网借来的图可知,SSR有两个入口文件,entry-client和entry-server两个文件,都包含了应用代码,webpack会根据这两个入口文件分别打包成给服务端用的,Server Bundle及客户端使用的Client Bundle ,当服务器接收到了来自客户端的请求以后,会建立一个渲染器 bundleRenderer,这个 bundleRenderer 会读取上面生成的 server bundle 文件,而且执行它的代码, 而后发送一个生成好的 html 到浏览器,等到客户端加载了 client bundle 以后,会和服务端生成的DOM 进行 Hydration (判断这个 DOM 和本身即将生成的 DOM 是否相同,若是相同就将客户端的Vue实例挂载到这个 DOM 上, 不然会提示警告)。
而在vue服务器端渲染时,就不能只是使用web-dev-server和web-hot-middle了,由于咱们须要添加服务器渲染的node代码逻辑,这样,咱们能够本身开一个node服务器,使用webpack-dev-middle中间件进行打包、使用webpack-hot-middle中间件进行热更新,并添加服务器端渲染逻辑,即node端经过引入vue-serverer-renderer插件来渲染服务器端打包的bundle文件到客户端。
因此在项目开发期间,其实咱们是运行着两个node服务,一个作代理服务,一个提供ssr和其余的一些服务。
一、client-server的做用:
二、entry-server的做用:
createBundleRenderer
,这里会检查组件是否有 asyncData 方法,而后下一步
二、因为在node环境中,没法用webpack进行CSS文件处理,因此在配置文件中咱们须要对服务端渲染时,进行CSS白名单处理
1 externals: TARGET_NODE? nodeExternals({whitelist: [/\.css$/] }):undefined
三、咱们从打包出来的代码中能够看到,是vue-ssr-server-bundle.json,而很是规的JS文件。这是由于node环境下,每次打包成js文件,你得考虑node的热部署,而且node环境也不支持sourcemap,因此引入了 vue-server-renderer 组件,这种方式相似于常规的render,支持热部署,支持source map ,在配置文件中,咱们配置了该组件下的服务端渲染插件,可使得服务端渲染输出的是json文件。
四、
在CSR模式下,咱们开发过程当中会进行热部署,这样会大大提升工做效率。
1 let bundle 2 serverCompiler.watch({}, (err, stats) => { 3 if (err) { 4 throw err 5 } 6 stats = stats.toJson() 7 stats.errors.forEach(error => console.error(error)) 8 stats.warnings.forEach(warn => console.warn(warn)) 9 const bundlePath = path.join( 10 webpackConfig.output.path, 11 'vue-ssr-server-bundle.json' 12 ) 13 bundle = JSON.parse(mfs.readFileSync(bundlePath, 'utf-8')) 14 console.log('new bundle generated') 15 })
一、服务器预获取数据的异常处理,参考上面的entry-server中所说,让客户端主动获取数据,再次尝试渲染
二、在服务端数据预获取的生命周期结束后的渲染页面过程当中出现的异常,包括各类操做数据的语法错误等,如对undefined取属性。编写过程要注意全局环境下的代码,是否试用,作环境判断。
虽然 Vue 的服务器端渲染(SSR)至关快速,可是因为建立组件实例和虚拟 DOM 节点的开销,没法与纯基于字符串拼接(pure string-based)的模板的性能至关。在 SSR 性能相当重要的状况下,明智地利用缓存策略,能够极大改善响应时间并减小服务器负载,这是一个取舍的过程。vue服务区缓存分为页面缓存、组建缓存和接口缓存;
将渲染完成的页面缓存到内存中,同时设置最大缓存数量和缓存时间。 优点:大幅度提升页面的访问速度 代价:增长服务器内存的使用
1 const microCache = LRU({ 2 max: 100, // 最大缓存的数目 3 maxAge: 1000 // 重要提示:条目在 1 秒后过时。 4 }) 5 const isCacheable = req => { 6 // 判断是否须要页面缓存 7 if (req.url && req.url === '/') { 8 return req.url 9 } else { 10 return false 11 } 12 } 13 const handleRequest = async (ctx, next) => { 14 const req = ctx.req 15 const res = ctx.res 16 const cacheable = isCacheable(req) 17 if (cacheable) { 18 const hit = microCache.get(res.url) 19 if (hit) { 20 return res.end(hit) 21 } 22 } 23 ... 24 ... 25 }
使用较少,本次并未涉及
将通用的接口缓存到内存,减小服务端接口请求的时间
get (url, params = {}) { // url = baseUrl + '/sa' + url url = baseUrl + url const key = md5(url + JSON.stringify(params)) // 判断是否有缓存,直接返回缓存结果 if (params.cache && microCache.get(key)) { return Promise.resolve(microCache.get(key)) } let Cookie = '' if (params.req && params.req.headers && params.req.headers.cookie) { Cookie = params.req.headers.cookie } return new Promise((resolve, reject) => { axios({ url, params, headers: { 'X-Requested-With': 'XMLHttpRequest', 'Cookie': Cookie }, method: 'get' }).then(res => { // 判断是否须要缓存 若是须要缓存缓存数据 if (params.cache && microCache) { microCache.set(key, res.data) } resolve(res.data) }).catch(error => { reject(error) }) }) },
咱们是否真正的须要作同构渲染,这取决因素有不少,主要有,SEO,首屏时间比较重要的产品可考虑。
运用该技术并无想象中的轻松,对前端开发有必定的要求,编写过程要谨慎,涉及构建设置和部署的更多要求,还须要更多的服务器端负载,总之,咱们可能须要的支持会更多一点。
Demo已上传至github,以供参考,如若对您有帮助,给个小星星仍是很开心的,传送门