两个示例的git地址:

1. 我的环境

2. 方式一:使用prerender-spa-plugin插件获得SSR的效果。

2.1 说明

2.2 初始化

1
vue init webpack vue-prerender-demo //此文章都是在webpack基础上配置的
1
2
3
cd vue-prerender-demo
npm install
npm run dev

2.3 配置

2.4 开始

1. 安装 prerender-spa-plugin, 因为依赖phantom js,phantom 的安装比较蛋疼,太耗时了~
1
npm install prerender-spa-plugin -D
2. 开始 prerender 相关的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//引用
var PrerenderSpaPlugin = require('prerender-spa-plugin') //... plugins: {
//....
//配置 prerender-spa-plugin
new PrerenderSpaPlugin(
// 生成文件的路径,此处与webpack打包地址一致
path.join(config.build.assetsRoot), //config.build.assetsRoot为vue cli生成的配置,打包后的文件地址
// 配置要做预渲染的路由,只支持h5 history方式
[ '/', '/test']
) //....
}
3. 编译
1
npm run build

4. 验证
1
2
cd dist //进入到对应目录
python -m SimpleHTTPServer 8888 //将dist作为根目录,启动8888端口,


2.5 优缺点

3. 方式二:使用官方提供的轮子在node端做SSR

3.1 说明

3.2 约束

3.3 准备工作

1
vue init webpack vue-ssr-demo
1
2
3
cd vue-ssr-demo
npm install
npm run dev

3.4 开始折腾

