博客终于差很少写完了,虽然仍是可能有一堆bug, 不过我火烧眉毛要写一篇博文来分享了= =
javascript
你们一块儿来star、fork呀,欢迎提出各类改进意见,我知道确定还有一堆问题😵
域名尚未备案,后面就变成imhjm.com😆,敬请期待css
其实我一直在使用hexo搭建的博客,也一直用得还挺顺手,可是它只是个静态站点,当我须要一些定制化的需求,我没办法作更多的改变,而且搭在github page上有时不稳定,并且以为搭建一个网站而后本身来作各类优化是一件cool的事情,能够尝试各类新技术,能够接触到各个层面上的优化,因此写一个博客的念头就开始了。
其实vue-blog这个项目开了很久了,可是由于断断续续开发,过一段时间就以为以前的代码写得很差就开始重写,并且也是边写来边学习新技术,vue2全家桶,koa2, webpack2,这些都是以前我没怎么了解的技术,可是至少经过这个博客项目,我对它们也有了新的认识
这里也要感谢一下@Ma63d(@chuckliu),博客搭建初期学习了不少他的kov-blog代码,学习到不少东西,也让本身的后期实现得比较顺利html
就是这个图啦~
vue
这是博客后台,其实个人想法就是实现一个文本编辑器,有个左边栏,而后右边栏编辑,为了不复杂,我只用了两个页,一个登陆页,而后一个就是带有编辑器的列表页java
统一使用axios来通讯,鉴权使用jwt,login页中登陆成功存入token,而后进入编辑页,经过vue-router的beforeEach钩子加入node
Axios.defaults.headers.common['Authorization'] = 'Bearer ' + store.state.auth.token;复制代码
而后服务端接收时验证token来决定是否鉴权成功,失败时Axios统一拦截,删除store里存取的token, 经过vue-router再回到登陆页webpack
列表和编辑器分红了两个组件,用vuex统一管理状态,经过action取/存而后mutaion修改状态便可,可是这部分逻辑较多,具体实现就不展开描述了ios
// editor部分state
const state = {
articleList: [],
tagList: [],
currentArticle: {
id: -1,
index: -1,
content: '',
title: '',
tags: [],
save: true,
publish: false
},
allPage: 1,
curPage: 1,
selectTagArr: []
};复制代码
// auth部分state
const state = {
token: sessionStorage.getItem('token')
};复制代码
受@chuckliu安利一样使用了simplemde-markdown-editor,而后解析和高亮部分使用了marked.js
和highlight.js
css3
由于考虑到前台须要更快的加载速度,并且逻辑也比较简单,就放弃使用vuex,采用vue event bus来实现非父子组件间的通讯nginx
// 在main.js定义全局event bus,不使用vuex管理
var EventBus = new Vue();
Object.defineProperties(Vue.prototype, {
$eventBus: {
get: function() {
return EventBus;
}
}
});
// 而后在组件内能够这样使用
this.$eventBus.$on('filterListByTag', this.filterListByTag);
this.$eventBus.$emit('filterListByTag', this.filterListByTag);
this.$eventBus.$off('filterListByTag', this.filterListByTag);复制代码
排除article组件,其余则保留组件状态或避免从新渲染。
<transition name="fade" mode="out-in">
<!-- keep-alive排除article -->
<keep-alive exclude="article">
<router-view>
</router-view>
</keep-alive>
</transition>复制代码
原本的transition是使用到transform的,由于移动端个人侧边栏是fixed,发如今切换的过程当中侧边栏抖动,才发现是由于fixed是会跟随transform的,能够具体参考CSS3 transform对普通元素的N多渲染影响,因而便删去了切换时的移动,保留opacity
在布局上学习了下vue官网的两栏,两栏超出部分均可以滑动,而且不互相影响,这是怎么实现的?其实仍是挺简单的,不过用到一个小技巧,设置
// 这样能够实现一个元素100%width以及100%height
div {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}复制代码
其余就是经典两栏布局和加个overflow-y:auto了
还有一个经典的布局问题,就是foot部分如何实如今页面没什么东西的,固定在页面底部,页面出现滚动条,而后foot部分跟随在页面主体后面
server端直接上koa2了,支持async/await, 异步部分用起来真的很舒服,如今node7+也支持了,因此小伙伴们赶忙用吧~
再讲讲jwt鉴权吧
其实并不复杂
在验证登陆时,后端取出数据库已有的密码验证,成功则用配置好的secret生成一个signed jwt,通俗点说你将它加密了再传给客户端
const token = jwt.sign({
uid: user._id,
name: user.name,
exp: Math.floor(Date.now() / 1000) + 24 * 60 * 60 //1 hours
}, config.jwt.secret);复制代码
http无状态,因此客户端须要存下这个token, 而后以后请求时带上这个token服务端验证经过后返回资源便可
try {
tokenContent = await jwt.verify(token, config.jwt.secret);
} catch (err) {
if ('TokenExpiredError' === err.name) {
ctx.throw(401, 'token expired');
}
ctx.throw(401, 'invalid token');
}复制代码
若是想更深层次地了解jwt是什么,能够自行去搜索网上的文章
Representational State Transfer简单来理解就是每一个URL都是资源,经过不一样的http method去操做这些资源就行,设计上就能够这样,而后统一加上prefix:'/api'
router.get('/articles', verify, $.getAllArticles) //获取全部文章
.post('/articles', verify, $.createArticle) //建立文章
.patch('/articles/:id', verify, $.modifyArticle) //修改特定文章
.get('/articles/:id', $.getArticle) //获取特定文章
.delete('/articles/:id', verify, $.deleteArticle) //删除特定文章复制代码
原本打算直接使用vue-cli,这部分就很是省心了,vue-cli这个脚手架作得确实很友好,我以为vue比较好上手开发的一部分缘由也是由于它吧,不过由于这个博客项目就是学习的过程,不想这么轻易地逃过这部分的学习😸,直接上webpack2,而后参考vue-cli和webpack官网来写,以为也学习到不少东西,而且由于front和admin是分开的,因此也实现了多页配置
hot-reload是必备的
// ...
entry: {
'modules/admin': [
'webpack-hot-middleware/client?reload=true',
CLIENT_FOLDER + '/src/modules/admin/main'
],
'modules/front': [
'webpack-hot-middleware/client?reload=true',
CLIENT_FOLDER + '/src/modules/front/main'
]
},
// ...
plugins: [
new webpack.HotModuleReplacementPlugin()
// ..复制代码
用CleanWebpackPlugin清空下目录,HtmlWebpackPlugin自动生成html,而后该写的loader
生产环境下改动就大了,先得删去hot-reload和devtool部分,而后提取css
//...
styl: ExtractTextPlugin.extract({
use: [{
loader: 'css-loader',
options: {
minimize: true,
sourceMap: true
}
}, {
loader: 'stylus-loader',
options: {
sourceMap: true
}
}],
fallback: 'vue-style-loader'
}),
//...复制代码
UglifyJsPlugin压缩代码,而后提取公有代码vendor、manifest,manifest用来防止vendor的hash在vendor部分没有变化时不被修改
// ...
// 分别提取vendor、manifest
new webpack.optimize.CommonsChunkPlugin({
name: 'modules/vendor_admin',
chunks: ['modules/admin'],
minChunks: function(module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
join(__dirname, './node_modules')
) === 0
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'modules/manifest_admin',
chunks: ['modules/vendor_admin']
}),
//...复制代码
而后用CopyWebpackPlugin将static拷进dist就行了
这部分就能够看vue-cli是怎么实现的了,vue-cli使用的是express经过webpack-dev-middleware和webpack-hot-middleware实现开发模式下热重载,固然koa也能够
const koaWebpack = require('koa-webpack');
const webpack = require('webpack');
const webpackConfig = require('../webpack.config');
let compiler = webpack(webpackConfig);
app.use(koaWebpack({
compiler: compiler,
dev: {
//noInfo: true,
stats: {
colors: true,
chunks: false
},
publicPath: webpackConfig.output.publicPath,
}
}));复制代码
顺便讲到项目中用的是history模式,这里也须要后端配合
app.use(convert(historyApiFallback({
verbose: process.env.NODE_ENV == 'production' ? false : true,
index: '/front.html',
rewrites: [
{ from: /^\/admin$/, to: '/admin.html' },
{ from: /^\/admin\/login/, to: '/admin.html' },
{ from: /^\/$/, to: '/front.html' },
{ from: /^\/article/, to: '/front.html' }
]
})))复制代码
可是这里有个坑是要注意书写use的顺序,放在router api后面就行,这里须要理解下koa的洋葱结构
我以为这部分除了区分开发环境和生产环境之外,还要注意到对webpack打包的过程和模块的分析,不要吝啬webpack打包的输出
// 显示颜色,耗时长的都有颜色区分 --colors
// 能够看到每一步的耗时 --profile
// 显示模块 --display-modules
// 而且按size大小排序 --sort-modules-by size
webpack.config.js --colors --profile --display-modules --sort-modules-by size复制代码
这样就能看出打包什么耗去你大量的时间,占据了大量空间,还有是不是重复打包
还有一个直观而又酷炫的方式github.com/alexkuz/web…
我经过alias和external优化了下,效果仍是挺明显的,最后本地生产环境打包大概14-20s,也还能够接受,可是估计还有优化的空间,其实我也试过happypack和并行的uglify,不过发现没什么效果= =
//...
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [join(__dirname, './node_modules')],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'vuex$': 'vuex/dist/vuex.esm.js',
'vue-router$': 'vue-router/dist/vue-router.esm.js',
'simplemde$': 'simplemde/dist/simplemde.min.js',
'highlight.js$': 'highlight.js/lib/highlight.js',
'fastclick': 'fastclick/lib/fastclick.js',
'lib': resolve(__dirname, './client/src/lib'),
'api': resolve(__dirname, './client/src/api'),
'publicComponents': resolve(__dirname, './client/src/components'),
}
},
//...
// html template引入simplemde cdn
externals: {
'simplemde': 'SimpleMDE'
},
//...复制代码
还有一些缓存优化的问题,就是js/css的hash问题,js chunkhash而后提取css使用contenthash,为了不改动vendor的hash,commonChunk额外提取出manifest(extract the webpack bootstrap logic into a separate file
),这样当vendor没有被修改的时候,从新运行webpack不会再生产新的hash,变更的只有manifest,具体能够看webpack.js.org/plugins/com…
其实只须要根据模块划分而后多写几行配置就行,要作相似脚手架的话可使用glob
这些工具
具体看代码吧,会生成如下目录
dist
|---css
|---modules
|---admin.xxx.css
|---front.xxx.css
|---fonts
|---modules
|---admin.xxx.min.js
|---front.xxx.min.js
|---vendor_admin.xxx.min.js
|---vendor_front.xxx.min.js
|---manifest_admin.xxx.min.js
|---manifest_front.xxx.min.js
|---static
|---admin.html
|---front.html复制代码
表示以前我在玩耍node服务的时候都是使用screen命令的,pm2确实很赞,监控/日志管理这些都很完善,日志方面我还使用了pm2-logrotate
pm2 install pm2-logrotate
pm2 set pm2-logrotate:retain 100 //控制日志数量
pm2 set pm2-logrotate:size 1M //控制日志切割大小复制代码
nginx基本是上线必备,应该也不用多说了,开启gzip效果确实很显著,原本前台的vendor_front从227k直接被压缩到84k,简直cool!😆
谢谢阅读~
欢迎follow我哈哈github.com/BUPT-HJM
看到这里,不star不行了😋
github.com/BUPT-HJM/vu…
欢迎继续观光个人博客~
欢迎关注