vue 使用vue-vue cli dev serverr-renderer开发

这是一篇社区协同翻译的文章,已完成翻译,更多信息请点击
对于客户端应用来说,服务端渲染是一个热门话题。然而不幸的是,这并不是一件容易的事,尤其是对于不用 Node.js 环境开发的人来说。
我发布了两个库让 PHP 从服务端渲染成为可能. 和 适配 laravel
让我们一起来仔细研究一些服务端渲染的概念,权衡优缺点,然后遵循第一法则用 PHP 建立一个服务端渲染。
什么是服务端渲染
一个单页应用(通常也叫做 SPA )是一个客户端渲染的 App 。这是一个仅在浏览器端运行的应用。如果你正在使用框架,比如 React, Vue.js 或者
AngularJS ,客户端将从头开始渲染你的 App 。
lchola 翻译于 3个月前
浏览器的工作
在 SPA 被启动并准备使用之前,浏览器需要经过几个步骤。
下载 JavaScript 脚本
解析 JavaScript 脚本
运行 JavaScript 脚本
取回数据(可选,但普遍)
在原本的空容器渲染应用
(首次有意义的渲染)
准备完成! (可以交互啦)
用户不会看到任何有意义的内容,直到浏览器完全渲染 App(需要花费一点时间)。这会造成一个明显的延迟,直到
完成,从而影响了用户体验。
这就是为什么服务端渲染(一般被称作 SSR )登场的原因。SSR 在服务器预渲染初始应用状态。这里是浏览器在使用服务端渲染后需要经过的步骤:
渲染来自服务端的 HTML (首次有意义的渲染)
下载 JavaScript 脚本
解析 JavaScript 脚本
运行 JavaScript 脚本
使已存在的 HTML 页面可交互
准备完成! (可以交互啦)
由于服务器提供了 HTML 的预渲染块,因此用户无需等到一切完成后才能看到有意义的内容。注意,虽然
仍然处于最后,但可感知的表现得到了巨大的提升。
Littlesqx 翻译于 3个月前
浏览器需要做的工作
在 SPA 启动和准备使用之前,浏览器需要执行几个操作。
检索数据 (可选,但很常见)
在先前为空的容器中渲染应用 (第一个有意义的绘图)
准备好了! (交互时间)
在浏览器完全渲染完应用之前,用户看不到任何有意义的内容, 这会花一点时间! 这会在
之前产生一个明显的延迟,同时减去了一些用户体验。
这就是服务器端渲染 (通俗称为 SSR) 的地方。 SSR 在服务器上预渲染初始的应用状态。 以下是浏览器待执行的列表与服务器渲染相似的地方:
从服务器渲染传入的 HTML (第一个有意义的绘图)
使现有的 HTML 交互
准备开始! (交互时间)
由于服务器提供 HTML 的预渲染块,用户不再需要等到一切完成在看到有意义的内容。 请注意
还是处在行尾, 但 感知 体验得到巨大提升。
BradStev 翻译于 3个月前
服务端渲染的优点
服务端渲染的主要优点是可以提升用户体验。并且,如果你的网站需要应对不能执行 JavaScript 的老旧爬虫,SSR 将是必须的,这样,爬虫才能索引服务端渲染过后的页面,而不是一个空荡荡的文档。
服务端如何渲染?
记住服务端渲染并非微不足道,这一点很重要。当你的 Web 应用同时运行在浏览器和服务器,而你的 Web 应用依赖 DOM 访问,那么你需要确保这些调用不会在服务端触发,因为没有 DOM API 可用。
基础设施复杂性
假设你决定了服务端渲染你的应用端程序,你如果正在阅读这篇文章,很大可能正在使用 PHP 构建应用的大部分(功能)。但是,服务端渲染的 SPA 需要运行在 Node.js 环境,所以将需要维护第二个程序。
你需要构建两个应用程序之间的桥梁,以便它们进行通信和共享数据:需要一个 API。构建无状态 API 相比于构建有状态是比较 困难 的。你需要熟悉一些新概念,例如基于 JWT 或 OAUTH 的验证,CORS,REST ,添加这些到现有应用中是很重要的。
有得必有所失,我们已经建立了 SSR 以增加 Web 应用的用户体验,但 SSR 是有成本的。
Littlesqx 翻译于 3个月前
服务器端渲染权衡取舍
服务器上多了一个额外的操作。一个是服务器增加了负载压力,第二个是页面响应时间也会稍微加长。 不过因为现在服务器返回了有效内容,在用户看来,第二个问题的影响不大。
大部分时候你会使用 Node.js 来渲染你的 SPA 代码。如果你的后端代码不是使用 Javascript 编写的话,新加入 Node.js 堆栈将使你的程序架构变得复杂。
为了简化基础架构的复杂度, 我们需要找到一个方法,使已有的 PHP 环境作为服务端来渲染客户端应用。
在 PHP 中渲染 JavaScript
在服务器端渲染 SPA 需要集齐以下三样东西:
一个可以执行 JavaScript 的引擎
一个可以在服务器上渲染应用的脚本
一个可以在客户端渲染和运行应用的脚本
BradStev 翻译于 3个月前
SSR scripts 101
下面的例子使用了 Vue.js。你如果习惯使用其它的框架(例如 React),不必担心,它们的核心思想都是类似的,一切看起来都是那么相似。
简单起见,我们使用经典的 “ Hello World ” 例子。
下面是程序的代码(没有 SSR):
import Vue from 'vue'
template: `
&div&Hello, world!&/div&
el: '#app'
这短代码实例化了一个 Vue 组件,并且在一个容器(id 值为 app 的 空 div)渲染。
如果在服务端运行这点脚本,会抛出错误,因为没有 DOM 可访问,而 Vue 却尝试在一个不存在的元素里渲染应用。
重构这段脚本,使其 可以 在服务端运行。
import Vue from 'vue'
export default () =& new Vue({
template: `
&div&Hello, world!&/div&
// entry-client.js
import createApp from './app'
const app = createApp()
app.$mount('#app')
我们将之前的代码分成两部分。app.js 作为创建应用实例的工厂,而第二部分,即 entry-client.js,会运行在浏览器,它使用工厂创建了应用实例,并且挂载在 DOM。
现在我们可以创建一个没有 DOM 依赖性的应用程序,可以为服务端编写第二个脚本。
// entry-server.js
import createApp from './app'
import renderToString from 'vue-server-renderer/basic'
const app = createApp()
renderToString(app, (err, html) =& {
if (err) {
throw new Error(err)
// Dispatch the HTML string to the client...
我们引入了相同的应用工厂,但我们使用服务端渲染的方式来渲染纯 HTML 字符串,它将包含应用初始状态的展示。
我们已经具备三个关键因素中的两个:服务端脚本和客户端脚本。现在,让我们在 PHP 上运行它吧!
Littlesqx 翻译于 3个月前
执行 JavaScript
在 PHP 运行 JavaScript,想到的第一个选择是 V8Js。V8Js 是嵌入在 PHP 扩展的 V8 引擎,它允许我们执行 JavaScript。
使用 V8Js 执行脚本非常直接。我们可以用 PHP 中的输出缓冲和 JavaScript 中的 print 来捕获结果。
$v8 = new V8Js();
ob_start();
// $script 包含了我们想执行的脚本内容
$v8-&executeString($script);
echo ob_get_contents();
print('&div&Hello, world!&/div&')
这种方法的缺点是需要第三方 PHP 扩展,而扩展可能很难或者不能在你的系统上安装,所以如果有其他(不需要安装扩展的)方法,它会更好的选择。
这个不一样的方法就是使用 Node.js 运行 JavaScript。我们可以开启一个 Node 进程,它负责运行脚本并且捕获输出。
Symfony 的 Process 组件就是我们想要的。
use Symfony\Component\Process\P
// $nodePath 是可执行的 Node.js 的路径
// $scriptPath 是想要执行的 JavaScript 脚本的路径
new Process([$nodePath, $scriptPath]);
echo $process-&mustRun()-&getOutput();
console.log('&div&Hello, world!&/div&')
注意,(打印)在 Node 中是调用 console.log 而不是 print 。
Littlesqx 翻译于 3个月前
执行 JavaScript
在 PHP 运行 JavaScript,想到的第一个选择是 V8Js。V8Js 是嵌入在 PHP 扩展的 V8 引擎,它允许我们执行 JavaScript。
使用 V8Js 执行脚本非常直接。我们可以用 PHP 中的输出缓冲和 JavaScript 中的 print 来捕获结果。
$v8 = new V8Js();
ob_start();
// $script 包含了我们想执行的脚本内容
$v8-&executeString($script);
echo ob_get_contents();
print('&div&Hello, world!&/div&')
这种方法的缺点是需要第三方 PHP 扩展,而扩展可能很难或者不能在你的系统上安装,所以如果有其他(不需要安装扩展的)方法,它会更好的选择。
这个不一样的方法就是使用 Node.js 运行 JavaScript。我们可以开启一个 Node 进程,它负责运行脚本并且捕获输出。
Symfony 的 Process 组件就是我们想要的。
use Symfony\Component\Process\P
// $nodePath 是可执行的 Node.js 的路径
// $scriptPath 是想要执行的 JavaScript 脚本的路径
new Process([$nodePath, $scriptPath]);
echo $process-&mustRun()-&getOutput();
console.log('&div&Hello, world!&/div&')
注意,(打印)在 Node 中是调用 console.log 而不是 print 。
Littlesqx 翻译于 3个月前
让我们一起来实现它吧!
spatie/server-side-rendering 包的其中一个关键理念是 引擎 接口。引擎就是上述 JavaScript 执行的一个抽象概念。
namespace Spatie\S
* 创建引擎接口。
interface Engine
public function run(string $script):
public function getDispatchHandler():
run 方法预期一个脚本的输入 (脚本 内容,不是一条路径),并且返回执行结果。 getDispatchHandler 允许引擎声明它预期脚本如何展示发布。例如 V8 中的print 方法,或是 Node 中的 console.log 。
V8Js 引擎实现起来并不是很花俏。它更类似于我们上述理念的验证,带有一些附加的错误处理机制。
namespace Spatie\Ssr\E
use Spatie\Ssr\E
use Spatie\Ssr\Exceptions\EngineE
* 创建一个 V8 类来实现引擎接口类 Engine 。
class V8 implements Engine。
/** @var \V8Js */
protected $v8;
public function __construct(V8Js $v8)
$this-&v8 = $v8;
* 打开缓冲区。
* 返回缓冲区存储v8的脚本处理结果。
public function run(string $script): string
ob_start();
$this-&v8-&executeString($script);
return ob_get_contents();
} catch (V8JsException $exception) {
throw EngineError::withException($exception);
} finally {
ob_end_clean();
public function getDispatchHandler(): string
return 'print';
注意这里我们将 V8JsException 重新抛出作为我们的 EngineError。 这样我们就可以在任何的引擎视线中捕捉相同的异常。
Node 引擎会更加复杂一点。不像 V8Js,Node 需要 文件 去执行,而不是脚本内容。在执行一个服务端脚本前,它需要被保存到一个临时的路径。
namespace Spatie\Ssr\E
use Spatie\Ssr\E
use Spatie\Ssr\Exceptions\EngineE
use Symfony\Component\Process\P
use Symfony\Component\Process\Exception\ProcessFailedE
* 创建一个 Node 类来实现引擎接口类 Engine 。
class Node implements Engine
/** @var string */
protected $nodeP
/** @var string */
protected $tempP
public function __construct(string $nodePath, string $tempPath)
$this-&nodePath = $nodeP
$this-&tempPath = $tempP
public function run(string $script): string
// 生成一个随机的、独一无二的临时文件路径。
$tempFilePath = $this-&createTempFilePath();
// 在临时文件中写进脚本内容。
file_put_contents($tempFilePath, $script);
// 创建进程执行临时文件。
$process = new Process([$this-&nodePath, $tempFilePath]);
return substr($process-&mustRun()-&getOutput(), 0, -1);
} catch (ProcessFailedException $exception) {
throw EngineError::withException($exception);
} finally {
unlink($tempFilePath);
public function getDispatchHandler(): string
return 'console.log';
protected function createTempFilePath(): string
return $this-&tempPath.'/'.md5(time()).'.js';
除了临时路径步骤之外,实现方法看起来也是相当直截了当。
Wiki_Yao 翻译于 3个月前
我们已经创建好了 Engine 接口,接下来需要编写渲染的类。以下的渲染类来自于 spatie/server-side-rendering 扩展包,是一个最基本的渲染类的结构。
渲染类唯一的依赖是 Engine 接口的实现:
class Renderer
public function __construct(Engine $engine)
$this-&engine = $
渲染方法 render 里将会处理渲染部分的逻辑,想要执行一个 JavaScript 脚本文件,需要以下两个元素:
我们的应用脚本文件;
一个用来获取解析产生的 HTML 的分发方法;
一个简单的 render 如下:
class Renderer
public function render(string $entry): string
$serverScript = implode(';', [
"var dispatch = {$this-&engine-&getDispatchHandler()}",
file_get_contents($entry),
return $this-&engine-&run($serverScript);
此方法接受
entry-server.js 文件路径作为参数。
我们需要将解析前的 HTML 从脚本中分发到 PHP 环境中。dispatch 方法返回
Engine 类里的 getDispatchHandler 方法,dispatch 需要在服务器脚本加载前运行。
还记得我们的服务器端入口脚本吗?接下来我们在此脚本中调用我们的
dispatch 方法:
// entry-server.js
import app from './app'
import renderToString from 'vue-server-renderer/basic'
renderToString(app, (err, html) =& {
if (err) {
throw new Error(err)
dispatch(html)
Vue 的应用脚本无需特殊处理,只需要使用
file_get_contents 方法读取文件即可。
我们已经成功创建了一个 PHP 的 SSR 。spatie/server-side-rendering 中的完整渲染器 Renderer 跟我们实现有点不一样,他们拥有更高的容错能力,和更加丰富的功能如有一套 PHP 和 JavaScript 共享数据的机制。如果你感兴趣的话,建议你阅读下源码
Summer 翻译于 3个月前
三思而后行
我们弄清楚了服务器端渲染的利和弊,知道 SSR 会增加应用程序架构和基础结构的复杂度。如果服务器端渲染不能为你的业务提供任何价值,那么你可能不应该首先考虑他。
如果你 确实 想开始使用服务器端渲染,请先阅读应用程序的架构。大多数 JavaScript 框架都有关于 SSR 的深入指南。Vue.js 甚至有一个专门的 SSR ,解释了诸如数据获取和管理用于服务器端渲染的应用程序方面的坑。
如果可能,请使用经过实战检验的解决方案
有许多经过实战检验的解决方案,能提供很好的 SSR 开发体验。比如,如果你在构建 React 应用,可以使用 ,或者你更青睐于 Vue 则可用 ,这些都是很引人注目的项目。
田勇 翻译于 3个月前
还不够?尝试 PHP 服务端渲染
你仅能以有限的资源来管理基础架构上的复杂性。你想将服务端渲染作为大型 PHP 应用中的一部分。你不想构建和维护无状态的 API。 如果这些原因和你的情况吻合,那么使用 PHP 进行服务端渲染将会是个不错方案。
我已经发布两个库来支持 PHP 的服务端 JavaScript 渲染:
和专为 Laravel 应用打造的
。Laravel 定制版在 Laravel 应用中近乎 0 配置即可投入使用,通用版需要根据运行环境做一些设置调整。当然,详细内容可以参考软件包自述文件。
如果你仅是想体验,从
检出项目并参考指南进行安装。
如果你考虑服务端渲染,我希望这类软件包可以帮到你,并期待通过 Github 做进一步问题交流和反馈!
3en 翻译于 3个月前
原文地址:
译文地址:
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 ,如果我们的工作有侵犯到您的权益,请及时联系我们。
本帖已被设为精华帖!
附加内容, 使用此功能的话, 会给所有参加过讨论的人发送提醒.
<button class="btn btn-success popover-with-html"
data-toggle="modal" data-target="#payment-qrcode-modal" data-content="如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!可以修改个人资料「支付二维码」开启打赏功能。">
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
感觉现在好像没啥必要使用SSR了, SEO, 首屏载入时间(js按需加载)等 vue
页面少使用SSR也还接受, 如果页面很多,为了快速开发,
还不如直接用PHP来渲染前端
SEO 有什么方案呢?
SSR 是为了同构,以前 PHP 负责的页面交给了 JS 来做了,但是 JS 无法像以前 HTML 那样整合到后端,后端不能执行 JS,不过 Google 出了 V8,接着就有了 Node.js,因为 V8 的存在,其他语言也写了相应的扩展库,PHP 里的就是 V8JS 这个家伙,文中用到的扩展就是这个。
带来的意义就是可以 PHP 端执行 JS 了,解决前端 JS 写的 UI 组件整合到后端的问题。
之前我写过一个 execjs 的库,感兴趣可以看看,这里是 vue 的例子,比文章的清晰简洁。
现在有一个vue的应用需要seo
是 去读vue文档的ssr比较好呢
还是 用该文的php方式去处理呢
还是用服务区分爬虫和用户,用户正常走,爬虫走phantomjs解析后的..
ps:谷歌爬虫能爬虫js渲染后的页面..
其他任何搜索引擎都不行..
SEO问题控制器判断一下是否爬虫就可以了,没那么麻烦
我测试过了,这个根本不管用好吧,完全没用,我测试用node的js引擎一直在报错。并这个例子(spatie/laravel-server-side-rendering-examples)里面根本就没有过后端的引擎!!请楼主检查下
暂无评论~~
您需要登陆以后才能留下评论!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
请使用微信扫描二维码。
将托管在 packagist.org 和 github.com 的扩展包使用国内 CDN 加速
下载量最高的 100 个 Laravel 扩展包推荐
Lumen 是为速度而生,专注于构建无状态 API 的 Laravel 精简版
速查表方便快速查询框架功能,支持手机访问,支持中英文版本
Laravel 中文文档,由社区用户翻译和维护,将会保持一直更新
此文档的目的,就是为了提高技术团队的凝聚力、一致性和生产效率。
开发环境的部署,开发者工具的选择,适用于 Mac 和 Windows。
Lumen 中文文档,由社区用户翻译和维护,将会保持一直更新
GraphQL PHP 项目的中文文档,教你如何开发 GraphQL API 接口
一些撰写文档的技巧和思路,一个教你写出好文档的文档。
本系列文章为 laracasts.com 的系列视频教程的课程笔记
PSR 是由 PHP FIG 组织制定的 PHP 规范,是 PHP 开发的实践标准。
设计模式是 PHP 架构师必备知识,本文档完整收录了 PHP 相关的设计模式。
Laravel 下知名扩展包 Dingo API 的中文文档,Laravel API 开发必知必会新人专享好礼凡未购买过小册的用户,均可领取三张 5 折新人专享券,购买小册时自动使用专享券,最高可节省 45 元。小册新人 5 折券最高可省 15 元小册新人 5 折券最高可省 15 元小册新人 5 折券最高可省 15 元注:专享券的使用期限在领券的七天内。一键领取购买小册时自动使用专享券前往小册首页本活动仅适用于小册新用户知道了使用 Vue2.0 + vue-server-renderer 案例之 豆瓣读书原文链接:
vue.js 2.0, vuex, vue-router, vue-server-renderer,
express, cheerio, superagent, redis
#redis-server
redis-server &
# install dependencies
npm install
# serve with hot reload at localhost:4000
npm run dev
# init data
curl http://host:port/api/spider // 更替换成真实地址和端口号
# build for production with minification
npm run build && npm start
请确认 redis 是 start 状态
在浏览器中访问
目前完成的界面: 首页, 读书首页, 标签页, 列表页, 详情页
增加了搜索功能,优化了排版, 但是豆瓣没有评论接口,所以只能等日后写爬虫解决
在2.0中 Vue.set(store.item, item) 不会触发更新dom, store.item = item 才可以
由于 server side render 的原因, 不能使用 vue-resource 了, 改用 superagent 发请求了
store.item 为{}时, 在页面中引用 会直接error, 需要指定详细数据类型
v-html 替换了 &&{&&}
webpack出现了 mdzz 的错误 Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
解决办法为:
$ npm uninstall webpack --save-dev
followed by
$ npm install webpack@2.1.0-beta.22 --save-dev
Then you should be able to gulp again. Fixed the issue for me.
然后 npm run dev 即可, 蜜汁玄学
&& n && // 需要指定n
&& $index && // 需要显示声明$index
上面的 bug 已经被 尤大 fixed
根据 i5ting 前辈的建议, 更改了目录结构
├── README.md
├── build
├── index.html
├── server.js
├── frontend
├── App.vue
├── app.js
├── assets
├── client-entry.js
├── components
├── router
├── server-entry.js
├── store
└── views
├── backend
├── spiders
└── routers
├── node_modules
├── package.json
├── public
└── test
相关热门文章分享vue-server-renderer 文档翻译 - 简书
vue-server-renderer 文档翻译
vue-server-renderer
用于 Vue2.0 的服务端渲染
这个包是自动生成的。如果你想合并请求请看 GigHub 上的
这个包提供了基于 Node.js 的 Vue2.0 服务端渲染。
&a name="installation" href="#installation"&安装&/a&
npm install vue-server-rederer
&a name="api" &API&/a&
createRenderer([rendererOptions])
创建一个randerer实例。
const renderer = require('vue-server-renderer').createRenderer();
renderer.renderToString(vm,cb)
渲染一个string类型的 Vue 实例。它的回调函数是第一个参数为接受到的error对象的标准 Node.js 的回调函数形式。
const Vue = require('vue')
const renderer = require('vue-server-renderer').createRenderer()
const vm = new Vue({
render (h) {
return h('div', 'hello')
renderer.renderToString(vm, (err, html) =& {
console.log(html) // -& &div server-rendered="true"&hello&/div&
renderer.renderToStream(vm)
渲染一个流模式的 Vue 实例。返回一个 Node.js 的可读流。
// 使用 express 的一个例子
app.get('/', (req, res) =& {
const vm = new App({ url: req.url })
const stream = renderer.renderToStream(vm)
res.write(`&!DOCTYPE html&&html&&head&&title&...&/title&&/head&&body&`)
stream.on('data', chunk =& {
res.write(chunk)
stream.on('end', () =& {
res.end('&/body&&/html&')
createBundleRenderer(code,[rendererOptions])
通过预打包应用程序代码(请看)来创建一个bundleRenderer实例。对于每一次渲染调用,使用 Node.js 的 vm 模块实现代码在新的上下文中重新执行。这确保了你的应用程序状态是在请求之间是相互隔离的,并且你不用担心为了服务端渲染而在一个限制模式下构建你的应用。
const bundleRenderer = require('vue-server-renderer').createBundleRenderer(code)
bundleRenderer.renderToString([context],cb)
渲染一个string类型的打包好的应用。和renderer.renderToString相同的回调接口。这个上下文参数对象将会传递给打包的输出函数。
bundleRenderer.renderToString({ url: '/' }, (err, html) =& {
bundleRenderer.renderToString([context])
渲染一个流模式的打包好的应用。和renderer.renderToStream想用的流式接口。这个上下文对象将会传递给打包的输出函数。
bundleRenderer
.renderToStream({ url: '/' })
.pipe(writableStream)
&a name="renderer-options"&Renderer 选项&/a&
允许你提供一些自定义指令用于服务端渲染的实现。
const renderer = createRenderer({
directives: {
example (vnode, directiveMeta) {
// transform vnode based on directive binding metadata
// 基于绑定元数据的指令转化 vnode
还有一个例子,。
提供了一种的实现。这个缓存对象必须实现下面的接口:
get: (key: string, [cb: Function]) =& string | void,
set: (key: string, val: string) =& void,
has?: (key: string, [cb: Function]) =& boolean | void // optional
一个典型的应用是传一个 :
const LRU = require('lru-cache')
const renderer = createRenderer({
cache: LRU({
max: 10000
注意,缓存对象至少应该设置get和set。另外,get方法如果提供了第二个参数作为回调函数那么还可以选择异步使用。这允许缓存使用异步APIs,例如redis client 例子:
const renderer = createRenderer({
get: (key, cb) =& {
redisClient.get(key, (err, res) =& {
// handle error if any
set: (key, val) =& {
redisClient.set(key, val)
&a name="why-use-bundlerrenderer"&为什么使用 bundleRenderer?&/a&
在一个典型的 Node.js 应用中,后端服务是一个长时间运行的进程。如果我们直接请求我们的应用代码,实例化模块将会在每个请求中共享。这带了一些不方便的限制在我们构建时:比如我们必须避免使用全局状态单例(例如:Vuex里面的store),否则每一次状态改变都会导致下一次请求被影响。
相反,bundleRenderer更容易保证我们的每一个请求在运行的应用程序中都是“新的”(即实例化模块不共享),这样我们不需要去考虑通过每次请求避免状态污染的问题了。这些都是bundleRenderer帮助我们实现的。
&a name="creating-the-server-bundle"&服务端打包生成&/a&
服务端打包生成
应用程序的打包可以通过任何构建工具生成,你可以使用很简单的 Webpack + vue-loader 还有 bundleRenderer实现。你需要使用略微不同的 webpack 配置和为了服务端渲染的入口文件,但是这个不同是很小的:
为你的 webpack 配置添加 target:'node' 和 output:{libraryTarget:'commonjs2'} 。这可能是一个比较好的处理你的外部依赖文件的方法。
在你的服务端入口文件抛出一个方法。这个方法将会接收到渲染的上下文对象(传递给bundleRenderer.renderToString 或者 bundleRenderer.renderToStream),并且返回一个Promise,这将最终解决应用程序 Vue 根实例的问题。
// server-entry.js
import Vue from 'vue'
import App from './App.vue'
const app = new Vue(App)
// 默认的输出应该是一个接收渲染调用时上文对象的函数。
export default context =& {
// data pre-fetching
return app.fetchServerData(context.url).then(() =& {
return app
我们在使用bundleRenderer时,最好在服务端打包时通过默认的打包方式把每一个依赖文件打进我们的应用程序。这意味着在每次请求那些依赖文件时将需要解析和运行一遍,但是在大多数情况下这些是不需要的。
我们能够通过你打的包来优化这些外部依赖关系。在渲染过程中,任何原始的require()调用都将返回实际的 Node 模块从你的渲染进程中。使用 webpack ,我们可以很简单的通过externals配置选项来列举出那些我们想要处理的外部依赖模块。
// webpack.config.js
module.exports = {
// 这些外部依赖中的所有模块都在你的package.json文件中的 “dependencies” 下面
externals: Object.keys(require('./package.json').dependencies)
由于外部依赖模块在每个请求中是共享的,所以你必须保证这些依赖关系是等同的。这样,通过不同的请求应该总是返回相同的结果,并且它不能拥有通过你的应用程序来改变的全局状态(如:使用 Vue 插件)。
&a name="component-caching"&组件缓存&/a&
你可以容易的通过serverCacheKyy函数来在服务端渲染中来缓存组件:
export default {
name: 'item', // required
props: ['item'],
serverCacheKey: props =& props.item.id,
render (h) {
return h('div', this.item.id)
注意缓存组件必须配置唯一的“name”选项。这对于 Vue 在使用打包渲染时确定组件的身份来说是必须的。
使用唯一的名字来作为缓存组件的的键名:你不用担心两个组件返回相同的键。一个缓存组件的键名应该包含足够的信息来表述它渲染的结果。上面的这种方式是一种很好的实现如果这个渲染结果可以通过props.item.id能完全确定。然而,这个组件随着时间的推移原本的 ID 可能会改变,或者渲染结果还依赖另一个prop,这样你需要去修改你的getCacheKey来实现获取其他的变量在程序中。
返回一个常数总会被缓存,这对于纯粹的静态组件来说是很好的。
什么时候使用组件缓存?
如果渲染器在渲染期间渲染了一个组件,它将直接为真个子树重用缓存结果。所以不要缓存包含全局状态的子组件。
在大多数情况下,你不应该和不需要缓存简单的实例组件。最常见的组件缓存需要大名单。由于这些组件通常是一些由数据库中的对象集合驱动的,他们可以使用一些简单的缓存策略。生成它们的缓存键名使用它们自己的唯一ID加最后更新的时间戳。
serverCacheKey: props =& props.item.id + '::' + props.item.last_updated
&a name="client-side-hydration"&客户端合成&/a&
在服务端渲染输出,根元素将会有一个server-rendered=true的属性标记。在客户端,当你使用这个属性挂载一个 Vue 实例到元素上时,它将尝试合成到现有的DOM实例而不是创建新的DOM节点。
在开发模型中,Vue 将维护客户端生成的虚拟DOM树来匹配来自服务端渲染的DOM结构。如果不匹配,它将放弃合成,维持现有DOM并且从头开始渲染。在生产模型下,这种维护是被禁用的为了更高的性能。
有一些事情需要特别注意,当使用服务端渲染+客户端合成一些特殊HTML结构时,浏览器可能会改变HTML结构。比如,当你写下面这个样的Vue实例的时候:
&tr&&td&hello word&/td&&/tr&
浏览器会自动添加tbody到table中,然而,Vue生成的虚拟DOM不会包含tbody,所以将会导致不匹配。为了确保正确的匹配,请准确书写有效的HTML在你的模板中。
本文为个人在学习 Vue 服务端渲染时,翻译自的README文档,本人初学 Vue 能力有限,翻译有误地方请大家指出。
另外,如果想学习Vue官方的服务端渲染的例子和的例子,而又对各种webpack配置和英文注释有些迷茫,可以看一下我对官方和一个注释版本,根据自己的理解加的注释。当然个人能力有限,可能有些地方理解有误,还请谅解
时而绅士,时而疯癫。彬彬有礼,待人谦和;谈吐自然,温文尔雅,有理想,有信念,社会主义好青年。这只是第一印象而已,一旦我们成了朋友,哼哼哼…
(译) 使用 Vue.js 和 Axios 从第三方 API 获取数据 — SitePoint - 前端 - 掘金更多的往往不是,建立你的JavaScript应用程序时,你会想把数据从远程源或消耗一个[ API ](https:/ /恩。维基百科。org /维基/ appl...
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
转载 :OpenDiggawesome-github-vue 是由OpenDigg整理并维护的Vue相关开源项目库集合。我们会定期同步OpenDigg上的项目到这里,也欢迎各位提交项目给我们。 如果收录的项目有错误,可以通过issue反馈给我们。这里的项目Star数不是实时...
去美丽的丽江古城来个难忘的艳遇 去风景优美的鼓浪屿感受一下海风轻拂你的脸颊 去古老悠久的罗马体会一下浓厚的浪漫气息 背上行囊 挎上单方 和最好的闺蜜 来一场说走就走的旅行吧! 亲爱的
你的生活不止眼前的苟且
还有诗和远方…
浑浑噩噩。一个人呆在图书馆。闷的感觉快要窒息。下楼,看到他们,最终还是转身走了。毕竟,已形同陌路。再去又有何意义呢。餐厅,没有丝毫胃口。一碗很咸的蛋汤,满足了可怜的胃,咸的嗓子痛,更不想说一句话。还好,温暖了胃,让心也感觉没有那么孤单了。 低沉。像是曾被压抑的那个真实的我突...
阿蛮的父母和小萝的父母是很好的朋友。阿蛮的父母和小萝父母大学是好友,毕业后小萝的爸爸和阿蛮的爸爸没有去找工作而是开起了自己的公司。阿蛮的爸爸本就打算毕业后就和阿蛮的妈妈结婚,两家便决定一起办婚礼。婚后不久,阿蛮的妈和小萝的妈妈前后怀了孕,两个男人可高兴坏了。 两家商量买房子...
ps:我已委托“维权骑士”(http://rightknights.com)为我的文章进行维权行动。转载必须联系本人 否则一律侵权 1.下厨的频率是怎样的?是天天煮、偶尔使用还是几乎不用? 2.家中通常谁做饭?常有的煮食方式是热炒还是水煮?川湘菜还是清淡为主? 3.目前厨房...}

我要回帖

更多关于 vue server 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信