vue ssr服务端渲染-初学开发环境搭建

vue ssr服务端渲染-初学者的开发环境搭建

前言

默认已经了解ssr的基本内容和实现,不熟悉的可以先看下vue ssr服务端渲染小白解惑

网上有关ssr开发环境搭建的文章不算多,就算找到也是比较高级的,不太适合新手入坑;这篇内容只抽取了其中最重要的部分,实现最基础的开发环境搭建;所谓开发环境无非两件事:自动打包·自动刷新页面,叫法比较土,也可以叫热更新,热加载。

自动更新renderer

先看目录结构
image.png
没啥东西,新增了一个hot.config.js文件,用来放置热加载的配置;
先看下server.js

//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实例化是通过加载静态文件而生产的一个不再变化的实例;

webpack.hot.config.js也可以写在server.js里面,不过看上去就不太好看,也不符合模块开发的原则;

自动打包

webpack自动打包有watch,或者使用webpack-dev-serve,dev-server会自己启一个服务,然而我们有自己的server,他们之间通信不是不可以,只是比较困难,不适用;watch也是一样,比较独立;
webpack可以独立使用,然而它也只是node中的一个模块,可以作为插件使用,而且可以通过其他插件和express结合使用;

webpack-dev-middleware

webpack-dev-middleware是实现热加载的核心组件,看一下webpack.hot.config.js的内容

//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插件;

简单说明下webpack流程,webpack是单线程,在打包的过程中会广播不同的事件告诉大家webpack现在干到哪一步了,webpack()会返回一个实例compalier,通过compalier.plugin('done',()=>{})方式监听webpack的情况,这也是自己编写webpack 插件的核心内容;done就表示打包完了,我们就这这个时候去拿我们想要的文件就对了;

页面自动刷新

默认上面的代码没有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单页面(一)

3.4k 声望
333 粉丝
0 条评论
推荐阅读
h5微信分享实现(node+express);
前言(^o^)/~ h5页面在微信中使用微信分享功能,实现个性化分享模版。 从默认样式:到自定义样式:第一步:注册微信公众平台账号(已有略过此步)[链接]个人只能注册订阅号类型,服务号就需要企业认证了。企业权限...

liubingyang13阅读 6.2k评论 10

手把手教你写一份优质的前端技术简历
不知不觉一年一度的秋招又来了,你收获了哪些大厂的面试邀约,又拿了多少offer呢?你身边是不是有挺多人技术比你差,但是却拿到了很多大厂的offer呢?其实,要想面试拿offer,首先要过得了简历那一关。如果一份简...

tonychen153阅读 18k评论 5

封面图
正则表达式实例
收集在业务中经常使用的正则表达式实例,方便以后进行查找,减少工作量。常用正则表达式实例1. 校验基本日期格式 {代码...} {代码...} 2. 校验密码强度密码的强度必须是包含大小写字母和数字的组合,不能使用特殊...

寒青57阅读 8.7k评论 11

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy49阅读 7.4k评论 12

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs42阅读 7k评论 12

封面图
CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(&gt;^ω^&lt...

XboxYan48阅读 3.4k评论 14

封面图
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs32阅读 3.6k评论 5

封面图
3.4k 声望
333 粉丝
宣传栏