1. 首先安装 ssr 支持
1
npm i -D vue-server-renderer
2. 增加路由test与页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
Just a test page.
<div>
<router-link to="/">Home</router-link>
</div>
<div><h2>{{mode}}</h2></div>
<div><span>{{count}}</span></div>
<div><button @click="count++">+1</button></div>
</div>
</template>
<script>
export default {
data () {
return {
mode: process.env.VUE_ENV === 'server' ? 'server' : 'client',
count: 2
}
}
}
</script>
3. 在src目录下创建两个js:
1
2
3
src
├── entry-client.js # 仅运行于浏览器
└── entry-server.js # 仅运行于服务器
4. 修改router配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld' Vue.use(Router) export function createRouter () {
return new Router({
mode: 'history', // 注意这里也是为history模式
routes: [
{
path: '/',
name: 'Hello',
component: HelloWorld
}, {
path: '/test',
name: 'Test',
component: () => import('@/components/Test') // 异步组件
}
]
})
}
5. 改造main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue'
import App from './App'
import { createRouter } from './router' export function createApp () {
// 创建 router 实例
const router = new createRouter()
const app = new Vue({
// 注入 router 到根 Vue 实例
router,
render: h => h(App)
})
// 返回 app 和 router
return { app, router }
}
6. entry-client.js加入以下内容:
1
2
3
4
5
6
import { createApp } from './main'
const { app, router } = createApp()
// 因为可能存在异步组件,所以等待router将所有异步组件加载完毕,服务器端配置也需要此操作
router.onReady(() => {
app.$mount('#app')
})
7. entry-server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// entry-server.js
import { createApp } from './main'
export default context => {
// 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise,
// 以便服务器能够等待所有的内容在渲染前,
// 就已经准备就绪。
return new Promise((resolve, reject) => {
const { app, router } = createApp()
// 设置服务器端 router 的位置
router.push(context.url)
// 等到 router 将可能的异步组件和钩子函数解析完
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
// 匹配不到的路由,执行 reject 函数,并返回 404
if (!matchedComponents.length) {
// eslint-disable-next-line
return reject({ code: 404 })
}
// Promise 应该 resolve 应用程序实例,以便它可以渲染
resolve(app)
}, reject)
})
}
8. webpack配置
1
2
3
4
build
├── webpack.base.conf.js # 基础通用配置
├── webpack.client.conf.js # 客户端打包配置
└── webpack.server.conf.js # 服务器端打包配置
9. webpack 客户端的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
// ...
// ...
plugins: [
new webpack.DefinePlugin({
'process.env': env,
'process.env.VUE_ENV': '"client"' // 增加process.env.VUE_ENV
}),
//...
// 另外需要将 prod 的HtmlWebpackPlugin 去除,因为我们有了vue-ssr-client-manifest.json之后,服务器端会帮我们做好这个工作。
// new HtmlWebpackPlugin({
// filename: config.build.index,
// template: 'index.html',
// inject: true,
// minify: {
// removeComments: true,
// collapseWhitespace: true,
// removeAttributeQuotes: true
// // more options:
// // https://github.com/kangax/html-minifier#options-quick-reference
// },
// // necessary to consistently work with multiple chunks via CommonsChunkPlugin
// chunksSortMode: 'dependency'
// }), // 此插件在输出目录中
// 生成 `vue-ssr-client-manifest.json`。
new VueSSRClientPlugin()
]
// ...
10. webpack 服务器端的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const webpack = require('webpack')
const merge = require('webpack-merge')
const nodeExternals = require('webpack-node-externals')
const baseConfig = require('./webpack.base.conf.js')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
// 去除打包css的配置
baseConfig.module.rules[1].options = '' module.exports = merge(baseConfig, {
// 将 entry 指向应用程序的 server entry 文件
entry: './src/entry-server.js',
// 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),
// 并且还会在编译 Vue 组件时,
// 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。
target: 'node',
// 对 bundle renderer 提供 source map 支持
devtool: 'source-map',
// 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
output: {
libraryTarget: 'commonjs2'
},
// https://webpack.js.org/configuration/externals/#function
// https://github.com/liady/webpack-node-externals
// 外置化应用程序依赖模块。可以使服务器构建速度更快,
// 并生成较小的 bundle 文件。
externals: nodeExternals({
// 不要外置化 webpack 需要处理的依赖模块。
// 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,
// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单
whitelist: /\.css$/
}),
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.VUE_ENV': '"server"'
}),
// 这是将服务器的整个输出
// 构建为单个 JSON 文件的插件。
// 默认文件名为 `vue-ssr-server-bundle.json`
new VueSSRServerPlugin()
]
})
1
baseConfig.module.rules[1].options = '' // 去除分离css打包的插件
11. 配置package.json增加打包服务器端构建命令并修改原打包命令
1
2
3
4
5
6
"scripts": {
//...
"build:client": "node build/build.js",
"build:server": "cross-env NODE_ENV=production webpack --config build/webpack.server.conf.js --progress --hide-modules",
"build": "rimraf dist && npm run build:client && npm run build:server"
}
12. 修改index.html
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue-ssr-demo</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
13. 运行构建命令
1
npm run build
14. 构建服务器端(官方例子使用的express,所以此 demo 将采用koa2来作为服务器端,当然,无论是 koa 与 express 都不重要…)
1
npm i -S koa
1
2
3
4
5
6
7
8
9
const Koa = require('koa')
const app = new Koa() // response
app.use(ctx => {
ctx.body = 'Hello Koa'
}) app.listen(3001)
15. 编写服务端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const Koa = require('koa')
const app = new Koa()
const fs = require('fs')
const path = require('path')
const { createBundleRenderer } = require('vue-server-renderer') const resolve = file => path.resolve(__dirname, file) // 生成服务端渲染函数
const renderer = createBundleRenderer(require('./dist/vue-ssr-server-bundle.json'), {
// 推荐
runInNewContext: false,
// 模板html文件
template: fs.readFileSync(resolve('./index.html'), 'utf-8'),
// client manifest
clientManifest: require('./dist/vue-ssr-client-manifest.json')
}) function renderToString (context) {
return new Promise((resolve, reject) => {
renderer.renderToString(context, (err, html) => {
err ? reject(err) : resolve(html)
})
})
}
app.use(require('koa-static')(resolve('./dist')))
// response
app.use(async (ctx, next) => {
try {
const context = {
title: '服务端渲染测试', // {{title}}
url: ctx.url
}
// 将服务器端渲染好的html返回给客户端
ctx.body = await renderToString(context) // 设置请求头
ctx.set('Content-Type', 'text/html')
ctx.set('Server', 'Koa2 server side render')
} catch (e) {
// 如果没找到,放过请求,继续运行后面的中间件
next()
}
}) app.listen(3001)
1
node server.js
16. 大功告成

3.4 优缺点

