淺談 VueSSR 和 Express 結合的開發模式

引言

其實這種開發模式,我之前講 VueSSR 的時候已經提過了。但是,當時只是簡單的提及一個工作目錄 entry-server.js 和 server.js 兩個和服務端相關的文件,用來進行一些後端的查詢之類的。但是如果是簡單的 VueSSR,不能完全適應一些後端的開發,如果需要多寫幾個查詢,項目的耦合性就不高了。現在,我把它補上。

目錄結構

對比我之前將的目錄結構,其實就多了個文件夾。然後,這個文件夾裏面都是和 Express 和 MySQL 相關的文件,例如連接數據庫、路由等等。並且,數據處理部分,我把它簡單地分了兩個部分 Controller、Model(一般我不用哈哈,留着已被不時之需)。所以,一個完整的 Express + VueSSR 的項目結構會是這樣:

build
├── webpack.client.config.js # 用於服務端的打包
├── webpack.server.config.js # 用於客戶端的打包

server # 和服務端相關的代碼,可以理解爲中間層
├── controllers # 進行數據的處理和返回
		├── index.js
├── db # 連接數據庫相關
		├── index.js
├── routes # 後端路由
		├── index.js
├── index.js # 整個項目入口

src
├── store
    	├── index.js # 不同於傳統的,它是一個工廠函數
├── routes 
    	├── index.js # 不同於傳統的,它是一個工廠函數
├── components # 組件
├── views # 頁面
		├── Home
				├── index.vue					
├── App.vue
├── main.js # 通用 entry(universal entry),不同於傳統的,它是一個工廠函數
├── entry-client.js # 僅運行於客戶端(瀏覽器)
└── entry-server.js # 僅運行於服務器

相比較之前的 VueSSR 其實還有一個小細節,就是我把項目入口文件改成 server 文件夾下的 index.js,其實就是爲了方便閱讀。接下來,來看看 Server 中文件夾具體作用。

作用

1.index.js 項目入口文件
首先,項目的入口遷到 server 文件夾中,也不是平白無故。因爲,要用 express 框架實現中間層的概念,所以相應地也得在項目入口中,實例化 express 並綁定路由,不過需要注意的是原來的 SSR 邏輯保持不變,不過還得設置一些 Content-Type,畢竟我們後面要傳輸 JSON 數據給前端。

// 導入路由文件
const router = require('./routes/index')
// 實例化 express
const app = express()
// 綁定路由
router(app)
...
app.get('*', isProd ? render : (req, res) => {
    console.log('請求中')
    res.setHeader('Content-Type', 'text/html;charset=utf-8')
    readyPromise.then(() => render(req, res))
})

2.routes 路由文件夾
比如說現在有個首頁 home 的 banner 對應的路由(即對應 home.js),它在 express 中路由是這樣的:

const express = require('express')
const route = express.Router()
const home = require('../controllers/home')

route.get('/api/banner', home.getBanner)

module.exports = route

在平常的開發中我們可能存在很多模塊,爲了項目的解耦,我們也需要適當地將不同模塊的路由分開在淡單獨的文件。然後,通過新建一個 index.js 文件來統一導出項目所有路由。

const home = require('./home')

module.exports = function (app) {
    app.use(home)
}

3.db 數據庫連接相關文件夾
實現中間層,意味着我們需要查詢數據庫,那就需要連接數據庫。

const mysql = require('mysql')
var pool = mysql.createPool({
    host: 'localhost',
    port: '3306',
    user: 'root',
    password: '',
    database: 'myblog'
})

const query = function (sql, callback) {
    pool.getConnection(function(err, conn) {
        if (err) {
            callback(err, null, null)
        } else {
            conn.query(sql, function(qerr, vals, fields) {
                // 釋放連接
                conn.release()
                callback(qerr, vals, fields)
            })
        }
    })
}

// 向外暴露連接數據庫的db對象
module.exports = query

連接的操作很簡單,這裏用了連接池來管理我對數據庫的連接。

4. controllers 文件夾

而 controllers 文件夾中,具體做的就是對查詢的數據進行修飾,返回給前端可以直接使用的數據格式,這裏繼續延續我們前面的 homer 模塊的 benner 路由。

const query = require("../db/index")

function getBanner(req, res, next) {
    const sql = "SELECT * FROM banner"

    query(sql, (err, result) => {
        if (err) {
            console.log(`[SELECT ERROR] - `, err.message)
            return
        }

        const data = {
            status: 1001,
            message: 'success',
            data: {
                bannerList: result
            }
        }

        res.json(data)
    })
}

module.exports = {
    getBanner
}

PS:model 文件夾就不講了,沒用過…這裏後端的同學應該更懂

總結

其實,說白了就是將 Express 應用直接嵌入到 VueSSR 項目中。很類似與以前的 MVC,可以這麼說,也可以不那麼說。因爲傳統的 MVC 已經不符合這個時代的需要,並且隨着前端的工程化,Node.js 搭建的服務更適合和 Vue、React 之類的框架搭配使用,它們所用的工具鏈,幾乎都是基於 Node 實現的,所以誇張點就是無縫銜接。當然,話說回來,用這種開發要應場景而進行不同的選擇,Node.js 並不是萬能的~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章