Skip to content

Develop locally, proxy to prod, browser-sync, and process ESI tags.

License

Notifications You must be signed in to change notification settings

karelhala/spandx

 
 

Repository files navigation

spandx logo

Build Status

What is spandx?

spandx is an HTTP switchboard. With it, you can weave together pieces of a large, complex website by choosing which resources should come from your local system and which should come from a remote environment.

For example, you could point spandx at your production site, but route /static/js to a local directory, which allows you to test your local JS against the production environment. Code in production, it's fun.

More technically, spandx is a flexible, configuration-based reverse proxy for local development.

Quick-start

(Note: if you're a developer on the Customer Portal, please use this guide)

While I recommend local install, if you want to quickly take spandx for a whirl, the fastest way to get started is by installing spandx as a global package.

npm install -g spandx

Generate a sample configuration file:

spandx init > spandx.config.js

Launch!

spandx

Table of Contents

Commands

spandx

To launch spandx, simply run spandx. If a spandx.config.js file exists in the current directory, it will be used.

Option Description Example
-c, --config Specify an alternate config file. Config files are JS by default (to enable commenting), but JSON is also accepted. spandx -c ./configs/spandx.json
-v, --version Print the current version of spandx. spandx -v

init

Generate a configuration file. When invoked with no arguments, it prints a barebones config file. Redirect to a file (this could be improved by writing the file automatically).

spandx init > spandx.config.js

Configuration

After spandx init has generated a configuration file for you, there are many ways you can tweak it.

spandx.config.js

Here are the configuration options accepted by the config file.

Option Description Type
host The hostname you wish to use to access spandx. Usually "localhost", or a multi-host object. string or object
port The port for spandx to listen on, or "auto". number or "auto"
open Whether to open a browser tab when spandx is launched. boolean
startPath The URL path to open, if open is true. ex: "/site". string
verbose Display English summary of configuration settings and display Browsersync logs, or not. boolean
routes Define where to send requests for any number of URL paths, best explained in routes by example. object
bs A Browsersync config object, in case you need to further customize spandx's Browsersync instance. object
portalChrome Settings related to Portal Chrome, see Portal Chrome settings. object
esi Set to true to enable processing ESI tags, or pass in a nodesi config object. boolean or object

Routes

Routes are the core of spandx's flexibility. They allow you to define where to pull assets at any given URL path.

Route all requests to palebluepixel.org (a perfect reverse proxy), unless the request falls under /theme, in which case look for files in ~/projects/pbp/theme.

routes: {
    "/theme" : "~/projects/pbp/theme/",
    "/"      : { host: "https://palebluepixel.org/" },
},

Here's how this configuration would play out.

  1. visit localhost:1337 and you see what looks like palebluepixel.org
  2. one exception, the page includes /theme/site.css
  3. because it falls under the /theme route, spandx fetches ~/projects/pbp/theme/site.css instead of palebluepixel.org/theme/site.css

This effectively overlays a local directory of static files on top of a remote server. In other words... test in production!

In addition, because ~/projects/pbp/theme is a local directory, changes to files inside it will trigger a Browsersync refresh.

Routing to a local directory

To route to a local directory, the destination should be a string. The directory path can be absolute or relative. If relative, it's resolved relative to the spandx.config.js file.

routes: {
    "/incoming": "./destination"
}

Routing to a server

To route to a server, the destination should be an object with a host property.

routes: {
    "/incoming": {
      host: "http://localhost:8080"
    }
}

In this form, requests to /incoming will route to http://localhost:8080/incoming. If you would rather route to a different path (such as http://localhost:8080), you can specify a path property as follows.

Multi-host routing

Many projects have multiple remote webservers, for example a dev server, qa, staging, and production. To simplify dealing with multiple remotes, spandx offers multi-host routing, whether the local hostname determines which remote host to proxy to. Here's an example config.

module.exports = {
    host: {
 +---<  dev: "dev-local.foo.com",
 |      prod: "prod-local.foo.com"
 |  },
 |  routes: {
 |      "/": {
 |          host: {
 +----------->  dev: "http://dev.foo.com",
                prod: "http://www.foo.com"
            }
        }
    }
};

In this case, dev-local.foo.com and prod-local.foo.com should be entered in /etc/hosts, pointing to 127.0.0.1. Then, when spandx is visited at dev-local.foo.com, spandx knows it's the "dev" host and proxies to dev.foo.com. The names "dev" and "prod" can be any names you choose. See the examples dir for a working example.

Path rewriting

routes: {
    "/my-app": {
      host: "http://localhost:8080",
      path: "/"
    }
}

With this path setting, requests to /my-app will route to http://localhost:8080/. This is particularly useful when using a local development server (like webpack-dev-server) where your app lives at /.

single mode

When a route has single: true, spandx will send all requests under that route to a single index.html file (except requests for assets).

This is intended to be used with pushState and enables hash-free user-friendly URLs for single-page apps.

routes: {
    "/my-app": {
      host: "http://localhost:8080",
      single: true
    }
}

With this config, a request to /my-app/users/active would be routed to http://localhost:8080/my-app/index.html.

single can also be combined with path.

routes: {
    "/my-app": {
      host: "http://localhost:8080",
      path: "/",
      single: true
    }
}

Here, a request to /my-app/users/active would be routed to http://localhost:8080/.

Overriding Browsersync options

Internally, spandx uses Browsersync to power some features like live-reloading. Custom Browsersync options can be embedded in your spandx.config.js file under the bs property.

For example, let's enable HTTPS.

Enabling HTTPS

You can enable HTTPS by

module.exports = {
    bs: {
        https: true,
    }
};

For extra customization (like providing your own certs), see Browsersync's HTTPS options.

spandx as a local dependency

The quick-start has you install spandx as a global package for simplicity, but installing it locally per-project is a better approach in many ways.

Go to your project, install spandx as a dev dependency, and create a config file:

cd $YOUR_PROJECT
npm install --save-dev spandx
npx spandx init > spandx.config.js

Modify spandx.config.js to reflect the needs of your application.

Then edit your package.json and add a start script which launches spandx.

    "scripts": {
        "start": "spandx"
    }

Now you and your fellow contributors can run npm start without having to install or even understand spandx!

Contributing

Contributions are very welcome! There's not much here yet, but when there's enough content it can be split out into a dedicated CONTRIBUTING.md.

Commit messages

Starting with spandx v2.0.0, one goal is to adhere to the Conventional Commits style of writing commit messages. The rewards of doing so are automating semantic version bumps and CHANGELOG updates. For now, the commit style will be used and later on, the tooling (conventional-changelog-cli perhaps) will be added.

Running specific tests

When writing a test, or debugging a failing test, you may want to run only that test instead of the entire suite. To do that, you can filter by the name of the test. Just be specific enough to target only the test (or tests) you want to run.

For example, to run the test named "should reject invalid multi-host configs":

npm test -- --filter="invalid multi"

Known issues

cURLing spandx

When curling spandx, if you are requesting an HTML document, it's important to include an appropriate Accept header. There are two spandx features, described below, that will not work without that header.

Body URL rewriting

The URL-rewriting feature is powered by browserSync's rewriteRules. However, Browsersync will only perform the rewrites if text/html is present in the request's Accept header. Web browsers include it by default, but if you're using cURL, you'll need to add that header in order for URLs to be rewritten.

For example:

curl -H 'Accept: text/html' localhost:1337

single mode URL rewriting

Just like body URL rewriting, the URL rewrite associated with the single also needs the incoming Accept header to include text/html.

All other spandx features work with or without text/html in the Accept header.

Alternatives

If spandx doesn't fit, here are a few other tools that offer similar features.

  • devd, a local development server with a focus on flexible reverse proxying, much like spandx. Written in Go.
  • http-server, a simple command-line HTTP server. The --proxy flag provides a remote fallback for requests that can't be resolved locally. Written in JS.
  • dprox, a declarative reverse proxy for local development. Similar configuration philosophy to spandx.

About

Develop locally, proxy to prod, browser-sync, and process ESI tags.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 95.9%
  • HTML 4.1%