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).