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. 留言板

頁面詳情看這裡

後台頁面

  1. 主頁
  2. 發佈文章
  3. 關於我
  4. 評論列表
  5. 設置

其他的例如文章列表等我後面會別補上,「主要是想讓你們研究透代碼,自己去寫,因為真的很簡單(手動狗頭)」

頁面詳情看這裡

後端相關

  1. 數據庫操作使用 sequelize
  2. 後端框架使用 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

然後點擊右邊的「免費授權頁面」填寫相應資料即可下載

  1. 首先需要安裝「nodeJs」,百度安裝方式很多,請自選其一,安裝完成後node -v,能打印出版本代表安裝完成, 安裝完成後設置為淘寶鏡像:「npm config set registry //registry.npm.taobao.org」

    選裝[「nvm」(node管理工具), 「git」]

  2. nginx 安裝可以看這裡,或者百度教程很多

  3. 「mysql」 百度一下,你就知道~~

  4. navicat(數據庫操作工具), 可以使用「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文件夾裏面的放置放到同級

皆大歡喜,做到這裡就完成了。接下使用 域名就能訪問啦

例如我的博客

日誌記錄

放置到服務器後,出了問題,肯定不像本地開發調試一樣方便,所以我們需要「日誌記錄」,來定位問題

我採用的庫是 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吧!!

喜歡技術的也可以加我,一起進步。

郵箱: [email protected]

微信號: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 命令分別打包前台和後台**執行打包後的結構是這樣的
![](//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2819cf6a0eb94f159ce1f38f0b581322~tplv-k3u1fbpfcp-watermark.image)
接下來把項目(除client和backstage和node_modules以外)放置到服務器的dist文件夾中(然後打該目錄執行**npm i**下載依賴)
![](//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/513eb7328a604833b6eb9ba51635320f~tplv-k3u1fbpfcp-watermark.image)
由於對nginx不熟悉,所以我這裡public文件放置得做一些改動,熟悉的可以自行配置(順便教下我。。)
![](//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4008502c23024cde872c20e3510eb992~tplv-k3u1fbpfcp-watermark.image)
就是把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統一
![](//p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2d8464af989e4e83b20f67dc3dda583e~tplv-k3u1fbpfcp-watermark.image)#### 合併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