Vue、Node全棧項目~面向小白的部落格系統~
- 2020 年 11 月 3 日
- 筆記
前言
❝
程式碼品質問題輕點噴(去年才學的前端),有啥建議歡迎聯繫我,聯繫方式見最下方,感謝!
頁面有啥bug也可以回饋給我,感謝! 這是一套包含前後端程式碼的個人部落格系統,歡迎各位提出建議,本來打算用nuxt來書寫,但是想學了react之後用next來寫,後面會用reactSSR來重構!
❞
部落格該有的功能都有,可以寫文章,可以評論,可以留言,甚至可以玩遊戲(雖然還沒完善),等等讓你來發現。
這是一個小型的全棧項目,主要是檢驗並記錄一下自己的學習成果
運用的技術Vue、Vue-Cli、Element-Ui、後端NodeJs、資料庫MySql等各種技術
看到這裡了,請你們不要白嫖,點個star(O(∩_∩)O)
前台頁面
- 頁面設計 借鑒開源項目「白茶」
「支援PC端和移動端,響應式頁面,更多頁面戲節讓你去發掘」
1. 主頁
2. 文章列表
3. 聽雨
4. Demo
5. 關於我
6. 留言板
頁面詳情看這裡
後台頁面
- 主頁
- 發布文章
- 關於我
- 評論列表
- 設置
其他的例如文章列表等我後面會別補上,「主要是想讓你們研究透程式碼,自己去寫,因為真的很簡單(手動狗頭)」
頁面詳情看這裡
後端相關
「sequelize」和「koa」在此項目中的使用有機會我會寫成對應的文章出來
❝
資料庫表結構
❞
「這個部落格里本來打算實現文章分類功能,後面感覺不需要,就沒用到這個表了」
- 用戶表 ID 用戶名 用戶帳號 用戶密碼 生日 頭像 創建時間
- 文章表 ID 用戶ID 文章標題 文章圖片 文章music 文章內容 分類ID(外鍵) 文章摘要 發布時間 瀏覽人數 喜歡人數 評論數(通過文章留言板去查) 分類ID
- 文章留言表 ID 留言文章ID 留言用戶ID 留言內容 留言時間
- 分類表 ID 分類名稱
- 留言表 ID 留言用戶ID 留言內容
- 用戶是否喜歡文章表 ID 用戶ID 文章ID (通過多對多關係生產)
❝
表關係
❞
- 一個分類有多個文章(一對多)
- 一篇文章可以有多個評論(一對多)
- 一個用戶可以評論多篇文章(一對多)
- 一個用戶可以留言多次(一對多)
- 一篇文章可以被多個用戶喜歡,一個用戶可以喜歡多個文章(多對多)
程式碼目錄介紹及運行介紹
後端程式碼採用三層架構模式
❝
models 是表現層
services 是業務邏輯層
routes 是數據訪問層
❞
- 「backstage」 是後台管理系統
- 「client」 是前端
「拉取程式碼後先在根目錄和client文件夾裡面和backstage都執行 npm install安裝依賴」
「之後首先要在跟目錄創建public和encrypt文件夾」
「public文件夾裡面要創建upload文件夾,上傳文件需要,打包前端程式碼也是打包到這個目錄」
「encrypt裡面要創建dbEncrypt.js和ossEncrypt.js」
可隨時在models/tables/db.js裡面切換
本地開發就用localDbInfo裡面的,注意要在db.js切換
——————————資料庫請自行安裝————————————
dbEncrypt.js
module.exports = {
localDbInfo: {
dbName: 'XXX', // 資料庫名稱
userName: 'XXX', // 資料庫用戶名
password: 'XXX', // 資料庫密碼
host: {
host: 'localhost',
dialect: 'mysql'
}
},
aliDbInfo: { // 伺服器上的資料庫資訊,同上
dbName: 'XXX',
userName: 'XXX',
password: 'XXX',
host: {
host: 'XXX',
dialect: 'mysql'
}
}
}
如果沒有伺服器,本地開發的話就不需要這個了
我寫了兩個上傳文件的介面,/upload和/ossUpload,沒有伺服器就切換成/upload就行了
ossEncrypt.js
module.exports = {
region: 'XXX', // OSS region
accessKeyId: 'XXXXXX', OSS accessKeyId
accessKeySecret: 'XXXXXX', OSS accessKeySecret
bucket: 'XXXX', // OSS bucket名
}
接下來就可以愉快的玩耍了
「確保資料庫資訊填寫正確之後 在根目錄輸入在 npm sync 同步資料庫,提示同步完成即可」 「然後輸入npm start 開啟服務,這樣本地服務就跑起來了」 「接下來就跟平時開發一樣跑前端就行了,進入client或者backstage 輸入 npm run dev 進入開發模式」
部署
首先你得有一個自己的伺服器,我用的是阿里雲
這裡推薦一個我用的伺服器工具 xShell和xFtp
然後點擊右邊的「免費授權頁面」填寫相應資料即可下載
-
首先需要安裝「nodeJs」,百度安裝方式很多,請自選其一,安裝完成後node -v,能列印出版本代表安裝完成, 安裝完成後設置為淘寶鏡像:「npm config set registry //registry.npm.taobao.org」
❝
選裝[「nvm」(node管理工具), 「git」]
❞
-
「nginx」 安裝可以看這裡,或者百度教程很多
-
「mysql」 百度一下,你就知道~~
-
「navicat」(資料庫操作工具), 可以使用「navicat註冊機」破解,教程點此
-
「打開navicat連接上伺服器的資料庫,連接成功即可」
-
「pm2」(PM2是node進程管理工具,可以利用它來簡化很多node應用管理的繁瑣任務,如性能監控、自動重啟、負載均衡等,而且使用非常簡單)
❝
安裝命令:npm install pm2@latest -g
❞
❝
pm2 -v列印版本即安裝成功
❞
-
打開伺服器和阿里雲上相應的埠(3306,5008,80)
-
「nginx配置」
為什麼是5008,因為我koa監聽的是5008埠
❝
這裡給出我的nginx配置
❞
user root root;
worker_processes auto;
error_log /www/logs/nginx_error.log crit;
pid /www/server/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
events
{
use epoll;
worker_connections 51200;
multi_accept on;
}
http
{
include mime.types;
#include luawaf.conf;
# 設置快取路徑並且使用一塊最大100M的共享記憶體,用於硬碟上的文件索引,包括文件名和請求次數,每個文件在1天內若不活躍(無請求)則從硬碟上淘汰,硬碟快取最大10G,滿了則根據LRU演算法自動清除快取。
proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=imgcache:100m inactive=1d max_size=10g;
include proxy.conf;
default_type application/octet-stream;
server_names_hash_bucket_size 512;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 100m;
sendfile on;
tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
#開啟和關閉gzip模式
gzip on;
#gizp壓縮起點,文件大於1k才進行壓縮
gzip_min_length 1k;
# 設置壓縮所需要的緩衝區大小,以4k為單位,如果文件為7k則申請2*4k的緩衝區
gzip_buffers 4 16k;
#nginx對於靜態文件的處理模組,開啟後會尋找以.gz結尾的文件,直接返回,不會佔用cpu進行壓縮,如果找不到則不進行壓縮
gzip_static on;
# 識別http協議的版本,早起瀏覽器可能不支援gzip自解壓,用戶會看到亂碼
gzip_http_version 1.1;
# gzip 壓縮級別,1-9,數字越大壓縮的越好,也越佔用CPU時間
gzip_comp_level 1;
# 進行壓縮的文件類型。
gzip_types text/plain application/json application/javascript application/x-javascript text/javascript text/css application/xml image/jpeg image/gif image/png video/mpeg audio/x-pn-realaudio audio/x-midi audio/basic audio/mpeg audio/ogg audio/* video/mp4;
# 啟用應答頭"Vary: Accept-Encoding"
gzip_vary on;
# nginx做為反向代理時啟用,off(關閉所有代理結果的數據的壓縮),expired(啟用壓縮,如果header頭中包括"Expires"頭資訊),no-cache(啟用壓縮,header頭中包含"Cache-Control:no-cache"),no-store(啟用壓縮,header頭中包含"Cache-Control:no-store"),private(啟用壓縮,header頭中包含"Cache-Control:private"),no_last_modefied(啟用壓縮,header頭中不包含"Last-Modified"),no_etag(啟用壓縮,如果header頭中不包含"Etag"頭資訊),auth(啟用壓縮,如果header頭中包含"Authorization"頭資訊)
gzip_proxied expired no-cache no-store private auth;
# (IE5.5和IE6 SP1使用msie6參數來禁止gzip壓縮 )指定哪些不需要gzip壓縮的瀏覽器(將和User-Agents進行匹配),依賴於PCRE庫
gzip_disable "MSIE [1-6]\.";
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server_tokens off;
access_log off;
# 是否啟用在on-the-fly方式壓縮文件,啟用後,將會在響應時對文件進行壓縮並返回。
brotli on;
# 啟用後將會檢查是否存在帶有br擴展的預先壓縮過的文件。如果值為always,則總是使用壓縮過的文件,而不判斷瀏覽器是否支援。
brotli_static always;
# 設置壓縮品質等級。取值範圍是0到11.
brotli_comp_level 6;
# 設置緩衝的數量和大小。大小默認為一個記憶體頁的大小,也就是4k或者8k。
brotli_buffers 16 8k;
# 設置需要進行壓縮的最小響應大小。
brotli_min_length 20;
# 指定對哪些內容編碼類型進行壓縮。text/html內容總是會被進行壓縮
brotli_types text/plain application/json application/javascript application/x-javascript text/javascript text/css application/xml image/jpeg image/gif image/png video/mpeg audio/x-pn-realaudio audio/x-midi audio/basic audio/mpeg audio/ogg audio/* video/mp4;
server {
listen 80;
# 您的域名
server_name xxxxxx.xxx;
location ^~ / {
proxy_cache imgcache;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
proxy_cache_valid 200 304 302 24h;
proxy_pass //www.域名:5008;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
rewrite ^.+(?<!js|css|png|map)$ /index.html break;
autoindex on;
index index.htm index.html;
set $fallback_uri /index.html;
if ($http_accept !~ text/html) {
set $fallback_uri /null;
}
try_files $uri $uri/ $fallback_uri = 404;
}
location ^~ /pc {
proxy_pass //www.域名:5008/back;
index index.htm index.html;
}
}
include /www/server/panel/vhost/nginx/*.conf;
}
一切準備工作已就緒,可以把項目部署到伺服器上了
「執行 npm run build 命令分別打包前台和後台」 執行打包後的結構是這樣的
接下來把項目(除client和backstage和node_modules以外)放置到伺服器的dist文件夾中(然後打該目錄執行「npm i」下載依賴)
由於對nginx不熟悉,所以我這裡public文件放置得做一些改動,熟悉的可以自行配置(順便教下我。。)
就是把pc文件夾裡面的放置放到同級
皆大歡喜,做到這裡就完成了。接下使用 域名就能訪問啦
日誌記錄
放置到伺服器後,出了問題,肯定不像本地開發調試一樣方便,所以我們需要「日誌記錄」,來定位問題
我採用的庫是 log4js打不開就得翻牆,我只記錄了介面調用記錄,需要sql調用記錄的可以自行加上 npm i koa-log4
const log4js = require('koa-log4')
const path = require('path')
log4js.configure({
appenders: {
api: {
type: 'dateFile',
filename: path.resolve(__dirname, 'logs', 'api', 'logging.log'),
maxLogSize: 1024 * 1024, // 配置文件的最大位元組數
keepFileExt: 3, // 最多保存3天
layout: {
type: 'pattern',
pattern: '%c [%d{yyyy-MM-dd hh:mm:ss}] [%p]:%m%n'
}
},
default: {
type: 'stdout'
}
},
categories: {
api: {
appenders: ['api'],
level: 'all'
},
default: {
appenders: ['default'],
level: 'all'
}
}
})
process.on("exit", () => {
log4js.shutdown()
})
const apiLogger = log4js.getLogger("api")
exports.apiLogger = apiLogger
然後創建一個中間件
// apiLoggerMiddleware.js
const { apiLogger } = require('../logger')
// 處理錯誤的中間件
module.exports = async (ctx, next) => {
try {
await next();
}
finally {
apiLogger.debug(`${ctx.method} ${ctx.path} ${JSON.stringify(ctx.body)}`)
}
};
//init.js
app.use(require('./apiLoggerMiddleware')) // API請求日誌
首頁載入速度優化
用vue-cli正常打包後,會生成「多個chunk-hash.js 和 chunk-hash.css」,些許增加訪問速度,所以我們需要把對應和合為一個
合併chunk-hash.js
在所有非同步組件前增加以下程式碼,目的是把打包的chunk統一
合併chunk-hash.css
vue.config.js
module.exports = {
configureWebpack: config => {
// 公共程式碼抽離
config.optimization.splitChunks.cacheGroups = {
vendor: {
chunks: 'all',
test: /node_modules/,
name: 'vendor',
minChunks: 1,
maxInitialRequests: 5,
minSize: 0,
priority: 100
},
common: {
chunks: 'all',
test: /[\\/]src[\\/]js[\\/]/,
name: 'common',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 60
},
styles: {
name: 'styles',
test: /\.(le|sa|sc|c)ss$/,
chunks: 'all',
reuseExistingChunk: true,
minChunks: 1,
enforce: true
}
}
}
}
index.html
「XXX是我的名字」
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="XXX,一名前端工程師,這是我的個人部落格,網站文章隨便寫,想寫啥寫啥">
<meta name="keywords" content="個人部落格,XXX,前端,技術,WEB,blog,BLOG,搭建部落格,前端技術,VUE部落格,XXX的部落格">
<meta name="anthor" content="XXX,[email protected]">
<meta name="robots" content="部落格, 前端, blog, 個人部落格, XXX, Yong,XXX的部落格,web,VUE,React">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<link rel="icon" href="//qiheizhiya.oss-cn-shenzhen.aliyuncs.com/image/favicon.ico">
<!-- 使用CDN的CSS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.css) { %>
<link
href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
rel="stylesheet"
/>
<% } %>
<title>漆黑之牙</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<!-- 使用CDN的JS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<!-- 使用CDN的JS文件 -->
</body>
</html>
cdn
vue.config.js
const isProduction = process.env.NODE_ENV === 'production';
const cdn = {
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'axios': 'axios',
"element-ui": "ELEMENT",
},
css: [
'//lib.baomitu.com/element-ui/2.13.2/theme-chalk/index.css'
],
js: [
'//cdn.bootcss.com/vue/2.6.10/vue.min.js',
'//cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
'//cdn.bootcss.com/vuex/3.1.2/vuex.min.js',
'//lib.baomitu.com/element-ui/2.13.2/index.js',
'//cdn.bootcss.com/axios/0.19.2/axios.min.js'
]
}
module.exports = {
chainWebpack: config => {
// 注入cdn
config.plugin('html').tap(args => {
// 生產環境或本地需要cdn時,才注入cdn
if (isProduction) { args[0].cdn = cdn }
return args
})
},
configureWebpack: config => {
config.externals = cdn.externals
}
}
前端gzip
npm i -d compression-webpack-plugin
vue.config.js
//也是在configureWebpack中
//gzip壓縮
config.plugins.push(new CompressionPlugin({
filename: '[path].gz[query]',
//壓縮演算法
algorithm: 'gzip',
//匹配文件
test: /\.js$|\.css$|\.html$|\.woff$|\.ttf$|\.eot$|/,
//壓縮超過此大小的文件,以位元組為單位
threshold: 1024,
minRatio: 0.8,
//刪除原始文件只保留壓縮後的文件
deleteOriginalAssets: isProduction
}))
「完整配置請自行看client中的vue.config.js」
優化前:1M頻寬才首屏載入「10多秒」
優化後:正常情況下首屏載入「1,2秒」
最後
不知不覺寫的太多了
項目無模板,純手寫
分享自己的一個全棧簡單項目給大家,有什麼建議/bug/優化可以提一下,感謝!!。
如果看到這裡,就請幫忙點個star吧!!
喜歡技術的也可以加我,一起進步。
微訊號:qwer880620
# <center>個人部落格系統</center>
## 前言> 程式碼品質問題輕點噴(去年才學的前端),有啥建議歡迎聯繫我,聯繫方式見最下方,感謝!>> 頁面有啥bug也可以回饋給我,感謝!這是一套包含前後端程式碼的個人部落格系統,歡迎各位提出建議,本來打算用nuxt來書寫,但是想學了react之後用next來寫,後面會用reactSSR來重構!
部落格該有的功能都有,可以寫文章,可以評論,可以留言,甚至可以玩遊戲(雖然還沒完善),等等讓你來發現。
這是一個小型的全棧項目,主要是檢驗並記錄一下自己的學習成果
運用的技術Vue、Vue-Cli、Element-Ui、後端NodeJs、資料庫MySql等各種技術
看到這裡了,請你們不要白嫖,點個[star(O(∩_∩)O)](//github.com/qiheizhiya/myBlog)
### 前台頁面- 頁面設計 借鑒開源項目**白茶** **支援PC端和移動端,響應式頁面,更多頁面戲節讓你去發掘**
1. 主頁
2. 文章列表
3. 聽雨
4. Demo
5. 關於我
6. 留言板
頁面詳情看[這裡](//www.llongjie.top)### 後台頁面1. 主頁2. 發布文章3. 關於我4. 評論列表5. 設置 其他的例如文章列表等我後面會別補上,**主要是想讓你們研究透程式碼,自己去寫,因為真的很簡單(手動狗頭)**
頁面詳情看[這裡](//www.llongjie.top/pc)### 後端相關1. 資料庫操作使用 [sequelize](//github.com/demopark/sequelize-docs-Zh-CN)2. 後端框架使用 [koa](//www.w3cways.com/doc/koa/)
**sequelize**和**koa**在此項目中的使用有機會我會寫成對應的文章出來
> 資料庫表結構>**這個部落格里本來打算實現文章分類功能,後面感覺不需要,就沒用到這個表了**1. 用戶表 ID 用戶名 用戶帳號 用戶密碼 生日 頭像 創建時間 2. 文章表 ID 用戶ID 文章標題 文章圖片 文章music 文章內容 分類ID(外鍵) 文章摘要 發布時間 瀏覽人數 喜歡人數 評論數(通過文章留言板去查) 分類ID 3. 文章留言表 ID 留言文章ID 留言用戶ID 留言內容 留言時間4. 分類表 ID 分類名稱 5. 留言表 ID 留言用戶ID 留言內容6. 用戶是否喜歡文章表 ID 用戶ID 文章ID (通過多對多關係生產)
> 表關係1. 一個分類有多個文章(一對多)2. 一篇文章可以有多個評論(一對多)3. 一個用戶可以評論多篇文章(一對多)4. 一個用戶可以留言多次(一對多)5. 一篇文章可以被多個用戶喜歡,一個用戶可以喜歡多個文章(多對多) ### 程式碼目錄介紹及運行介紹後端程式碼採用三層架構模式> models 是表現層> > services 是業務邏輯層> > routes 是數據訪問層>1. **backstage** 是後台管理系統2. **client** 是前端
**拉取程式碼後先在根目錄和client文件夾裡面和backstage都執行 npm install安裝依賴**
**之後首先要在跟目錄創建public和encrypt文件夾**
**public文件夾裡面要創建upload文件夾,上傳文件需要,打包前端程式碼也是打包到這個目錄**
**encrypt裡面要創建dbEncrypt.js和ossEncrypt.js**
“` 可隨時在models/tables/db.js裡面切換本地開發就用localDbInfo裡面的,注意要在db.js切換
——————————資料庫請自行安裝————————————
dbEncrypt.js module.exports = { localDbInfo: { dbName: ‘XXX’, // 資料庫名稱 userName: ‘XXX’, // 資料庫用戶名 password: ‘XXX’, // 資料庫密碼 host: { host: ‘localhost’, dialect: ‘mysql’ } }, aliDbInfo: { // 伺服器上的資料庫資訊,同上 dbName: ‘XXX’, userName: ‘XXX’, password: ‘XXX’, host: { host: ‘XXX’, dialect: ‘mysql’ } }}“““如果沒有伺服器,本地開發的話就不需要這個了我寫了兩個上傳文件的介面,/upload和/ossUpload,沒有伺服器就切換成/upload就行了ossEncrypt.js module.exports = { region: ‘XXX’, // OSS region accessKeyId: ‘XXXXXX’, OSS accessKeyId accessKeySecret: ‘XXXXXX’, OSS accessKeySecret bucket: ‘XXXX’, // OSS bucket名 }“`
接下來就可以愉快的玩耍了
**確保資料庫資訊填寫正確之後 在根目錄輸入在 npm sync 同步資料庫,提示同步完成即可****然後輸入npm start 開啟服務,這樣本地服務就跑起來了****接下來就跟平時開發一樣跑前端就行了,進入client或者backstage 輸入 npm run dev 進入開發模式**
### 部署首先你得有一個自己的伺服器,我用的是阿里雲
這裡推薦一個我用的伺服器工具[xShell和xFtp](//www.netsarang.com/zh/xshell-download/)
然後點擊右邊的**免費授權頁面**填寫相應資料即可下載
1. 首先需要安裝**nodeJs**,百度安裝方式很多,請自選其一,安裝完成後node -v,能列印出版本代表安裝完成, 安裝完成後設置為淘寶鏡像:**npm config set registry //registry.npm.taobao.org**> 選裝[**nvm**(node管理工具), **git**]2. **[nginx](//www.llongjie.top/detail/55)** 安裝可以看這裡,或者百度教程很多 3. **mysql** 百度一下,你就知道~~4. **[navicat](//www.navicat.com.cn/)**(資料庫操作工具), 可以使用**navicat註冊機**破解,教程點此5. **打開navicat連接上伺服器的資料庫,連接成功即可**6. **pm2**(PM2是node進程管理工具,可以利用它來簡化很多node應用管理的繁瑣任務,如性能監控、自動重啟、負載均衡等,而且使用非常簡單)> 安裝命令:npm install pm2@latest -g > pm2 -v列印版本即安裝成功7. 打開伺服器和阿里雲上相應的埠(3306,5008,80)8. **nginx配置**
為什麼是5008,因為我koa監聽的是5008埠 > 這裡給出我的nginx配置“` user root root; worker_processes auto; error_log /www/logs/nginx_error.log crit; pid /www/server/nginx/logs/nginx.pid; worker_rlimit_nofile 51200; events { use epoll; worker_connections 51200; multi_accept on; }
http { include mime.types; #include luawaf.conf;
# 設置快取路徑並且使用一塊最大100M的共享記憶體,用於硬碟上的文件索引,包括文件名和請求次數,每個文件在1天內若不活躍(無請求)則從硬碟上淘汰,硬碟快取最大10G,滿了則根據LRU演算法自動清除快取。 proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=imgcache:100m inactive=1d max_size=10g;
include proxy.conf;
default_type application/octet-stream; server_names_hash_bucket_size 512; client_header_buffer_size 32k; large_client_header_buffers 4 32k; client_max_body_size 100m;
sendfile on; tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 256k;fastcgi_intercept_errors on; #開啟和關閉gzip模式 gzip on; #gizp壓縮起點,文件大於1k才進行壓縮 gzip_min_length 1k; # 設置壓縮所需要的緩衝區大小,以4k為單位,如果文件為7k則申請2*4k的緩衝區 gzip_buffers 4 16k; #nginx對於靜態文件的處理模組,開啟後會尋找以.gz結尾的文件,直接返回,不會佔用cpu進行壓縮,如果找不到則不進行壓縮 gzip_static on; # 識別http協議的版本,早起瀏覽器可能不支援gzip自解壓,用戶會看到亂碼 gzip_http_version 1.1; # gzip 壓縮級別,1-9,數字越大壓縮的越好,也越佔用CPU時間 gzip_comp_level 1; # 進行壓縮的文件類型。 gzip_types text/plain application/json application/javascript application/x-javascript text/javascript text/css application/xml image/jpeg image/gif image/png video/mpeg audio/x-pn-realaudio audio/x-midi audio/basic audio/mpeg audio/ogg audio/* video/mp4; # 啟用應答頭”Vary: Accept-Encoding” gzip_vary on; # nginx做為反向代理時啟用,off(關閉所有代理結果的數據的壓縮),expired(啟用壓縮,如果header頭中包括”Expires”頭資訊),no-cache(啟用壓縮,header頭中包含”Cache-Control:no-cache”),no-store(啟用壓縮,header頭中包含”Cache-Control:no-store”),private(啟用壓縮,header頭中包含”Cache-Control:private”),no_last_modefied(啟用壓縮,header頭中不包含”Last-Modified”),no_etag(啟用壓縮,如果header頭中不包含”Etag”頭資訊),auth(啟用壓縮,如果header頭中包含”Authorization”頭資訊) gzip_proxied expired no-cache no-store private auth; # (IE5.5和IE6 SP1使用msie6參數來禁止gzip壓縮 )指定哪些不需要gzip壓縮的瀏覽器(將和User-Agents進行匹配),依賴於PCRE庫 gzip_disable “MSIE [1-6]\.”;
limit_conn_zone $binary_remote_addr zone=perip:10m;limit_conn_zone $server_name zone=perserver:10m;
server_tokens off; access_log off;
# 是否啟用在on-the-fly方式壓縮文件,啟用後,將會在響應時對文件進行壓縮並返回。 brotli on; # 啟用後將會檢查是否存在帶有br擴展的預先壓縮過的文件。如果值為always,則總是使用壓縮過的文件,而不判斷瀏覽器是否支援。 brotli_static always; # 設置壓縮品質等級。取值範圍是0到11. brotli_comp_level 6; # 設置緩衝的數量和大小。大小默認為一個記憶體頁的大小,也就是4k或者8k。 brotli_buffers 16 8k; # 設置需要進行壓縮的最小響應大小。 brotli_min_length 20; # 指定對哪些內容編碼類型進行壓縮。text/html內容總是會被進行壓縮 brotli_types text/plain application/json application/javascript application/x-javascript text/javascript text/css application/xml image/jpeg image/gif image/png video/mpeg audio/x-pn-realaudio audio/x-midi audio/basic audio/mpeg audio/ogg audio/* video/mp4; server { listen 80; # 您的域名 server_name xxxxxx.xxx; location ^~ / { proxy_cache imgcache; proxy_cache_key $scheme$proxy_host$uri$is_args$args; proxy_cache_valid 200 304 302 24h; proxy_pass //www.域名:5008; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Nginx-Proxy true; proxy_redirect off; rewrite ^.+(?<!js|css|png|map)$ /index.html break; autoindex on; index index.htm index.html; set $fallback_uri /index.html; if ($http_accept !~ text/html) { set $fallback_uri /null; } try_files $uri $uri/ $fallback_uri = 404; } location ^~ /pc { proxy_pass //www.域名:5008/back; index index.htm index.html; } } include /www/server/panel/vhost/nginx/*.conf; }
“`一切準備工作已就緒,可以把項目部署到伺服器上了
**執行 npm run build 命令分別打包前台和後台**執行打包後的結構是這樣的

接下來把項目(除client和backstage和node_modules以外)放置到伺服器的dist文件夾中(然後打該目錄執行**npm i**下載依賴)

由於對nginx不熟悉,所以我這裡public文件放置得做一些改動,熟悉的可以自行配置(順便教下我。。)

就是把pc文件夾裡面的放置放到同級
皆大歡喜,做到這裡就完成了。接下使用 域名就能訪問啦
[例如我的部落格](//www.llongjie.top)
### 日誌記錄放置到伺服器後,出了問題,肯定不像本地開發調試一樣方便,所以我們需要**日誌記錄**,來定位問題
我採用的庫是 [log4js](//log4js-node.github.io/log4js-node/)打不開就得翻牆,我只記錄了介面調用記錄,需要sql調用記錄的可以自行加上npm i koa-log4
“`const log4js = require(‘koa-log4’)const path = require(‘path’)
log4js.configure({ appenders: { api: { type: ‘dateFile’, filename: path.resolve(__dirname, ‘logs’, ‘api’, ‘logging.log’), maxLogSize: 1024 * 1024, // 配置文件的最大位元組數 keepFileExt: 3, // 最多保存3天 layout: { type: ‘pattern’, pattern: ‘%c [%d{yyyy-MM-dd hh:mm:ss}] [%p]:%m%n’ } }, default: { type: ‘stdout’ } }, categories: { api: { appenders: [‘api’], level: ‘all’ }, default: { appenders: [‘default’], level: ‘all’ } }})
process.on(“exit”, () => { log4js.shutdown()})
const apiLogger = log4js.getLogger(“api”)
exports.apiLogger = apiLogger“`
然後創建一個中間件
“`// apiLoggerMiddleware.jsconst { apiLogger } = require(‘../logger’)
// 處理錯誤的中間件module.exports = async (ctx, next) => { try { await next(); } finally { apiLogger.debug(`${ctx.method} ${ctx.path} ${JSON.stringify(ctx.body)}`) }
};
//init.jsapp.use(require(‘./apiLoggerMiddleware’)) // API請求日誌“`
### 首頁載入速度優化用vue-cli正常打包後,會生成**多個chunk-hash.js 和 chunk-hash.css**,些許增加訪問速度,所以我們需要把對應和合為一個#### 合併chunk-hash.js在所有非同步組件前增加以下程式碼,目的是把打包的chunk統一
#### 合併chunk-hash.cssvue.config.js“`module.exports = {configureWebpack: config => { // 公共程式碼抽離 config.optimization.splitChunks.cacheGroups = { vendor: { chunks: ‘all’, test: /node_modules/, name: ‘vendor’, minChunks: 1, maxInitialRequests: 5, minSize: 0, priority: 100 }, common: { chunks: ‘all’, test: /[\\/]src[\\/]js[\\/]/, name: ‘common’, minChunks: 2, maxInitialRequests: 5, minSize: 0, priority: 60 }, styles: { name: ‘styles’, test: /\.(le|sa|sc|c)ss$/, chunks: ‘all’, reuseExistingChunk: true, minChunks: 1, enforce: true } } }}“`index.html
**XXX是我的名字**“`<!DOCTYPE html><html lang=”en”> <head> <meta charset=”utf-8″> <meta http-equiv=”X-UA-Compatible” content=”IE=edge”> <meta name=”description” content=”XXX,一名前端工程師,這是我的個人部落格,網站文章隨便寫,想寫啥寫啥”> <meta name=”keywords” content=”個人部落格,XXX,前端,技術,WEB,blog,BLOG,搭建部落格,前端技術,VUE部落格,XXX的部落格”> <meta name=”anthor” content=”XXX,[email protected]”> <meta name=”robots” content=”部落格, 前端, blog, 個人部落格, XXX, Yong,XXX的部落格,web,VUE,React”> <meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no”> <link rel=”icon” href=”//qiheizhiya.oss-cn-shenzhen.aliyuncs.com/image/favicon.ico”> <!– 使用CDN的CSS文件 –> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %> <link href=”<%= htmlWebpackPlugin.options.cdn.css[i] %>” rel=”stylesheet” /> <% } %> <title>漆黑之牙</title> </head> <body> <noscript> <strong>We’re sorry but <%= htmlWebpackPlugin.options.title %> doesn’t work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id=”app”></div> <!– built files will be auto injected –>
<!– 使用CDN的JS文件 –> <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> <script src=”<%= htmlWebpackPlugin.options.cdn.js[i] %>”></script> <% } %> <!– 使用CDN的JS文件 –> </body></html>
“`#### cdnvue.config.js“` const isProduction = process.env.NODE_ENV === ‘production’;const cdn = { externals: { ‘vue’: ‘Vue’, ‘vuex’: ‘Vuex’, ‘vue-router’: ‘VueRouter’, ‘axios’: ‘axios’, “element-ui”: “ELEMENT”, }, css: [ ‘//lib.baomitu.com/element-ui/2.13.2/theme-chalk/index.css’ ], js: [ ‘//cdn.bootcss.com/vue/2.6.10/vue.min.js’, ‘//cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js’, ‘//cdn.bootcss.com/vuex/3.1.2/vuex.min.js’, ‘//lib.baomitu.com/element-ui/2.13.2/index.js’, ‘//cdn.bootcss.com/axios/0.19.2/axios.min.js’ ]}module.exports = {chainWebpack: config => { // 注入cdn config.plugin(‘html’).tap(args => { // 生產環境或本地需要cdn時,才注入cdn if (isProduction) { args[0].cdn = cdn } return args }) }, configureWebpack: config => { config.externals = cdn.externals }}“`#### 前端gzipnpm i -d compression-webpack-plugin
vue.config.js“`//也是在configureWebpack中//gzip壓縮 config.plugins.push(new CompressionPlugin({ filename: ‘[path].gz[query]’, //壓縮演算法 algorithm: ‘gzip’, //匹配文件 test: /\.js$|\.css$|\.html$|\.woff$|\.ttf$|\.eot$|/, //壓縮超過此大小的文件,以位元組為單位 threshold: 1024, minRatio: 0.8, //刪除原始文件只保留壓縮後的文件 deleteOriginalAssets: isProduction }))“`
**完整配置請自行看client中的vue.config.js**
優化前:1M頻寬才首屏載入**10多秒**
優化後:正常情況下首屏載入**1,2秒**
### 最後
不知不覺寫的太多了
項目無模板,純手寫
分享自己的一個全棧簡單項目給大家,有什麼建議/bug/優化可以提一下,感謝!!。
如果看到這裡,就請幫忙點個[star](//github.com/qiheizhiya/myBlog)吧!!
喜歡技術的也可以加我,一起進步。
郵箱: [email protected]
微訊號:qwer880620