vue 博客的教程及上线指南
首先先提下提交我们的代码上线的过程,线上服务器只需要我们最后的 server 文件以及构建后的前端文件,即根目录下的 public 文件夹下的东东。即在完成每次的开发内容后,记得在 frond-end
前端项目中,执行 npm run build
代码构建。
可以注意到根目录下的 server.js
文件,将代码 push 上去后,会自动执行 node server.js
启动 node
服务器,配置的地方见 package.json
里面的 scripts 部分,当然你也可以根据自己喜欢的方式进行定义。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
再看看 server.js
需要做些什么,
'use strict';
var AV = require('leanengine');
AV.init({
appId: process.env.LEANCLOUD_APP_ID,
appKey: process.env.LEANCLOUD_APP_KEY,
masterKey: process.env.LEANCLOUD_APP_MASTER_KEY
});
// 如果不希望使用 masterKey 权限,可以将下面一行删除
AV.Cloud.useMasterKey();
var app = require('./server-modules/app');
// 端口一定要从环境变量 `LEANCLOUD_APP_PORT` 中获取。
// LeanEngine 运行时会分配端口并赋值到该变量。
var PORT = parseInt(process.env.LEANCLOUD_APP_PORT || 3000);
app.listen(PORT, function () {
console.log('Node app is running, port:', PORT);
// 注册全局未捕获异常处理器
process.on('uncaughtException', function(err) {
console.error("Caught exception:", err.stack);
});
process.on('unhandledRejection', function(reason, p) {
console.error("Unhandled Rejection at: Promise ", p, " reason: ", reason.stack);
});
});
其实就是一些启动 node 服务器以及连接 leancloud 的一些验证信息等各种配置,如果出现异常将错误信息打印等工作。
最后说的就是部署的工作,由于是用的免费测试应用,所以只有一个生产环境,不用管环境的问题。我们使用的部署方式使用官方提供的一套命令行工具即可完成,安装方式:(执行下面的命令即可,需要提前装好 brew)
brew install lean-cli
装好后,如果在命令行执行 lean
,后可以看到使用说明,说明已经安装成功了,接着进行下一步。在项目根目录下,登录自己的 leancloud 账号,并完成当前项目与线上创建应用的绑定。如果项目是第一次绑定,请先执行 lean init
初始化。
lean login
// 输入邮箱 & 密码
// 登录成功后
lean init
// 可以看到已经创建的应用,选择即可完成绑定,已绑定可键入 lean switch 切换应用
绑定好我们的应用后,为了防止部署后出现问题,可以先执行 lean up
尝试在本地启动服务,检查应用是否启动正常。如果有报错,请先检查是否本地端口被占用,换一个即可。
如果前面一切顺利,在根目录下执行
lean deploy
即完成可对代码进行线上部署。由于是免费的测试服务器,所以会出现时不时的服务无法访问的情况,且一段时间不访问,也会自动进入休眠状态,即再次启动时需要等待服务被唤醒,时间较长。
部署完成后,访问我们线上填写的 url 即可在线看到我们的应用。
首先观察我们的文件结构,主要设置如下
├── front-end 前端代码
├── build 构建脚本
├── config 通用配置
├── node_modules
├── src 页面编写的代码
├── static
└── test
├── node_modules
├── public
└── server-modules 后台服务调用
└── modules 模块拆分
前端部分的文件结构直接使用 vue-cli
生成即可,根目录下的需要的模块主要是为了提供 node.js
跑服务使用,用到了如下几个:
"dependencies": {
"body-parser": "1.12.3", // 解析body参数
"cookie-parser": "^1.3.5", // 解析 cookie
"express": "4.12.3", // express 服务框架
"leanengine": "^1.0.0-beta" // leancloud 提供的 SDK,提供我们本地对云存储的操作
}
注意确保已经安装配置好了 node.js 与 npm 等环境。
设置好我们的文件结构即可进入到后面的实战开发了。
先说明这一部分,主要是考虑到本应用涉及到的逻辑并不复杂,所以讲基本所有的数据请求以及交互都存放在了 Vuex 的 store 中,也是直接请求我们服务端的地方,所以理清楚这一块对于整体应用也基本了解了。
import createLogger from 'vuex/dist/logger'
import actions from './actions'
// modules 模块分类
import contentList from './modules/contentList'
import article from './modules/article'
import commentsList from './modules/commentsList'
import tags from './modules/tags'
import tagContentList from './modules/tagContentList'
import user from './modules/user'
Vue.use(Vuex)
Vue.config.debug = true
// 非生产环境下开启严格模式,用以检测是否有在 mutation 外改变 store
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
strict: debug,
actions,
modules: {
contentList,
article,
commentsList,
tags,
tagContentList,
user
},
plugins: process.env.NODE_ENV !== 'production'
? [createLogger()]
: []
})
可以看到我们将应用的不同部分分成了多个模块去管理,包括 首页的文章列表、详情、评论、标签、标签下文章列表、用户等, 也将我们的具体工作分成对应的模块,按模块开发。Action 内则进行异步请求处理。注意这里用到了 createLogger
插件,这是一个 Vuex 插件,能够追踪 Vuex 状态的变化,并在控制台打印,在开发模式下启动即可,便于我们开发中即时看到状态的变化过程。
具体模块内容参考源代码即可,不过多啰嗦了,可以看到每个模块中我们使用 state 存放每个模块的基本数据属性、mutations 放置对 state 的修改操作,并供 Actions 调用。
对于路由的配置,将我们应用需要的页面全部设置在这里,可以得到应用的一个大概了。
Vue.use(VueRouter)
export default new VueRouter({
mode: 'history',
routes: [{
path: '/',
name: 'Index',
component: function(resolve) {
require(['@/views/Index'], resolve)
}
}, {
path: '/article/:id',
name: 'article',
component: function(resolve) {
require(['@/views/Article'], resolve)
}
}, {
path: '/tags',
name: 'tags',
component: function(resolve) {
require(['@/views/Tags'], resolve)
}
}, {
path: '/about',
name: 'about',
component: function(resolve) {
require(['@/views/About'], resolve)
}
}, {
path: '/post',
name: 'post',
component: function(resolve) {
require(['@/views/Post'], resolve)
},
// meta: {
// requiresAuth: true
// }
}, {
path: '/login',
name: 'login',
component: function(resolve) {
require(['@/views/Login'], resolve)
}
}, {
path: '/home',
name: 'home',
component: function (resolve) {
require(['@/views/pages/Index'], resolve)
}
}],
scrollBehavior(to, from, savedPosition) {
// return 期望滚动到哪个的位置
// 路由切换时滚动到顶部
if (savedPosition) {
return savedPosition
} else {
return { y: 0 }
}
}
})
注意到每个路由组件的应用方式均采用了异步调用的方式,是一种路由懒加载的手段,使我们在访问到对应路由时采取加载对应的模块代码,可以用于提高首屏加载的时间。
通过 leanengine
SDK 可以很方便的与云端存储通信,并将返回的最新数据通过 api 接口提供出来供我们前台显示。
const router = require('express').Router();
// 添加路由模块
const content = require('./modules/content');
const comments = require('./modules/comment');
const tags = require('./modules/tags');
const user = require('./modules/user');
// 路由设置
router.get('/hello', content.hello);
// Content
router.get('/contentAll', content.contentList);
router.get('/contentList/:page', content.getTenContent);
router.get('/content/backgroundImg', content.getImgUrl);
// Article
router.get('/article/:id', content.article);
router.post('/article/submitArticle', content.submitArticle);
// Comment
router.get('/comments/:articleId', comments.commentsList);
router.post('/comments/submitComment', comments.submitComment);
// Tag
router.get('/tags', tags.tags);
router.get('/tags/:tagId', tags.tagList);
// User
router.post('/login', user.login);
router.post('/logout', user.logout);
module.exports = router;
路由按照模块划分,将我们应用中需要的接口,在这里提供出来。
const AV = require('leanengine');
let Content = {};
// 获取10篇文章
Content.getTenContent = async(req, res) => {
const page = req.params.page || 1
const queryTenContent = (page) => {
const query = new AV.Query('ContentList') // 创建查询实例
query.descending('createdAt') // 创建时间->降序查询
query.skip((page - 1)*10) // 跳过指定项
query.limit(10) // 限制返回项数量
return query.find();
}
try {
const data = await queryTenContent(page)
if (data) {
let arr = []
for (let item of data) {
let result = {}
result.objectId = item.get('objectId')
result.title = item.get('title')
result.abstract = item.get('abstract')
result.author = item.get('author')
result.createdAt = item.get('createdAt').Format("yyyy-MM-dd hh:mm:ss")
arr.push(result)
}
let final_result = {};
final_result.page = page;
final_result.data = arr;
res.send(final_result)
} else {
throw new Error('Can\'t find the data-Content')
}
} catch (err) {
console.error(err)
}
}
module.exports = Content;
有了云服务提供的存储支持,我们只用像上面这样编写相应的类似 controller 函数即可完成各类交互,具体方法,查阅请官方文档。