vue ssr服務端渲染-初學開發環境搭建

vue ssr服務端渲染-初學者的開發環境搭建

前言

默認已經瞭解ssr的基本內容和實現,不熟悉的能夠先看下vue ssr服務端渲染小白解惑html

網上有關ssr開發環境搭建的文章不算多,就算找到也是比較高級的,不太適合新手入坑;這篇內容只抽取了其中最重要的部分,實現最基礎的開發環境搭建;所謂開發環境無非兩件事:自動打包·自動刷新頁面,叫法比較土,也能夠叫熱更新,熱加載。前端

自動更新renderer

先看目錄結構
image.png
沒啥東西,新增了一個hot.config.js文件,用來放置熱加載的配置;
先看下server.jsvue

//server.js
const express = require('express');
const chalk = require('chalk');

const server = express();

let   renderer;
const hotServer = require('./webpack.hot.config.js')
//咱們但願經過不停的執行下面這樣一個函數的回調,重新實例化renderer,已達到自動更新的目的;
hotServer(server,({serverBundle,clientManifest})=>{
  console.log('hot***************************************************')
  renderer = require('vue-server-renderer').createBundleRenderer(serverBundle,{
    runInNewContext: false, // 推薦
    template: require('fs').readFileSync('./index.html', 'utf-8'),
    clientManifest // (可選)客戶端構建 manifest
  })
})
server.use('/',express.static('./dist')) // 設置訪問靜態文件路徑
server.get('*', (req, res) => {
    res.set('content-type', "text/html");
    const context = {
        url:req.url
      }

        renderer.renderToString(context, (err, html) => {
          if (err) {
            res.status(500).end('Internal Server Error')
            return
          } else {
            res.end(html)
          }
        })

  })

server.listen(8080,function(){
    let ip = getIPAdress();
    console.log(`服務器開在:http://${chalk.green(ip)}:${chalk.yellow(8080)}`)
})

function getIPAdress(){//node下的os模塊能夠拿到啓動該文件的服務端的部分信息,細節本身去node上面查
    var interfaces = require('os').networkInterfaces();
    for (var devName in interfaces) {
        var iface = interfaces[devName];
        for (var i = 0; i < iface.length; i++) {
            var alias = iface[i];
            if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
                return alias.address;
            }
        }
    }
}

跟自動化有關的代碼只有和hotServer有關的幾行代碼,其實也是通過分析,對於這個server服務,有用的文件只有服務端配置vue-ssr-server-bundle.json和客戶端配置vue-ssr-client-manifest.json,咱們只要在這兩個文件打包以後重新實例化renderer就能夠了,應爲renderer實例化是經過加載靜態文件而生產的一個再也不變化的實例;node

webpack.hot.config.js也能夠寫在server.js裏面,不過看上去就不太好看,也不符合模塊開發的原則;webpack

自動打包

webpack自動打包有watch,或者使用webpack-dev-serve,dev-server會本身啓一個服務,然而咱們有本身的server,他們之間通訊不是不能夠,只是比較困難,不適用;watch也是同樣,比較獨立;
webpack能夠獨立使用,然而它也只是node中的一個模塊,能夠做爲插件使用,並且能夠經過其餘插件和express結合使用;web

webpack-dev-middleware

webpack-dev-middleware是實現熱加載的核心組件,看一下webpack.hot.config.js的內容express

//webpack.hot.config.js
const webpack = require('webpack');
//新增webpack-dev-middleware插件
const webpackDevMiddleware = require('webpack-dev-middleware');
const path=require('path')
const clientConfig=require('./webpack.client.config.js')
const serverConfig=require('./webpack.server.config.js')
//輸出一個函數給server使用
module.exports = function(server,callBack){
    
    
    let b,c;
    //這裏先定義一個run方法,保證vue-ssr-server-bundle.json和vue-ssr-client-manifest.json都有的狀況纔去執行回調;
    function run(){
        console.log('run');
        if(b && c){
            console.log('runend ')
            callBack({serverBundle:JSON.parse(b),clientManifest:JSON.parse(c)})
        }
    }
    //生成vue-ssr-server-bundle.json
    //實例化webpack
    const serverComplier = webpack(serverConfig);
    middleware = webpackDevMiddleware(serverComplier)
    server.use(middleware);
    //serverComplier是webpack返回的實例,plugin方法能夠捕獲事件,done表示打包完成
    serverComplier.plugin('done',complation => {
        console.log('serverdown')
        //核心內容,middleware.fileSystem.readFileSync是webpack-dev-middleware提供的讀取內存中文件的方法;
        //不過拿到的是二進制,能夠用JSON.parse格式化;
        let serverBundle=middleware.fileSystem.readFileSync(path.join(serverConfig.output.path, 'vue-ssr-server-bundle.json'))
        //把拿到的文件複製給b
        b=serverBundle;
        run();
    })
    //生成vue-ssr-client-manifest.json,方法和上面如出一轍
    const clientComplier = webpack(clientConfig)
    clientMiddleware = webpackDevMiddleware(clientComplier),{
        noInfo: true,
        stats: {
            colors: true
        }
    }
    server.use(clientMiddleware)
    clientComplier.plugin('done',complation=>{
        console.log('clientdown')
        let clientBundle=clientMiddleware.fileSystem.readFileSync(path.join(clientConfig.output.path, 'vue-ssr-client-manifest.json'))
        c=clientBundle;
        run()
    })

}

