github.com/llimllib/devd@v0.0.0-20230426145215-4d29fc25f909/README.md (about)

     1  # devd: a local webserver for developers
     2  
     3  This is an experimental branch forked from [cortesi/devd](https://github.com/cortesi/devd)
     4  
     5  ![screenshot](docs/devd-terminal.png "devd in action")
     6  
     7  # Install
     8  
     9  Go to the [releases page](https://github.com/llimllib/devd/releases/latest), download the package for your OS, and copy the binary to somewhere on your PATH.
    10  
    11  If you have a working Go installation, you can also say
    12  
    13      go get github.com/llimllib/devd/cmd/devd
    14  
    15  # Quick start
    16  
    17  Serve the current directory, open it in the browser (**-o**), and livereload when files change (**-l**):
    18  
    19  ```bash
    20  devd -ol .
    21  ```
    22  
    23  Reverse proxy to http://localhost:8080, and livereload when any file in the **src** directory changes:
    24  
    25  ```bash
    26  devd -w ./src http://localhost:8080
    27  ```
    28  
    29  
    30  # Using devd with modd
    31  
    32  [Modd](https://github.com/cortesi/modd) is devd's sister project - a dev tool
    33  that runs commands and manages daemons in response to filesystem changes. Devd
    34  can be used with modd to rebuild a project and reload the browser when
    35  filesystem changes are detected.
    36  
    37  Here's a quick example of a simple *modd.conf* file to illustrate.
    38  
    39  ```
    40  src/** {
    41      prep: render ./src ./rendered
    42  }
    43  
    44  rendered/*.css ./rendered/*.html {
    45      daemon: devd -m ./rendered
    46  }
    47  ```
    48  
    49  The first block runs the *render* script whenever anything in the *src*
    50  directory changes. The second block starts a devd instance, and triggers
    51  livereload with a signal whenever a .css or .html file in the *rendered*
    52  directory changes.
    53  
    54  See the [modd](https://github.com/cortesi/modd) project page for details.
    55  
    56  
    57  # Features
    58  
    59  ### Cross-platform and self-contained
    60  
    61  Devd is a single statically compiled binary with no external dependencies, and
    62  is released for macOS, Linux and Windows. Don't want to install Node or Python
    63  in that light-weight Docker instance you're hacking in? Just copy over the devd
    64  binary and be done with it.
    65  
    66  
    67  ### Designed for the terminal
    68  
    69  This means no config file, no daemonization, and logs that are designed to be
    70  read in the terminal by a developer. Logs are colorized and log entries span
    71  multiple lines. Devd's logs are detailed, warn about corner cases that other
    72  daemons ignore, and can optionally include things like detailed timing
    73  information and full headers.
    74  
    75  
    76  ### Convenient
    77  
    78  To make quickly firing up an instance as simple as possible, devd automatically
    79  chooses an open port to run on (unless it's specified), and can open a browser
    80  window pointing to the daemon root for you (the **-o** flag in the example
    81  above). It also has utility features like the **-s** flag, which auto-generates
    82  a self-signed certificate for devd, stores it in ~/.devd.certs and enables TLS
    83  all in one step.
    84  
    85  
    86  ### Livereload
    87  
    88  When livereload is enabled, devd injects a small script into HTML pages, just
    89  before the closing *head* tag. The script listens for change notifications over
    90  a websocket connection, and reloads resources as needed. No browser addon is
    91  required, and livereload works even for reverse proxied apps. If only changes
    92  to CSS files are seen, devd will only reload external CSS resources, otherwise
    93  a full page reload is done. This serves the current directory with livereload
    94  enabled:
    95  
    96  <pre class="terminal">devd -l .</pre>
    97  
    98  You can also trigger livereload for files that are not being served, letting
    99  you reload reverse proxied applications when source files change. So, this
   100  command watches the *src* directory tree, and reverse proxies to a locally
   101  running application:
   102  
   103  <pre class="terminal">devd -w ./src http://localhost:8888</pre>
   104  
   105  The **-x** flag excludes files from triggering livereload based on a [pattern
   106  specification](#excluding-files-from-livereload). The following command
   107  disables livereload for all files with the ".less" extension:
   108  
   109  <pre class="terminal">devd -x "**.less" -l .</pre>
   110  
   111  When livereload is enabled (with the **-L**, **-l** or **-w** flags), devd
   112  responds to a SIGHUP by issuing a livereload notice to all connected browsers.
   113  This allows external tools, like devd's sister project **modd**, to trigger
   114  livereload. If livereload is not enabled, SIGHUP causes the daemon to exit.
   115  
   116  The closing *head* tag must be found within the first 30kb of the remote file,
   117  otherwise livereload is disabled for the file.
   118  
   119  
   120  ### Reverse proxy + static file server + flexible routing
   121  
   122  Modern apps tend to be collections of web servers, and devd caters for this
   123  with flexible reverse proxying. You can use devd to overlay a set of services
   124  on a single domain, add livereload to services that don't natively support it,
   125  add throttling and latency simulation to existing services, and so forth.
   126  
   127  Here's a more complicated example showing how all this ties together - it
   128  overlays two applications and a tree of static files. Livereload is enabled for
   129  the static files (**-l**) and also triggered whenever source files for reverse
   130  proxied apps change (**-w**):
   131  
   132  <pre class="terminal">
   133  devd -l \
   134  -w ./src/ \
   135  /=http://localhost:8888 \
   136  /api/=http://localhost:8889 \
   137  /static/=./assets
   138  </pre>
   139  
   140  The [route specification syntax](#routes) is compact but powerful enough to cater for most use cases.
   141  
   142  ### Light-weight virtual hosting
   143  
   144  Devd uses a dedicated domain - **devd.io** - to do simple virtual hosting. This
   145  domain and all its subdomains resolve to 127.0.0.1, which we use to set up
   146  virtual hosting without any changes to */etc/hosts* or other local
   147  configuration. Route specifications that don't start with a leading **/** are
   148  taken to be subdomains of **devd.io**. So, the following command serves a
   149  static site from devd.io, and reverse proxies a locally running app on
   150  api.devd.io:
   151  
   152  <pre class="terminal">
   153  devd ./static api=http://localhost:8888
   154  </pre>
   155  
   156  
   157  ### Latency and bandwidth simulation
   158  
   159  Want to know what it's like to use your fancy 5mb HTML5 app from a mobile phone
   160  in Botswana? Look up the bandwidth and latency
   161  [here](http://www.cisco.com/c/en/us/solutions/collateral/service-provider/global-cloud-index-gci/CloudIndex_Supplement.html),
   162  and invoke devd like so (making sure to convert from kilobits per second to
   163  kilobytes per second and account for the location of your server):
   164  
   165  <pre class="terminal">devd -d 114 -u 51 -n 275 .</pre>
   166  
   167  Devd tries to be reasonably accurate in simulating bandwidth and latency - it
   168  uses a token bucket implementation for throttling, properly handles concurrent
   169  requests, and chunks traffic up so data flow is smooth.
   170  
   171  
   172  ## Routes
   173  
   174  The devd command takes one or more route specifications as arguments. Routes
   175  have the basic format **root=endpoint**. Roots can be fixed, like
   176  "/favicon.ico", or subtrees, like "/images/" (note the trailing slash).
   177  Endpoints can be filesystem paths or URLs to upstream HTTP servers.
   178  
   179  Here's a route that serves the directory *./static* under */assets* on the server:
   180  
   181  ```
   182  /assets/=./static
   183  ```
   184  
   185  To use a **devd.io** subdomain (which will resolve to 127.0.0.1), just add it
   186  to the the front of the root specification. We recognize subdomains by the fact
   187  that they don't start with a leading **/**. So, this route serves the
   188  **/static** directory under **static.devd.io/assets**:
   189  
   190  ```
   191  static/assets=./static
   192  ```
   193  
   194  Reverse proxy specifications are similar, but the endpoint specification is a
   195  URL. The following serves a local URL from the root **app.devd.io/login**:
   196  
   197  ```
   198  app/login=http://localhost:8888
   199  ```
   200  
   201  If the **root** specification is omitted, it is assumed to be "/", i.e. a
   202  pattern matching all paths. So, a simple directory specification serves the
   203  directory tree directly under **devd.io**:
   204  
   205  ```
   206  devd ./static
   207  ```
   208  
   209  Similarly, a simple reverse proxy can be started like this:
   210  
   211  ```
   212  devd http://localhost:8888
   213  ```
   214  
   215  There is also a shortcut for reverse proxying to localhost:
   216  
   217  ```
   218  devd :8888
   219  
   220  ```
   221  
   222  ### Serving default content for files not found
   223  
   224  The **--notfound** flag can be passed multiple times, and specifies a set of
   225  routes that are consulted when a requested file is not found by the static file
   226  server. The basic syntax is **root=path**, where **root** has the same
   227  semantics as route specification. As with routes, the **root=** component is
   228  optional, and if absent is taken to be equal to **/**. The **path** is always
   229  relative to the static directory being served. When it starts with a leading
   230  slash (**/**), devd will only look for a replacement file in a single location
   231  relative to the root of the tree. Otherwise, it will search for a matching file
   232  by joining the specified **path** with all path components up to the root of
   233  the tree.
   234  
   235  Let's illustrate this with an example. Say we have a */static* directory as
   236  follows:
   237  
   238  ```
   239  ./static
   240  ├── bar
   241  │   └── index.html
   242  └── index.html
   243  ```
   244  
   245  We can specify that devd should look for an *index.html* anywhere on the path
   246  to the root of the static tree as follows:
   247  
   248  ```
   249  devd --notfound index.html  /static
   250  ```
   251  
   252  Now, the following happens:
   253  
   254  * A request for */nonexistent.html* returns the contents of */index.html*
   255  * A request for */bar/nonexistent.html* returns the contents of */bar/index.html*
   256  * A request for */foo/bar/voing/index.html* returns the contents of */index.html*
   257  
   258  We could instead specify an absolute path in the route, in which case the
   259  contents of */index.html* would be returned for all the examples above:
   260  
   261  ```
   262  devd --notfound /index.html  /static
   263  ```
   264  
   265  Devd won't serve an over-ride page if the expected type of the incoming request
   266  doesn't match that of the override specification. We do this by looking at the
   267  file extension and expected MIME types of the over-ride and request, defaulting
   268  to *text/html* if the type couldn't be positively established. This prevents
   269  issues where, for instance, an HTML over-ride page might be served where images
   270  are expected.
   271  
   272  
   273  ## Excluding files from livereload
   274  
   275  The **-x** flag supports the following terms:
   276  
   277  Term          | Meaning
   278  ------------- | -------
   279  `*`           | matches any sequence of non-path-separators
   280  `**`          | matches any sequence of characters, including path separators
   281  `?`           | matches any single non-path-separator character
   282  `[class]`     | matches any single non-path-separator character against a class of characters
   283  `{alt1,...}`  | matches a sequence of characters if one of the comma-separated alternatives matches
   284  
   285  Any character with a special meaning can be escaped with a backslash (`\`). Character classes support the following:
   286  
   287  Class      | Meaning
   288  ---------- | -------
   289  `[abc]`    | matches any single character within the set
   290  `[a-z]`    | matches any single character in the range
   291  `[^class]` | matches any single character which does *not* match the class
   292  
   293  
   294  ## About reverse proxying
   295  
   296  Devd does not validate upstream SSL certificates when reverse proxying. For our
   297  use case, development servers will usually be running locally, often with
   298  self-signed certificates for testing. You shouldn't use devd in cases where
   299  upstream cert validation matters.
   300  
   301  The *X-Forwarded-Host* and *X-Forwarded-Proto* headers are set to the devd
   302  server's address and protocol for reverse proxied traffic. You might need to
   303  enable support for this in your application for redirects and the like to work
   304  correctly.
   305  
   306  
   307  # Development
   308  
   309  The scripts used to build this package for distribution can be found
   310  [here](https://github.com/cortesi/godist). External packages are vendored using
   311  [dep](https://github.com/golang/dep).