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