vue ssr server-side rendering - preliminary development environment construction

Keywords: Javascript Webpack JSON Vue hot update

vue ssr server-side rendering: the construction of development environment for beginners

Preface

By default, you have understood the basic content and implementation of ssr. If you are not familiar with it, you can read it first vue ssr server rendering

There are not many articles about the construction of ssr development environment on the Internet, even if they are found, they are relatively advanced and not suitable for novices to enter the pit. This article only extracts the most important part to realize the construction of the most basic development environment. The so-called development environment is nothing more than two things: automatic packaging, automatic page refresh, and so-called "hot update" and "hot load".

Update renderer automatically

Look at the directory structure first

Nothing. A hot.config.js file is added to place the hot load configuration;
First look at server.js

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

const server = express();

let   renderer;
const hotServer = require('./webpack.hot.config.js')
//We hope that by continuously executing the callback of the following function, we can instantiate the renderer to achieve the purpose of automatic update;
hotServer(server,({serverBundle,clientManifest})=>{
  console.log('hot***************************************************')
  renderer = require('vue-server-renderer').createBundleRenderer(serverBundle,{
    runInNewContext: false, // Recommend
    template: require('fs').readFileSync('./index.html', 'utf-8'),
    clientManifest // (optional) client build manifest
  })
})
server.use('/',express.static('./dist')) // Set access static file path
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(`Server on: http://${chalk.green(ip)}:${chalk.yellow(8080)}`)
})

function getIPAdress(){//The os module under the node can get part of the information of the server that starts the file. Go to the node for details
    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;
            }
        }
    }
}

There are only a few lines of code related to automation and hotServer. Actually, they are also analyzed. For this server service, the only useful files are the server configuration vue-ssr-server-bundle.json and the client configuration vue-ssr-client-manifest.json. We just need to instantiate the renderer after these two files are packed. We should instantiate the renderer by adding An instance of production without any change with static files;

webpack.hot.config.js can also be written in server.js, but it doesn't look good or conform to the principle of module development;

Automatic packaging

When we use web pack to automatically package a watch, or when we use web pack dev serve, dev server will start a service by itself. However, we have our own server. The communication between them is not impossible, but difficult and not applicable. Watch is also the same and independent;
webpack can be used independently, but it is only a module in node, which can be used as a plug-in, and can be used in combination with express through other plug-ins;

webpack-dev-middleware

webpack-dev-middleware is the core component for hot loading. Take a look at the content of webpack.hot.config.js

//webpack.hot.config.js
const webpack = require('webpack');
//New webpack dev middleware plug-in
const webpackDevMiddleware = require('webpack-dev-middleware');
const path=require('path')
const clientConfig=require('./webpack.client.config.js')
const serverConfig=require('./webpack.server.config.js')
//Output a function to the server
module.exports = function(server,callBack){
    
    
    let b,c;
    //Here, a run method is defined to ensure that both vue-ssr-server-bundle.json and vue-ssr-client-manifest.json can execute the callback;
    function run(){
        console.log('run');
        if(b && c){
            console.log('runend ')
            callBack({serverBundle:JSON.parse(b),clientManifest:JSON.parse(c)})
        }
    }
    //Generate vue-ssr-server-bundle.json
    //Instantiate webpack
    const serverComplier = webpack(serverConfig);
    middleware = webpackDevMiddleware(serverComplier)
    server.use(middleware);
    //serverComplier is the instance returned by webpack. The plugin method can capture the event, and done indicates that the package is complete
    serverComplier.plugin('done',complation => {
        console.log('serverdown')
        //The core content, middleware.fileSystem.readFileSync is the method of reading files in memory provided by webpack dev middleware;
        //However, you get binary, which can be formatted with JSON.parse;
        let serverBundle=middleware.fileSystem.readFileSync(path.join(serverConfig.output.path, 'vue-ssr-server-bundle.json'))
        //Copy the obtained documents to b
        b=serverBundle;
        run();
    })
    //Generating vue-ssr-client-manifest.json is exactly the same as above.
    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()
    })

}

The biggest feature of webpack dev middleware is to put the packed files into memory and play without generating files. For most projects, there is no problem. However, ssr needs to read static files to continue playing. Webpack dev middleware does provide the method of reading files, such as middleware.fileSystem.readFileSync, which is similar to fs plug-in;

Simply explain the process of webback. Webback is a single thread. In the process of packaging, different events will be broadcast to tell you where webback is now. Webback () will return an instance of comparier, and monitor the situation of webback through comparier. Plugin ('done ', () = > {}). This is also the core content of the webback plug-in that you write yourself. Done means that the packaging is finished, and that's it This is the right time to get the documents we want.

Page auto refresh

By default, there is no bug in the code above. The plug-in below has nothing to say. Just know how to use it;

webpack-hot-middleware

Directly go to the final version of the code. Server and JS do not move. Modify webpack.hot.config.js:

//webpack.hot.config.js
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
//Add webpack hot middleware plug-in
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();
    })
    //Modify entry file, fixed writing
    clientConfig.entry=['./entry-client.js','webpack-hot-middleware/client?reload=true'];
    //Add auto update plug-in, fixed writing
    clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
    //The above two items should be written in the following before instantiation. It's easy to understand
    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()
    })
    //Just load this one
    server.use(webpackHotMiddleware(clientComplier));

}

node server.js try it. No problem in reasoning 0.0

In fact, there are many optimization points in the above code. In addition to random variable names, there are a lot of the same code in the way of generating two files. Besides, Vue SSR server bundle.json can be taken without webpack dev middleware. This is just a simple example, it can be used, but it is not enough.

summary

The development mode of express+webpack is to use the early dev middleware plug-in. Dev serve is only suitable for pure front-end. The difficulty here is how to get real files from memory and how to deal with them after getting them. Although it's only a few lines of code, it's not easy to understand. Besides, the packaging principle of webpack needs to be learned;
I also have an introductory article about the construction of the development environment developed by the front and back end of the node:
Manual building of vue+node single page (I)

Posted by Fastback_68 on Tue, 12 Nov 2019 02:22:00 -0800