webpack-dev-middleware最大的特色就是把打包好的文件放到內存中本身玩,不生成文件,對於大部分項目沒有問題,然而ssr須要讀取靜態文件才能繼續玩,webpack-dev-middleware也確實提供了讀取文件的方法middleware.fileSystem.readFileSync,相似fs插件;json

簡單說明下webpack流程,webpack是單線程,在打包的過程當中會廣播不一樣的事件告訴你們webpack如今幹到哪一步了,webpack()會返回一個實例compalier,經過compalier.plugin('done',()=>{})方式監聽webpack的狀況,這也是本身編寫webpack 插件的核心內容;done就表示打包完了,咱們就這這個時候去拿咱們想要的文件就對了;segmentfault

頁面自動刷新

默認上面的代碼沒有bug,下面這個插件沒什麼講的,知道怎麼用就好了;後端

webpack-hot-middleware

直接上最終版的代碼,server,js沒有動,修改下webpack.hot.config.js:

//webpack.hot.config.js
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
//新增webpack-hot-middleware插件
const webpackHotMiddleware = require('webpack-hot-middleware');
const path=require('path')
const clientConfig=require('./webpack.client.config.js')
const serverConfig=require('./webpack.server.config.js')

module.exports = function(server,callBack){

   
    let b,c;
    function run(){
        console.log('run');
        if(b && c){
            console.log('runend ')
            callBack({serverBundle:JSON.parse(b),clientManifest:JSON.parse(c)})
        }
    }
    const serverComplier = webpack(serverConfig) ;
    middleware = webpackDevMiddleware(serverComplier)
    server.use(middleware);
    serverComplier.plugin('done',complation => {
        console.log('serverdown')
        let serverBundle=middleware.fileSystem.readFileSync(path.join(serverConfig.output.path, 'vue-ssr-server-bundle.json'))
        b=serverBundle;
        run();
    })
    //修改入口文件,固定寫法
    clientConfig.entry=['./entry-client.js','webpack-hot-middleware/client?reload=true'];
    //新增自動更新插件,固定寫法
    clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
    //上面兩條要寫在下面這個實例化以前,很好理解
    const clientComplier = webpack(clientConfig)
    clientMiddleware = webpackDevMiddleware(clientComplier),{
        noInfo: true,
        stats: {
            colors: true
        }
    }
    server.use(clientMiddleware)
    clientComplier.plugin('done',complation=>{
        console.log('clientdown')
        let clientBundle=clientMiddleware.fileSystem.readFileSync(path.join(clientConfig.output.path, 'vue-ssr-client-manifest.json'))
        c=clientBundle;
        run()
    })
    //只須要加載這一個就好了
    server.use(webpackHotMiddleware(clientComplier));

}

node server.js 試一下。講道理沒有問題0.0

上面代碼優化的點其實很是多,除了隨意的變量名,就是生成兩個文件的方式,同樣的代碼不少,並且vue-ssr-server-bundle.json是否是能夠不用webpack-dev-middleware拿。這只是一個簡單的例子,能用,但還不夠。

總結

實現express+webpack的開發模式就是利用早期的dev-middleware插件,dev-serve只適合純前端,這裏的難點就是怎麼從內存中拿到真實的文件,拿到後怎麼處理;雖然只是幾行代碼,理解起來卻不太容易;還有就是webpack的打包原理,仍是要學一下;
有關node先後端一塊兒開發的開發環境搭建我這裏也有一篇入門的文章:
手動搭建vue+node單頁面(一)

相關文章
相關標籤/搜索