text: const express = require('express')
  const { createBundleRenderer } = require('vue-server-renderer')
  const fs = require('fs')
  const favicon = require('serve-favicon')
  const LRU = require('lru-cache')
  const compression = require('compression')
  
  const config = require('./config')
  
  const DEFAULT_OPTIONS = {
    prodOnly: false,
  }
  
  module.exports = (app, options) => {
    options = Object.assign({}, DEFAULT_OPTIONS, options)
  
    const isProd = process.env.NODE_ENV === 'production'
  
    if (options.prodOnly && !isProd) return
  
    const templatePath = config.templatePath
  
    try {
      // Vue bundle renderer
      let renderer
      // In development: wait for webpack compilation
      // when receiving a SSR request
      let readyPromise
  
      const directives = config.directives
  
      const lruCacheOptions = config.lruCacheOptions || {}
  
      const defaultRendererOptions = {
        cache: new LRU({
          max: 1000,
          maxAge: 1000 * 60 * 15,
          ...lruCacheOptions,
        }),
        runInNewContext: false,
        inject: false,
        directives,
        shouldPrefetch: (file, type) => {
          if (config.shouldNotPrefetch.indexOf(file) > -1) return false
          if (type === 'script' || type === 'style') return true
        },
        shouldPreload: (file, type) => {
          if (config.shouldNotPreload.indexOf(file) > -1) return false
          if (type === 'script' || type === 'style') return true
        },
      }
  
      if (isProd) {
        // In production: create server renderer using template and built server bundle.
        // The server bundle is generated by vue-ssr-webpack-plugin.
        const template = fs.readFileSync(templatePath, 'utf-8')
        const serverBundle = require(`${config.distPath}/vue-ssr-server-bundle.json`)
        // The client manifests are optional, but it allows the renderer
        // to automatically infer preload/prefetch links and directly add <script>
        // tags for any async chunks used during render, avoiding waterfall requests.
        const clientManifest = require(`${config.distPath}/vue-ssr-client-manifest.json`)
        renderer = createBundleRenderer(serverBundle, {
          ...defaultRendererOptions,
          template,
          clientManifest,
        })
      } else {
        // In development: setup the dev server with watch and hot-reload,
        // and create a new renderer on bundle / index template update.
        const { setupDevServer } = require('./dev-server')
        readyPromise = setupDevServer({
          server: app,
          templatePath,
          onUpdate: ({ serverBundle }, options) => {
            // Re-create the bundle renderer
            renderer = createBundleRenderer(serverBundle, {
              ...defaultRendererOptions,
              ...options,
            })
          },
        })
      }
  
      if(config.applyDefaultServer){
        // Serve static files
        const serve = (filePath, cache) => express.static(filePath, {
          maxAge: cache && isProd ? config.staticCacheTtl : 0,
          index: false,
        })
  
        // Serve static files
        app.use(compression({ threshold: 0 }))
        app.use(favicon(config.favicon))
        if (config.api.hasPlugin('pwa')) {
          app.use('/service-worker.js', serve(config.serviceWorkerPath))
        }
        const serveStaticFiles = serve(config.distPath, true)
        const { publicPath } = config.service.projectOptions
        app.use(publicPath, (req, res, next) => {
          if (/index\.html/g.test(req.path)) {
            next()
          } else {
            serveStaticFiles(req, res, next)
          }
        })
      }
  
      if (config.extendServer) {
        config.extendServer(app)
      }
  
      // Render the Vue app using the bundle renderer
      const renderApp = (req, res) => {
        res.setHeader('Content-Type', 'text/html')
  
        const context = Object.assign({
          req,
          url: req.url,
          title: config.defaultTitle,
          httpCode: 200,
        }, config.extendContext && config.extendContext(req, res, process))
  
        renderer.renderToString(context, (err, renderedHtml) => {
          let html = renderedHtml
  
          if (err || context.httpCode === 500) {
            console.error(`error during render url : ${req.url}`)
  
            // Render Error Page
            let errorHtml = config.error500Html
              ? fs.readFileSync(config.error500Html, 'utf-8')
              : '500 | Internal Server Error'
  
            if (err) {
              console.error(err)
  
              if (!isProd) {
                const errorMessage = `<pre>${err.stack}</pre>`
                config.error500Html
                  ? errorHtml = errorHtml.replace('<!--server-error-msg-->', errorMessage)
                  : errorHtml += errorMessage
              }
  
              if (config.onError) {
                config.onError(err)
              }
            }
  
            html = errorHtml
  
            res.status(500)
          } else {
            res.status(context.httpCode)
          }
  
          if(config.onRender){
            config.onRender(res, context)
          }
  
          res.send(html)
        })
      }
  
      // Process SSR requests
      let ssr
      if (isProd) {
        ssr = renderApp
      } else {
        // In development: wait for webpack compilation
        // when receiving a SSR request
        ssr = (req, res) => {
          readyPromise.then(() => renderApp(req, res)).catch(console.error)
        }
      }
      app.get(`${publicPath}*`, (req, res, next) => {
        if (config.skipRequests(req)) {
          return next()
        }
        ssr(req, res)
      })
      return readyPromise
    } catch (e) {
      console.error(e)
    }
  }
  