🐑 Commons Host

Documentation

@commonshost/server

Host Options

Example:

module.exports = {
  hosts: [{
    domain: 'example.net',
    root: './build/site',
    fallback: { 200: './app.html' },
    directories: { trailingSlash: 'never' },
    accessControl: { allowOrigin: '*' },
    headers: [{ fields: { 'X-Frame-Options': 'deny' } }],
    manifest: [{ get: '/app.html', push: '/app.css' }]
  }]
}

Table of Contents

hosts[].domain

Default: '' or 'localhost' (only for the default site, see serveDefaultSite)

The DNS hostname of the site. May be specified as an Internationalized Domain Name (IDN) containing non-ASCII characters.

Multiple sites on the same server can each have their own configuration.

Examples:

module.exports = {
  hosts: [
    { domain: 'example.net' },
    { domain: 'xn--yfro4i67o.example.net' },
    { domain: '🦄.example.net' }
  ]
}

hosts[].root

The path to the base directory containing static files to serve.

module.exports = {
  hosts: [{
    root: './website'
  }]
}

If no root is specified, the server tries to auto-detect static site generator or packaging tool output directories. For example: ./dist, ./public, ./_site, and many more.

If no directory is auto-detected, the current working directory is used. A warning message is logged to indicate this fallback behaviour.

hosts[].fallback

Default: {} (no fallback)

An object mapping HTTP status code to file paths.

Typically used for client side routing.

Fallbacks are supported for:

Example for client-side routing (e.g. SPA or PWA):

module.exports = {
  hosts: [{
    fallback: { 200: './app.html' }
  }]
}

Example for "Not Found" error pages:

module.exports = {
  hosts: [{
    fallback: { 404: './page-not-found.html' }
  }]
}

hosts[].directories

Behaviour of directory paths in clean URLs.

hosts[].directories.trailingSlash

Default: 'always'

Enforces a consistent ending character for directory paths.

The value is a string that can be:

hosts[].accessControl

Settings related to Cross-Origin Resource Sharing (CORS). The server responds to OPTIONS method requests with the appropriate response headers to allow (or deny) third-party access.

hosts[].accessControl.allowOrigin

Default: '*'

If specified, sets this value as the Access-Control-Allow-Origin header on every response.

hosts[].headers[]

Sets custom HTTP response headers. The headers array contains header objects. Each header object has the fields and uri properties.

module.exports = {
  hosts: [{
    headers: [
      {
        fields: {
          'Content-Security-Policy': "default-src 'self'",
          'Feature-Policy': "payment 'none'",
          'Strict-Transport-Security': 'max-age=31536000',
          'Referrer-Policy': 'strict-origin-when-cross-origin',
          'X-Frame-Options': 'SAMEORIGIN',
          'X-XSS-Protection': '1; mode=block',
          'X-Content-Type-Options': 'nosniff'
        }
      },
      {
        uri: '/service-worker.js',
        fields: {
          'Service-Worker-Allowed': '/'
        }
      },
      {
        uri: '/scripts/{filename}.{hash}.js',
        fields: {
          'Cache-Control': 'public, max-age=31536000, immutable'
        }
      },
      {
        fields: {
          'Set-Cookie': ['foo=bar', 'bar=baz']
        }
      }
    ]
  }]
}

hosts[].headers[].fields

fields is a required object whose property names and values are the HTTP headers to set on the response.

Property names must be valid HTTP header field names. Only case-insensitive alphanumeric characters (A through Z, and 0 through 9) and hyphens (- dash) are allowed.

Example Validity
Referrer-Policy Allowed
:status Not Allowed

Values may contain named template segments in braces. The values are substituted using matches from the uri template.

Values may also be arrays of strings to set multiple headers with the same name.

hosts[].headers[].uri

uri is an optional string as a URI Template. The header fields are applied only if the request pathname matches the route.

If no uri property is set, the fields headers are applied to all responses.

hosts[].manifest

The manifest property declares which files or URLs need to be pushed as dependencies for any request. Using HTTP/2 Server Push (PUSH_PROMISE frames) can eliminate round trips between browser and server and speed up resource loading.

The manifest property type can be:

Example: Inline manifest

module.exports = {
  hosts: [{
    manifest: [
      // Example:
      {
        // When serving the homepage,
        get: '**/*.html',
        // push all CSS and JS files.
        push: ['**/*.css', '**/*.js']
      }
    ]
  }]
}

Example: External manifest file

Using an external file is useful when using a build tool that traces dependencies to automatically generate the manifest.

This example shows a static website in the ./dist directory. The first section runs the @commonshost/manifest command line interface (CLI) tool to trace all HTML/JS/CSS files for dependencies. The automatically generated manifest is stored as ./manifest. The second section shows a reference to this external manifest.

$ npx @commonshost/manifest generate ./dist ./manifest.json
module.exports = {
  hosts: [{
    manifest: './manifest.json'
  }]
}

hosts[].redirects[]

Create redirects from gone pages to new pages.

Custom redirects help preserve inbound links and maintain search engine rankings & optimisation (SEO). As a website's content changes, pages are often moved around. Redirects are used to avoid leaving broken links from external sites to your old pages.

Tip: Use a fallback page (See: hosts[].fallback) to capture inbound links to no-longer-existing pages. With proper analytics reporting you can build a list of the most frequently visited broken links, and redirect them somewhere more useful.

Examples:

module.exports = {
  hosts: [{
    redirects: [
      // Old page to new page
      { from: '/old/page', to: '/new/page' },

      // Old page to a different website
      { from: '/somewhere', to: 'https://new.example.net/other/site' },

      // Override the HTTP status code to use a temporary redirect
      { from: '/promotion', to: '/summer-special', status: 307 },

      // Use URI Template pattern matching to preserve variables
      { from: '/shop{?sort,product}',
        to: '/store/item{/product}{?sort}' }
    ]
  }]
}

hosts[].redirects[].from

from is a required string as a URI Template.

Only paths on the current site can be matched.

hosts[].redirects[].to

to is a required string as a URI Template.

This path may be relative to the current origin (a.k.a. domain name) or an absolute URL pointing to a different origin.

hosts[].redirects[].status

status is an optional integer from 300 through 399.

The default status code is 308 which means Permanent Redirect. Use 307 to generate a Temporary Redirect.

See the IANA list of assigned HTTP status codes: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml