Custom Express middleware#

Volto uses the popular Express server for its server-side rendering implementation and static resource serving. In some cases it is useful to extend this server with new functionality. For example, Volto includes a middleware that proxies the backend and that can be used during development. Other use cases might include a CORS proxy server, a proxy to protect a database such as ElasticSearch or MongoDB, etc.

To add new middleware, use the settings.expressMiddleware configuration key. This is a list that takes Express middleware functions. For example:

import {
  settings as defaultSettings,
} from '@plone/volto/config';

const settings = { ...defaultSettings };

if (__SERVER__) {
  const express = require('express');
  const middleware = express.Router();

  middleware.all('/test-middleware', function (req, res, next) {
    res.send('Hello world');
  });
  middleware.id = 'test-middleware'

  settings.expressMiddleware = [
    ...defaultSettings.expressMiddleware,
    middleware,
  ] ;
}

Now the test-middleware page can be visited and it will return the simple string and not the usual Volto pages.

Static middleware#

The staticMiddleware is for serving static files such as style sheets and client-side JavaScript files from the BUILD_DIR/PUBLIC or PUBLIC_DIR directory. It uses the express.static() function to serve static files, and the setHeaders() function to add response headers to the files that it serves.

import { settings as defaultSettings } from '@plone/volto/config';
import express from 'express';

const settings = { ...defaultSettings };
if (__SERVER__) {
    const customStaticMiddleware = express.static('test/static/files');

    function setCustomHeaders(req, res, next) {
        res.setHeader('Cache-Control', 'public, max-age=3600');
        next();
    }

    customStaticMiddleware.setHeaders = setCustomHeaders;
    customStaticMiddleware.id = 'custom-static-middleware';

    settings.expressMiddleware = [
        ...defaultSettings.expressMiddleware,
        customStaticMiddleware,
    ];
}

Function setHeaders(path)#

The setHeaders() function is used to update the response headers for a file. It takes the path of the file being served as an argument, and adds the response headers to that file. It uses the config object specified in config.settings.serverConfig.staticFiles to determine which response headers should be added to the file.

Configuration#

The config.settings.staticFiles is an array of objects with three properties:

id

a string identifier for the static file rule

match

a regular expression that evaluates the path of the requested resource

headers

an object containing the headers added if the match is successful

The following example shows how to add the response header Cache-Control: public, max-age=3600 to a file named styles.css located in the BUILD_DIR/PUBLIC directory:

import {
    settings as defaultSettings,
} from '@plone/volto/config';

const settings = { ...defaultSettings };
settings.staticFiles = [
    ...defaultSettings.staticFiles, {
        id: 'styles_css',
        match: /^\/styles\.css$/,
        headers: {
            'Cache-Control': 'public, max-age=3600',
        },
    }
]

The rules are checked in sequential order, and the search stops at the first match. The default rules add headers that set the browser cache to 365 days for resources under the /static path and 60 seconds for all other paths.

Notice the use of the __SERVER__ condition. Because the code in a Volto project's config.js gets executed by both the server and the client (browser), the server-side libraries need to "excluded" with conditions.

See ExpressJS website for more documentation.

Note

Addon authors should add the id property to the middleware so that it can be identified and manipulated in Volto projects configuration.