Vue.js 是一个构建用户界面的渐进式框架,它可以帮助开发者快速构建出高质量的应用程序。Vue.js 允许开发者使用 JavaScript 和 HTML 来创建动态的 Web 应用程序,而不需要使用其他语言。Vue.js 还允许开发者使用服务端渲染来实现服务端渲染(SSR)。
服务端渲染是一种将客户端代码部署到服务器上的方法,以便在浏览器中运行。它可以帮助开发者在服务器上生成 HTML 页面,而不是在浏览器中生成 HTML 页面。这样就可以减少浏览器中的 JavaScript 的执行时间,并且能够在服务噮上处理大量数据。
Vue.js 支持 SSR 的方法是通过 vue-server-renderer 库来实现的。vue-server-renderer 是一个 Node.js 库,它允许开发者将 Vue 组件渲染为字符串,然后将其传递到浏览器中显示。vue-server-renderer 也允许开发者使用 Node.js 中间件来处理请求/响应循环,并将 Vue 组件注入到 HTML 页面中。
const renderer = require('vue-server-renderer').createRenderer() const context = { title: 'Hello' } renderer.renderToString(context, (err, html) => { if (err) throw err; console.log(html); //Hello World})
此外,Vue 还包含了一个 Nuxt.js 框架,该框架支持 SSR 功能。Nuxt.js 是一个 Vue 的应用程序开发工具包,它包含了所有必要的工具来快速开始一个新的 Vue 项目。Nuxt.js 还包含了一些特性来帮助开发者快速部署 SSR 功能:例如内部代理、内部 API 服务、内郹数据库连接、内郹 CSS 预处理噤、内郹代理、内郹 Webpack 配置文件、内郹 Babel 配置文件、内郹 ESLint 配置文件、内郹 TypeScript 配置文件、内郹 Pug/Jade/Handlebars/Markdown 等语法高亮显示工具。
在开始服务端渲染前,我们先看看它能给我们带来什么,以及什么时候需要用它。
谷歌和Bing可以很好地索引同步的JavaScript应用。同步在这里是个关键词。如果应用启动时有一个加载动画,然后内容通过ajax获取,那爬虫不会等待他们加载完成。
这意味着在异步获取内容的页面上很需要进行搜索引擎优化的时候,服务端渲染就很重要。
用户可能在网络比较慢的情况下从远处访问网站 - 或者通过比较差的带宽。这些情况下,尽量减少页面请求数量,来保证用户尽快看到基本的内容。
可以用Webpack的代码拆分避免强制用户下载整个单页面应用,但是,这样也远没有下载个单独的预先渲染过的HTML文件性能高。
对于世界上的一些地区人,可能只能用1998年产的电脑访问互联网的方式使用计算机。而Vue只能运行在IE9以上的浏览器,你可以也想为那些老式浏览器提供基础内容 - 或者是在命令行中使用 Lynx的时髦的黑客。
如果你只是用服务端渲染来改善一个少数的营销页面(如 首页,关于,联系 等等)的SEO,那你可以用预渲染替换。预渲染不像服务器渲染那样即时编译HTML,预渲染只是在构建时为了特定的路由生成特定的几个静态页面。其优势是预渲染的设置更加简单,可以保持前端是一个完整的静态站。
你用webpack可以很简单地通过prerender-spa-plugin来添加预渲染,它被广泛地用在Vue应用上 - 事实上,创建者也是Vue核心团队成员之一。
准备在行动中体验服务端渲染吧。服务端渲染(即SSR)听起来很复杂,不过一个简单的Node脚本只需要3步就可以实现这个功能:
// 步骤 1:创建一个Vue实例
var Vue = require("vue")
var app = new Vue({
render: function (h) {
return h("p", "hello world")
}
})
// 步骤 2: 创建一个渲染器
var renderer = require("vue-server-renderer").createRenderer()
// 步骤 3: 将 Vue实例 渲染成 HTML
renderer.renderToString(app, function (error, html) {
if (error) throw error
console.log(html)
// => <p server-rendered="true">hello world</p>
})
这并不困难。当然这个示例比大部分应用都简单。我们不必担心:
这个指南的其余部分,我们将探讨这些功能怎样运作。一旦你理解了基础,我们会提供更多细节和进一步的示例来帮助你解决意外情况。
如果没有一个Web服务器,很难说是服务端渲染,所以我们来补充它。我们将构建一个非常简单的服务端渲染应用,只用ES5,也不带其他构建步骤或Vue插件。
启动一个应用告诉用户他们在一个页面上花了多少时间。
new Vue({
template: "<div>你已经在这花了 {{ counter }} 秒。</div>",
data: {
counter: 0
},
created: function () {
var vm = this
setInterval(function () {
vm.counter += 1
}, 1000)
}
})
为了适应服务端渲染,我们需要进行一些修改,让它可以在浏览器和Node中渲染:
实现这个需要一点模板:
// assets/app.js
(function () { "use strict"
var createApp = function () {
// ---------------------
// 开始常用的应用代码
// ---------------------
// 主要的Vue实例必须返回,并且有一个根节点在id "app"上,这样客户端可以加载它。
return new Vue({
template: "<div id="app">你已经在这花了 {{ counter }} 秒。</div>",
data: {
counter: 0
},
created: function () {
var vm = this
setInterval(function () {
vm.counter += 1
}, 1000)
}
})
// -------------------
// 结束常用的应用代码
// -------------------
}
if (typeof module !== "undefined" && module.exports) {
module.exports = createApp
} else {
this.app = createApp()
}
}).call(this)
现在有了应用代码,接着加一个 html文件。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>My Vue App</title>
<script src="/assets/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script src="/assets/app.js"></script>
<script>app.$mount("#app")</script>
</body>
</html>
主要引用assets文件夹中我们先前创建的app.js,以及vue.js文件,我们就有了一个可以运行的单页面应用
然后为了实现服务端渲染,在服务端需要加一个步骤。
// server.js
"use strict"
var fs = require("fs")
var path = require("path")
// 定义全局的Vue为了服务端的app.js
global.Vue = require("vue")
// 获取HTML布局
var layout = fs.readFileSync("./index.html", "utf8")
// 创建一个渲染器
var renderer = require("vue-server-renderer").createRenderer()
// 创建一个Express服务器
var express = require("express")
var server = express()
// 部署静态文件夹为 "assets"文件夹
server.use("/assets", express.static(
path.resolve(__dirname, "assets")
))
// 处理所有的Get请求
server.get("*", function (request, response) {
// 渲染我们的Vue应用为一个字符串
renderer.renderToString(
// 创建一个应用实例
require("./assets/app")(),
// 处理渲染结果
function (error, html) {
// 如果渲染时发生了错误
if (error) {
// 打印错误到控制台
console.error(error)
// 告诉客户端错误
return response
.status(500)
.send("Server Error")
}
// 发送布局和HTML文件
response.send(layout.replace("<div id="app"></div>", html))
}
)
})
// 监听5000端口
server.listen(5000, function (error) {
if (error) throw error
console.log("Server is running at localhost:5000")
})
这样就完成了。整个示例,克隆下来深度实验。一旦它在本地运行时,你可以通过在页面右击选择页面资源(或类似操作)确认服务选渲染真的运行了。可以在body中看到:
<div id="app" server-rendered="true">You have been here for 0 seconds.</div>
代替:
<div id="app"></div>
Vue还支持流式渲染,优先选择适用于支持流的Web服务器。允许HTML一边生成一般写入相应流,而不是在最后一次全部写入。其结果是请求服务速度更快,没有缺点!
为了使上一节应用代码适用流式渲染,可以简单的替换 server.get("*",...)为下面的代码:
// 拆分布局成两段HTML
var layoutSections = layout.split("<div id="app"></div>")
var preAppHTML = layoutSections[0]
var postAppHTML = layoutSections[1]
// 处理所有的Get请求
server.get("*", function (request, response) {
// 渲染我们的Vue实例作为流
var stream = renderer.renderToStream(require("./assets/app")())
// 将预先的HTML写入响应
response.write(preAppHTML)
// 每当新的块被渲染
stream.on("data", function (chunk) {
// 将块写入响应
response.write(chunk)
})
// 当所有的块被渲染完成
stream.on("end", function () {
// 将post-app HTML写入响应
response.end(postAppHTML)
})
// 当渲染时发生错误
stream.on("error", function (error) {
// 打印错误到控制台
console.error(error)
// 告诉客服端发生了错误
return response
.status(500)
.send("Server Error")
})
})
这不比之前的版本复杂,甚至这对你来说都不是个新概念。我们做了:
Vue的服务端渲染默认非常快,但是你可以通过缓存渲染好的组件进一步提高性能。这被认为是一种先进的功能,但是,如果缓存了错误的组件(或者正确的组件带有错误的内容)将导致应用渲染出错。特别注意:
不应该缓存组件包含子组件依赖全局状态(例如来自vuex的状态)。如果这么做,子组件(事实上是整个子树)也会被缓存。所以要特别注意带有slots片段或者子组件的情况。
在警告情况之外的,我们可以用下面的方法缓存组件。
首先,你需要提供给渲染器一个 缓存对象。这有个简单的示例使用 lru-cache
var createRenderer = require("vue-server-renderer").createRenderer
var lru = require("lru-cache")
var renderer = createRenderer({
cache: lru(1000)
})
这将缓存高达1000个独立的渲染。对于更进一步缓存到内容中的配置,看lru-cache设置
然后对于你想缓存的组件,你可以为他们提供:
例如:
Vue.component({
name: "list-item",
template: "<li>{{ item.name }}</li>",
props: ["item"],
serverCacheKey: function (props) {
return props.item.type + "::" + props.item.id
}
})
任何纯组件可以被安全缓存 - 这是保证给任何组件传递一样的数据产生相同的HTML。这些场景的例子包括:
现在,应该理解服务端渲染背后的基本概念了。但是,构建过程、路由、Vuex每一个都有自己的注意事项。
要真正掌握复杂应用下的服务端渲染,我们推荐深度熟悉以下资源:
监听事件可以用v-on指令监听 DOM 事件来触发一些 JavaScript 代码。示例:div id="example-1"button v-on:click="counter += 1"...
稳定性: 2 - 不稳定流用于处理Node.js中的流数据的抽象接口,在Node里被不同的对象实现。例如,对HTTP服务器的请求是流,process...
稳定性: 2 - 不稳定Node.js域包含了能把不同的IO操作看成单独组的方法。如果任何一个注册到域的事件或者回调触发error事件,或者...
MongoDB是一种文档导向数据库管理系统,由C++撰写而成。本章节我们将为大家介绍如何使用 Node.js 来连接 MongoDB,并对数据库进...
关于术语的一点说明:请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块...
简介这篇指南的目的是教你如何书写高质量的TypeScript声明文件。 我们在这里会展示一些API的文档,还有它们的使用示例, 并且阐...
TypeScript是由微软开发的自由和开源的编程语言。TypeScript是JavaScript的一个超集,从今天数以百万计的JavaScript开发者所熟悉...
1. RegExp 构造函数在 ES5 中, RegExp 构造函数的参数有两种情况。第一种情况是,参数是字符串,这时第二个参数表示正则表达式...
1. 概述Reflect 对象与Proxy 对象一样,也是 ES6 为了操作对象而提供的新 API。 Reflect 对象的设计目的有这样几个。(1) 将 Ob...