笔者最近业余时间想着学点新东西,因而开始接触服务器端渲染(SSR),花了一周的时间学习和实战,而后在周末高仿掘金撸了一个 SSR 的 Demo 项目。javascript
技术栈选的是平滑开箱的 Nuxt,整个项目整合了 vue + nuxt + axios + vuex + vue-router (nuxt 自带 vuex 和 vue-router)。css
项目目前实现了如下几大功能html
服务器端渲染前端
静态页面部署vue
掘金首页java
掘金推荐列表node
滚动分页加载webpack
不一样端的布局适配ios
项目完整地址:nuxt-ssr-demonginx
前端交流群:731175396
看完最终完成的效果图,接下来,开始咱们的实战之旅吧 ~
一个项目开始以前,我喜欢先搭好一个空架子。因此这里仍是老规矩,先带着你们把项目空壳搭好吧。
这里关于项目初始化,我是直接使用的 Nuxt
官网提供的 starter 模板
# 安装 vue-cli
npm install -g vue-cli
# 初始化项目
vue init nuxt-community/starter-template nuxt-ssr-demo
# 安装依赖
cd nuxt-ssr-demo
npm install # Or yarn install
# 启动本地服务
npm run dev
复制代码
访问 http://localhost:3000 ,如今咱们来看下初始化好的项目目录
├── assets css,图片等资源都在这
├── components 组件相关
├── layouts 路由布局
├── middleware 中间件
├── pages 路由页面
├── static 静态资源
├── pages 路由页面
├── store vuex 相关
├── nuxt.config.js nuxt 相关配置
├── package.json 依赖相关
├── README.md 项目介绍
复制代码
接触过 vue
的小伙伴,看着这个目前可能会有点小疑问,为何没有 router 路由相关的文件?莫慌,Nuxt
会帮你将 pages 下面的文件自动解析成路由。因此在接下来的开发中,记得别瞎在 pages 下面新增文件,pages 下面的每个 vue 文件就是一个路由。
npm i axios -S
复制代码
为了项目以后更加方便的开发,咱们有必要对 axios 进行一层封装,咱们要时刻养成这样一种好习惯。
首先在根目录下面新建 service
目录,在其下面创建 config.js
和 index.js
两个文件,下面的代码仅供参考,若是你的项目还须要作额外的一些配置,可自行进行拓展
在 config.js
中写入:
import http from 'http'
import https from 'https'
export default {
// 自定义的请求头
headers: {
post: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
'X-Requested-With': 'XMLHttpRequest'
},
// 超时设置
timeout: 10000,
// 跨域是否带Token
withCredentials: true,
// 响应的数据格式 json / blob /document /arraybuffer / text / stream
responseType: 'json',
// 用于node.js
httpAgent: new http.Agent({
keepAlive: true
}),
httpsAgent: new https.Agent({
keepAlive: true
})
}
复制代码
在 index.js
中写入:
import axios from 'axios'
import qs from 'qs'
import config from './config'
const service = axios.create(config)
// POST 传参序列化
service.interceptors.request.use(
config => {
if (config.method === 'post') config.data = qs.stringify(config.data)
return config
},
error => {
return Promise.reject(error)
}
)
// 返回结果处理
service.interceptors.response.use(
res => {
return res.data
},
error => {
return Promise.reject(error)
}
)
export default {
// post 方法
post (url, data) {
console.log('post request url', url)
return service({
method: 'post',
url,
params: data
})
},
// get 方法
get (url, data) {
console.log('get request url', url)
return service({
method: 'get',
url,
params: data
})
},
// delete 方法
delete (url, data) {
console.log('delete request url', url)
return service({
methods: 'delete',
url,
params: data
})
}
}
复制代码
使用过 vue
的同窗,确定知道对于项目中的跨域,vue-cli
对 webpack
中的 proxy
选项进行了一层封装。它暴露出来的是一个叫 proxyTable
的选项,是对 webpack
中的 proxy
和其三方插件 http-proxy-middleware
的一个整合。
不幸的 Nuxt
中没有 proxyTable
这么一个配置项来进行跨域的配置。固然幸运的是,在 Nuxt
中你能够直接经过配置 http-proxy-middleware
来处理跨域。更幸运的是 Nuxt
官方提供了两个包来处理 axios
跨域问题。
首先,进行安装
npm i @nuxtjs/axios @nuxtjs/proxy -D
复制代码
而后在 nuxt.config.js
文件里进行配置
modules: [
'@nuxtjs/axios'
],
axios: {
proxy: true
},
proxy: {
'/api': {
target: 'xxx.target.com',
pathRewrite: { '^/api': '' }
}
}
复制代码
这里须要注意,由于是服务器端渲染,咱们得时刻明确当前地址是属于路由跳转仍是属于 axios 请求。因此咱们须要在 service/index.js
写入如下判断
// 判断是路由跳转仍是 axios 请求
if (process.server) {
config.baseURL = `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}`
}
复制代码
而后你就能够安心使用你的 axios 进行跨域请求了
先看下咱们 store 目录下须要的一些文件
├── actions.js axios 请求相关
├── index.js 主入口文件
├── mutations.js 同步状态操做相关
├── state.js 初始状态相关
复制代码
接下来咱们以此看看每一个文件的内容
import request from '~/service'
const api = '/api'
export const banner = async (store, params) => {
return await request.get(`${api}/v1/get_banner`, params)
}
复制代码
export default {
counter: 1,
isPhone: false
}
复制代码
export function INCREMENT (state) {
state.counter++
}
export function PCORPHONE (state, bool) {
state.isPhone = bool
}
复制代码
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import * as mutations from './mutations'
import * as actions from './actions'
Vue.use(Vuex)
const store = () => new Vuex.Store({
state,
mutations,
actions
})
export default store
复制代码
而后你就能够在页面中进行使用了
<template>
<div class="page">
<button @click="handleClick">{{ counter }}</button>
<p>{{ banner.name }}</p>
</div>
</template>
<script> import { mapState } from 'vuex' export default { async asyncData ({ store, error }) { // 对 axios 进行批量处理 let [ res ] = await Promise.all([ store.dispatch('banner') ]).catch((e) => { error({ statusCode: 404, message: 'Post not found' }) }) return { banner: res.banner } }, computed: { ...mapState({ counter: state => state.counter }) }, methods: { handleClick () { this.$store.commit('INCREMENT') } } } </script>
复制代码
Nuxt
的项目不比 vue
的项目,提供了主入口文件供咱们对全局组件进行配置。但要作到这个点也比较简单,咱们只须要按照 Nuxt
官网给出的规范来,将组件引入的相关配置写入到 plugins 目录下便可
好比,我须要引入三方组件库 element-ui ,咱们只需在 plugins 目录下新建一个 element-ui.js
文件,并写入
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
复制代码
而后在 nuxt.config.js
文件中引入
plugins: [
'~/plugins/element-ui'
]
复制代码
最后你就能够在你的项目中使用 element-ui
组件库里面的组件了。
固然,你想配置本身本地的全局组件,也是同样的作法。先在 plugins 目录下新建一个 js 文件,而后引入你的文件,最后再在 nuxt.config.js
文件中引入便可。
和组件管理同理,不一样的就是,css 须要存放在 assets 目录下。好比,如今我须要有一个 main.css
文件对路由跳转进行动态切换。
首选,你得在 assets/main.css
中写入重置样式吧
.page-enter-active, .page-leave-active {
transition: opacity .2s;
}
.page-enter, .page-leave-active {
opacity: 0;
}
复制代码
而后,你只要在 nuxt.config.js
进入引入便可
css: [
'~/assets/stylus/main.styl'
]
复制代码
关于 Nuxt
更多的用法,我就不一一介绍了,详细请参考:Nuxt.js 文档官网
而后关于项目的具体开发,也是屡见不鲜了,这里我也不展开描述了。若是想了解的,能够去 github 自行查阅。有问题的话能够加老司机群 731175396 ,而后在群里问我便可。
接下来的篇幅,我将讲一下项目部署的一些点
到这一步的同窗,你得先确保你拥有一个本身的服务器。若是没有的话,感受去买一个,如今阿里云和腾讯云都在搞活动,巨便宜哦 ~
OK,文章继续。在进行部署讲解前,咱们先看一下 Nuxt
提供的几个命令
命令 | 描述 |
---|---|
nuxt | 启动一个热加载的 Web 服务器(开发模式) localhost:3000 |
nuxt build | 利用 webpack 编译应用,压缩 JS 和 CSS 资源(发布用) |
nuxt start | 以生成模式启动一个 Web 服务器 (nuxt build 会先被执行) |
nuxt generate | 编译应用,并依据路由配置生成对应的 HTML 文件 (用于静态站点的部署) |
咱们从官网给出的文档能够看出,部署静态化页面须要用到的命令是 nuxt generate
,执行的时候会在根目录下面生成 dist 目录,里面的文件都是静态化页面须要的打包好的文件。
这里须要特别注意的一点是,若是你的项目中存在 axios 请求的话,记得在你本地开启一个本地服务哦 ~ 否则打包的时候执行到 axios 请求的时候会报错。由于前面咱们经过使用 node 的 process 对运行环境进行了是跳转仍是请求的断定,而打包进行请求的时候是不依赖 node 环境的
这里,我先假设小伙伴们均可以正常执行 nuxt generate
并生成对应的 dist 目录。
为了项目的并行开发,咱们通常会在 .gitignore
文件里面将打包文件给忽略掉,但咱们静态化页面的部署有须要用到 dist 目录下的全部打包文件。因此这里咱们将使用 gh-pages 将打包文件发布到咱们的 git 仓库
# 安装 gh-pages
npm i gh-pages -D
复制代码
而后在 package.json
写入配置(固然你也能够新建文件执行发布)
"scripts": {
"deploy": "gh-pages -d dist"
}
复制代码
执行 npm run deploy
,而后你的 dist 目录就会发到大家仓库的 gh-pages 分支了
打包文件上传好以后,你须要作的第一件事就是链接好你的服务器。而后在 cd 到服务器根目录下面,在 data/www
目录下面将你的项目 git clone
下来。而后切换到 gh-pages
分支
接下来,开始配置你的 nginx (还没下载 nginx 的同窗请自行解决)
server {
# 端口,默认是 80
listen 81;
# 服务名(写域名或者 ip 地址均可以)
server_name 123.12.123.12;
# server 根目录
root /data/www/nuxt-ssr-demo;
# 主入口文件
index index.html;
# 反向代理
location /api/ {
proxy_pass https://xxx.target.com/;
}
}
复制代码
而后重启 nginx
sudo service nginx restart
复制代码
而后你就能在 http://123.12.123.12:81 访问到你部署好的静态化页面了
看到上面静态化页面部署,详细有同窗会问。进行静态化页面部署,岂不是没有了服务器端渲染的优点了。
对的,若是你的项目只是静态页面的话,作静态化部署是彻底 OJBK 的。但若是牵扯到请求,仍是乖乖的进行服务器端的部署吧 ~
开始前,请确保你的服务器上已经搭建好了 node 环境。没有的同窗,我建议使用 nvm 安装 node 。接下来,开始部署
第一步,将以前 clone 下面的 git 项目切换到主开发分支,而后为了以后的方便修改一下你的 package.json
"scripts": {
"build": "npm run lint && nuxt build && npm start",
"start": "nuxt start"
}
复制代码
第二步,启动服务
npm run build
复制代码
第三步,配置你的 nginx 文件
# 经过 upstream nodejs 能够配置多台 nodejs 节点,作负载均衡
# keepalive 设置存活时间。若是不设置可能会产生大量的 timewait
# proxy_pass 反向代理转发 http://nodejs
upstream nodenuxt {
server 127.0.0.1:3000; # nuxt 项目监听端口
keepalive 64;
}
server {
listen 82;
server_name 118.25.109.133;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Nginx-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_pass http://nodenuxt; # 反向代理
}
}
复制代码
最后,从新启动 nginx 服务
sudo service nginx restart
复制代码
若是咱们按照上面的步骤进行部署的话,服务器会常常断掉链接,那咱们的服务也就断了。因此为了守护好咱们的 nodejs 进程,这里我将使用 pm2 对进程进行守护
首先全局安装 pm2
npm i pm2 -g
复制代码
而后进入到项目目录,执行
pm2 start npm --name "nuxt-ssr-demo" -- run build
复制代码
而后,妈妈不再用担忧个人 nodejs 进程说断就断啦 ~
对于 pm2 用法,请小伙伴们输入 pm2 --help
而后自行查阅
文章到这就要结束了,这里我作一个小总结。在一周的学习和实战中,产出一个高仿掘金的 SSR Demo 的同时,也踩了一些坑。
对于 Nuxt
,在使用层面,是比较简单、好上手的。相对 vue-ssr 来讲,它大大的简化了开发的配置,让开发人员能够只需思考业务的开发,而不用太去担忧文件的配置。其中 Nuxt
经过监听 pages 目录文件变动并自动生成路由更是直接省去了咱们日常对于路由的配置。
可是,目前 Nuxt
总体仍是有待提升的,目前社区相关的三方插件比较有限,市面上相关的参考资料也相对比较少。
无论如何,但愿 Nuxt
社区能够愈来愈好吧 ~
最后,想看项目源码的小伙伴,这里我再最后放一次连接
项目完整地址:nuxt-ssr-demo
前端交流群:731175396
我的准备从新捡回本身的公众号了,以后每周保证一篇高质量好文,感兴趣的小伙伴能够关注一波。