关于 vue 作服务端渲染,目前主要有俩种解决方案,使用 vue-server-renderer 或者使用 nuxt 。但我的感受使用 nuxt 写法太死,以及即便你用 nuxt 写出了 vue ssr 页面,可能你也只是说熟悉了 nuxt 这个框架,而不清楚 vue ssr 具体的原理。如下我会基于 vue ssr 渲染示例 vue-hackernews-2.0 以及豆瓣 api 实现一个简单的 vue-ssr。开始以前,请先大体阅读下官方文档css
首先经过一个简单的示例了解什么是服务端渲染。所谓服务端渲染就是经过服务端请求获取数据,根据 vue 模版渲染好 html 页面返回给前端,验证一个页面是否是经过服务端渲染的能够在页面上右键查看源代码有没有页面的 html 信息。html
const Vue = require('vue') const server = require('express')() const renderer = require('vue-server-renderer').createRenderer() server.get('*', (req, res) => { const app = new Vue({ data: { url: req.url }, template: `<div>访问的 URL 是: {{ url }}</div>` }) renderer.renderToString(app, (err, html) => { if (err) { res.status(500).end('Internal Server Error') return } // 返回 html 信息 res.end(` <!DOCTYPE html> <html lang="en"> <head><title>Hello</title></head> <body>${html}</body> </html> `) }) }) server.listen(8080)
|--build: webpack 配置文件 |--dist: 编译后文件目录 |--log: 日志目录 |--node_modules: npm 包 |--public: 公共文件目录 |--src: 项目开发目录 |--api: api 目录 |--assets: 资源目录,图片,css等 |--components: 公共组件 |--router: 路由 |--store: vuex 状态管理 |--util: 公共方法 |--views: 各目录对应各个页面 |--.babelrc: babel 配置 |--eslintrc.js: eslint 配置 |--ecosystem.js: pm2 配置文件 |--package.json: npm 包配置 |--postcss.config.js: postcss 配置 |--config.js: 配置文件 |--server.js: node 服务
了解 vue 服务端渲染最主要的是要知道上面的图片到底讲了什么。前端
这三者为无论是服务端渲染仍是客户端渲染都可使用的公共模块vue
定义好 vue 实例 app,路由 router、数据 store。方便服务端与客户端作同步。node
首先为何会有 Server entry 和 Client entry 俩个入口。咱们假设页面有俩个路由。当俩个路由均是经过浏览器输入 url 直接访问的,则均经过服务端请求数据渲染好页面返回给前端,俩个页面均是走 Server entry。当一个路由是经过浏览器输入,而另外一个路由是经过当前路由点击跳转到达的,走spa(单页) 前端请求数据渲染页面,则第一个路由走 Server entry,跳转的页面走 Client entry。
Server entry 与 Client entry 定义了一个钩子函数 asyncData 参数为 store 与 router,在服务端执行。同步了客户端与服务端的路由与数据。webpack
左侧 source 经过 webpack 打包,让 node 执行 Server enter 打包的代码,浏览器执行 Client entry 打包的代码。git
无论是走服务端渲染仍是客户端渲染,咱们均使用同一套路由,在 app.js 中定义一个 router 对象,在 Server entry 与 Client entry 中均使用该对象。github
服务端渲染好页面返回给客户端,客户端渲染好页面须要作一些交互修改一些数据,数据是经过服务端请求获取的,此时还存在服务端,客户端如何获取到这些数据呢?
服务端请求的数据会存放在 store 中,在 Server entry 中将 数据赋值给 context.state。执行 renderTostring 时会将数据存放在 window.__INITIAL_STATE__ 返回给前端。Client entry 将会读取 window.__INITIAL_STATE__ 中的数据存放在 store 中。这样就能够在 store 中获取到数据。web
前端页面直接调用第三方接口会报跨域错误,vue-hackernews-2.0 是使用 firebase 作处理,我这边直接在 node 端定义了俩个路由经过后端去请求。vuex
从主页跳到页面详情页时,后端请求接口获取到的数据我经过详情页 key - value的形式存放在 store 中,当请求的屡次不一样的详情也时致使返回的 window. INITIAL_STATE 数据量爆炸,页面加载缓慢。其实只需每一个路由建一个 key 便可,例详情页只创建一个 detail 的 key,请求的数据赋值给 detail 便可。见 issue
https://ssr.vuejs.org/zh/
https://github.com/vuejs/vue-hackernews-2.0