博客終於差很少寫完了,雖然仍是可能有一堆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…
歡迎繼續觀光個人博客~
歡迎關注