基于vue-cli项目添加服务端渲染的更多相关文章

  1. 改造@vue/cli项目为服务端渲染-ServerSideRender

    VUE SEO方案二 - SSR服务端渲染 在上一章中,我们分享了预渲染的方案来解决SEO问题,个人还是很中意此方案的,既简单又能解决大部分问题.但是也有着一定的缺陷,所以我们继续来看下一个方案--服 ...

  2. 使用 Vue 2.0 实现服务端渲染的 HackerNews

    Vue 2.0 支持服务端渲染 (SSR),并且是流式的,可以做组件级的缓存,这使得极速渲染成为可能.同时, 和 2.0 也都能够配合 SSR 提供同构路由和客户端 state hydration.v ...

  3. 使用 PHP 来做 Vue.js 的 SSR 服务端渲染

    对于客户端应用来说,服务端渲染是一个热门话题.然而不幸的是,这并不是一件容易的事,尤其是对于不用 Node.js 环境开发的人来说. 我发布了两个库让 PHP 从服务端渲染成为可能.spatie/se ...

  4. 基于Vue/React项目的移动端适配方案

    本文的目标是通过下文介绍的适配方案,使用vue或react开发移动端及H5的时候,不需要再关心移动设备的大小,只需要按照固定设计稿的px值布局,提升开发效率. 下文给出了本人分别使用create-re ...

  5. vue/cli项目添加外部js文件的一个方法

    有一个util.js文件,内容如下 function Util () { ... } export default new Util() 可以在main.js里面通过import引入js import ...

  6. 实例PK(Vue服务端渲染 VS Vue浏览器端渲染)

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

  7. Vue服务端渲染和Vue浏览器端渲染的性能对比

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

  8. Egg + Vue 服务端渲染工程化实现

    在实现 egg + vue 服务端渲染工程化实现之前,我们先来看看前面两篇关于Webpack构建和Egg的文章: 在 Webpack工程化解决方案easywebpack 文章中我们提到了基于 Vue ...

  9. Vue服务端渲染 VS Vue浏览器端渲染)

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

随机推荐

  1. 043 HIVE中的HQL操作

    1.字段查询 select empno,ename from emp; 2.过滤where,limit,distinct select * from emp where sal >2500; s ...

  2. 002.Heartbeat部署及httpd高可用

    一 前期准备 1.1 依赖准备 编译安装需要依赖的包,如gcc等: yum -y install gcc gcc-c++ make glibc kernel-devel kernel-headers ...

  3. 利用zabbix监控oracle数据库

    一.概述 zabbix是一款非常强大,同时也是应用最为广泛的开源监控软件,本文将给大家介绍如何利用zabbix监控oracle数据库. 二.环境介绍 以下是我安装的环境,实际部署时并不需要跟我的环境一 ...

  4. 从源码看Spring Boot 2.0.1

    Spring Boot 命名配置很少,却可以做到和其他配置复杂的框架相同的功能工作,从源码来看是怎么做到的. 我这里使用的Spring Boot版本是 2.0.1.RELEASE Spring Boo ...

  5. Java中A instanceof B是什么意思?

    instanceof用来判断内存中实际对象A是不是B类型 出现这种情况经常是需要强制转换的时候class Dog extends Animal譬如dog定义了自己的方法wangwang Animal ...

  6. Python学习——深浅拷贝

    1.对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. >>> import copy # ######### 数字.字符串 ######### ...

  7. C# 运行中 Lua 语言脚本

    这里就不介绍Lua语言了,使用挺广的一种脚本语言.自行百度. 第一步 使用 Nuget 安装引用 VikingErik.LuaInterface. 第二步 添加 Using using LuaInte ...

  8. JavaScript:变量提升和函数提升

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函 ...

  9. redis 在 php 中的应用(Connection [ 连接] 篇)

    本文为我阅读了 redis参考手册 之后编写,注意 php_redis 和 redis-cli 的区别(主要是返回值类型和参数用法) 目录: Connection(连接) AUTH ECHO PING ...

  10. memcache 在php中的用法

    memcached 的安装方法详见我博客的另一个页面:http://www.cnblogs.com/chrdai/p/6656443.html 用法: 一.memcache 连接命令: 1.memca ...