通过Nuxt将Vue项目改造为SSR

为了更好的享受现代化前端开发框架的乐趣,前一阵把官网给用Vue重写了,开发效率上确实一下子提升了一大截,但是过了一阵用百度一搜,emmm……

百度

对比一下别人家的,虽然不能像百度RMB玩家那样还有站点图标,但好歹描述信息要靠谱点儿把。

名侦探柯南事务所

总结起来了就是,现在的搜索引擎爬虫对于客户端渲染的站点都不是太友好,没办法获取到ajax拉取回来的动态内容,解决方案嘛就是得把页面的渲染逻辑再拿回服务端,让地址直接导出的就是最终渲染结果了,在Vue的架构下大致是三种:
1、 用插件的形式进行预渲染,比如:prerender-spa-plugin,简单倒是简单,不过最终生成的页面没法儿展示接口获取的动态数据;
2、 使用Vue官方的SSR方案,尝试一阵把代码结构改的乱七八糟后,放弃……
3、 基于NUXTJS的方案,相对来说功能齐备,改造成本最低的一套。

改造步骤

新建Nuxt工程

因为nuxt本身有一系列直接的工程目录结构跟配置,所以最省心的方式还是新建工程后再从Vue工程慢慢的蚂蚁搬家过来。

1
npx create-nuxt-app demo

各种模块根据提示依据自己的需要来选择就好了,就是注意最后的”Choose rendering mode”选择”Universal (SSR)”,完成后的目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
demo
├── README.md
├── assets
├── components
├── layouts
├── middleware
├── node_modules
├── nuxt.config.js
├── package-lock.json
├── package.json
├── pages
├── plugins
├── server
├── static
└── store

为了看起来跟Vue跟亲切一些儿,新建src目录,把这assets,components,layouts,middleware,pages,plugins,static,store几个目录都拉进去,调整完如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
demo
├── README.md
├── node_modules
├── nuxt.config.js
├── package-lock.json
├── package.json
├── server
│   └── index.js
└── src
├── assets
├── components
├── layouts
├── middleware
├── pages
├── plugins
├── static
└── store

然后修改nuxt.config.js,指定源码的目录

1
2
3
4
5
module.exports = {
mode: 'universal',
srcDir: 'src/',
....
}

依赖库迁移(main.js)

从原有Vue工程的package.json直接复制对应的dependencies跟devDependencies,合并到新工程的package.json中就好了,此外Nuxt的工程中没有了main.js,对应的库引用需要在plugins中进行处理。

ElementUI

1、 plugins目录下新建element-ui.js文件

1
2
3
4
// ElementUI
import Vue from 'vue';
import Element from 'element-ui'
Vue.use(Element);

2、 修改nuxt.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
...
css: [
...
'element-ui/lib/theme-chalk/index.css',
...
],
...
plugins: [
...
'@/plugins/element-ui.js',
...
],
....
}

Axios

1、 安装依赖

1
npm i -S @nuxtjs/axios

2、 plugins目录下新建http.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import axios from 'axios';
import * as Conf from '@/conf';

// http request 拦截器
export default function ({ $axios, redirect }) {
$axios.defaults.timeout = 5000;
$axios.defaults.baseURL = Conf.DEBUG?'http://localhost:9000':'https://api.demo.com';

$axios.onRequest(config => {

// 统一添加时间戳
if( 'get' === config.method){
config.params = {
_t: Date.parse(new Date())/1000,
...config.params
}
}

return config;
})

};

3、 修改nuxt.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
...
plugins: [
...
'@/plugins/http.js',
...
],
...
modules: [
...
'@nuxtjs/axios',
...
],
....
}

4、 程序中使用

1
2
this.$axios.$get(...);
this.$axios.$post(...);

VueLogger

1、 plugins目录下新建vuejs-logger.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import * as Conf from '@/conf';
import VueLogger from 'vuejs-logger';
const options = {
isEnabled: true,
logLevel : Conf.DEBUG ? 'debug' : 'error',
stringifyArguments : false,
showLogLevel : true,
showMethodName : true,
separator: '|',
showConsoleColors: true
};
Vue.use(VueLogger, options);

2、 修改nuxt.config.js

1
2
3
4
5
6
7
8
9
module.exports = {
...
plugins: [
...
'@/plugins/vuejs-logger.js',
...
],
....
}

PostCSS

1、 修改nuxt.config.js

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
...
build: {
postcss: {
'autoprefixer': {browsers: 'last 5 version'}
},
extend (config, ctx) {
}
}
....
}

静态文件迁移(public)

1、 原有public目录下的文件除index.html外全部转移至新工程的src/static下面;
2、 在src下新建app.html文件,其中对应nuxt.config.js中的head属性配置,就是要被动态替换的内容,模板如下:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang="en">
<head>
{{HEAD}}
</head>
<body>
{{APP}}
</body>
</html>

其他部分可以从index.html中捣腾过来。

路由迁移(router.js)

在nuxt中路由会根据pages路径跟文件名自动映射处理,所以这一步的迁移工作就省略掉了

运行

最后运行一下看看效果

1
npm run dev

打包部署

1、 编译打包(其中generate是生成静态文件部署的打包,这里用不上),成功后项目下会生成.nuxt目录

1
npm run build

2、 修改pacakge.json(原有node方式无法在服务器上正常运行)

1
2
3
4
5
6
7
{
"scripts": {
...
"start": "cross-env NODE_ENV=production nuxt start",
...
},
}

3、 将.nuxt目录和package.json文件上传至服务器,并安装依赖包

1
npm install

4、 编写启动脚本跟重启脚本

1
2
3
4
5
6
7
8
9
#start.sh
BASE_PATH="/servers/demo"
cd ${BASE_PATH}
nohup npm run start

#restart.sh
cd /servers/demo
ps -elf|grep "demo"|grep -v "grep"|grep -v "sh "|awk '{print $4}'|xargs kill -9
nohup ./start.sh >./log/nohup.out 2>&1 &

5、 配置nginx转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name demo.com;

access_log /logs/demo.log combined;
error_log /logs/demo_error.log;

location / {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
}

error_page 404 /index.html;

}