Skip to content

Commit 8aae141

Browse files
committed
Add watch and serve subcommands to wasm-pack
1 parent 1194a8e commit 8aae141

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed

text/010-wasm-pack-watch-and-serve.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
- Start Date: 2019-03-06
2+
- RFC PR: https://github.com/rustwasm/rfcs/pull/10
3+
- Tracking Issue: (leave this empty)
4+
5+
# Summary
6+
[summary]: #summary
7+
8+
Add two new sub-commands to `wasm-pack`:
9+
10+
1. `watch`: watch the crate's files and automatically rebuild whenever they
11+
change.
12+
2. `serve`: start an HTTP server for the crate directory on `localhost`.
13+
14+
# Motivation
15+
[motivation]: #motivation
16+
17+
Enable a smooth and complete local development experience for users who are not
18+
using a JavaScript bundler.
19+
20+
In particular, we would like to [remove the `npm` and bundler usage from our
21+
Game of Life tutorial][no-bundler-in-docs] without requiring readers to install
22+
any additional tools other than the Rust toolchain and `wasm-pack` when setting
23+
up their development environment. The goal here being less moving parts to learn
24+
and tools to wrangle when first exploring Rust and WebAssembly.
25+
26+
Additionally, we would like to make sure that the local development server uses
27+
the `application/wasm` MIME type when serving Wasm binaries. This enables the
28+
`WebAssembly.instantiateStreaming` fast-path for users.
29+
30+
[no-bundler-in-docs]: https://github.com/rustwasm/book/issues/150
31+
32+
# Stakeholders
33+
[stakeholders]: #stakeholders
34+
35+
The stakeholders are primarily people that are doing Rust and Wasm development
36+
without a JavaScript bundler, which potentially will include all of our new
37+
users who are just starting the Game of Life tutorial. Most of this demographic
38+
is probably not watching the RFCs repository, and only some are regularly coming
39+
to working group meetings, so it makes sense to advertise this RFC in TWiRaWA
40+
and on our @rustwasm Twitter account.
41+
42+
# Detailed Explanation
43+
[detailed-explanation]: #detailed-explanation
44+
45+
We will add two new subcommands to `wasm-pack`:
46+
47+
1. `watch`
48+
2. `serve`
49+
50+
## `wasm-pack watch`
51+
52+
The `watch` subcommand will observe the crate directory for changes and
53+
automatically re-build when files change.
54+
55+
### Command Line Interface
56+
57+
The `watch` command takes an identical set of command line arguments as
58+
`wasm-pack build` does.
59+
60+
```
61+
USAGE:
62+
wasm-pack watch [FLAGS] [OPTIONS] [path] [-- <extra_options>...]
63+
64+
FLAGS:
65+
--dev Create a development build. Enable debug info, and disable optimizations.
66+
--no-typescript By default a *.d.ts file is generated for the generated JS file, but this flag will disable
67+
generating this TypeScript file.
68+
-h, --help Prints help information
69+
--profiling Create a profiling build. Enable optimizations and debug info.
70+
--release Create a release build. Enable optimizations and disable debug info.
71+
-V, --version Prints version information
72+
73+
OPTIONS:
74+
-m, --mode <mode> Sets steps to be run. [possible values: no-install, normal, force] [default: normal]
75+
-d, --out-dir <out_dir> Sets the output directory with a relative path. [default: pkg]
76+
-s, --scope <scope> The npm scope to use in package.json, if any.
77+
-t, --target <target> Sets the target environment. [possible values: browser, nodejs, no-modules] [default:
78+
browser]
79+
80+
ARGS:
81+
<path> The path to the Rust crate.
82+
<extra_options>... List of extra options to pass to `cargo build`
83+
```
84+
85+
### Implementation
86+
87+
We can use [the `notify` crate][notify] to watch the filesystem for
88+
changes. Initially, we will just watch the crate directory for
89+
changes. Eventually, we can use [`cargo build --build-plan`][build-plan] to get
90+
a list of files that we should be watching.
91+
92+
[notify]: https://crates.io/crates/notify
93+
[build-plan]: https://github.com/rust-lang/cargo/issues/5579
94+
95+
## `wasm-pack serve`
96+
97+
The `serve` subcommand starts a local Web server in the crate directory, watches
98+
for file changes, and re-builds the crate on changes.
99+
100+
### Command Line Interface
101+
102+
The `serve` subcommand takes a superset of the arguments that `wasm-pack build`
103+
takes. Like other `wasm-pack` subcommands, it takes an optional path to the
104+
crate directory as a positional argument, but if that is missing, then it
105+
defaults to the current directory. It has the usual flags for controlling the
106+
build profile, and the target environment. It takes extra options after `--`
107+
that get passed through straight to `cargo build`.
108+
109+
Additionally, it has a `--no-watch` flag to disable watching the crate for
110+
changes to kick off automatic re-builds, and a `--port` option to specifiy the
111+
port the local server should bind to.
112+
113+
```
114+
USAGE:
115+
wasm-pack serve [FLAGS] [OPTIONS] [path] [-- <extra_options>...]
116+
117+
FLAGS:
118+
--dev Create a development build. Enable debug info, and disable optimizations.
119+
--no-typescript By default a *.d.ts file is generated for the generated JS file, but this flag will disable
120+
generating this TypeScript file.
121+
-h, --help Prints help information
122+
--profiling Create a profiling build. Enable optimizations and debug info.
123+
--release Create a release build. Enable optimizations and disable debug info.
124+
-V, --version Prints version information
125+
--no-watch Do not watch the crate for changes to automaticaly rebuild.
126+
127+
OPTIONS:
128+
-m, --mode <mode> Sets steps to be run. [possible values: no-install, normal, force] [default: normal]
129+
-d, --out-dir <out_dir> Sets the output directory with a relative path. [default: pkg]
130+
-s, --scope <scope> The npm scope to use in package.json, if any.
131+
-t, --target <target> Sets the target environment. [possible values: browser, nodejs, no-modules] [default:
132+
browser]
133+
-p, --port <port> Bind to this port number with the local development HTTP server. [default: 8000]
134+
135+
ARGS:
136+
<path> The path to the Rust crate.
137+
<extra_options>... List of extra options to pass to `cargo build`
138+
```
139+
140+
### Implementation
141+
142+
Rather than integrating an HTTP server into the `wasm-pack` binary itself, we
143+
should leverage its ability to download and run other binaries. Exactly *which*
144+
local HTTP server binary is left as an unresolved question.
145+
146+
The subcommand will start the local HTTP server and then execute the `watch`
147+
subcommand (unless `--no-watch` is supplied).
148+
149+
# Drawbacks, Rationale, and Alternatives
150+
151+
The primary drawbacks are authoring and maintaining two more subcommands to
152+
implement functionality that is already available in external, third-party
153+
tools. We try to mitigate this downside by using existing local HTTP server
154+
binaries rather than building an HTTP server directly into `wasm-pack` itself.
155+
156+
## Alternative: Build the HTTP Server into `wasm-pack`
157+
158+
An alternative design would be to build the HTTP server into `wasm-pack` itself,
159+
using one of the existing crates for building Web servers like rocket, actix,
160+
hyper, tide, etc:
161+
162+
* **Pros:**
163+
* The `wasm-pack serve` command is ready to roll immediately after `wasm-pack`
164+
is installed, and doesn't need to hit the network the first time you run
165+
it. This situation only arises when folks who already downloaded `wasm-pack`
166+
do their first build/serve offline, disconnected from the internet. This
167+
seems like a niche enough situation that we can take the trade off.
168+
* **Cons:**
169+
* Building the HTTP server into the `wasm-pack` binary is less robust: by
170+
shelling out to an external binary for our local server, we get process
171+
isolation, which makes error recovery simpler.
172+
* More work to implement. `wasm-pack` already has plenty of infrastructure for
173+
downloading and working with external binaries, so using external HTTP
174+
servers should be fairly easy to implement.
175+
176+
## Alternative: Only `serve` and Don't `watch`
177+
178+
We could only implement the `serve` subcommand and not the `watch` subcommand or
179+
the filesystem watching functionality.
180+
181+
My original motivation when writing this RFC was just to get a local server
182+
story sorted out. But I realized that for most users, if their build tool starts
183+
a local server, they expect new, post-`serve` file changes to be automatically
184+
rebuilt and reflected in the served things. This is what `webpack`, `jekyll`,
185+
`elm`, and `ember` CLIs do for a small selection. I think that this expectation
186+
is large enough that we have to support file watching and automatic rebuild if
187+
we support `serve` at all.
188+
189+
That said, we could avoid having a `watch` *subcommand* and only expose the file
190+
watching functionality through the `serve` subcommand. At this point though,
191+
supporting the `watch` subcommand is a trivial amount of work, and there are use
192+
cases where it could be useful without the server: for example, JS bundler
193+
plugins could use it to re-build wasm packages, but then they are already
194+
running their own local server and are doing bundler-y stuff in-between the wasm
195+
package build and serving the newest wasm, like minifying some JS.
196+
197+
## Alternative: Don't.
198+
199+
Are we fine with the status quo where `wasm-pack` can neither locally serve
200+
files nor watch for file changes and auto rebuild? I think that *if* we want to
201+
remove the npm and bundler usage from the Game of Life tutorial, then the answer
202+
is "no". But maybe it isn't worth the hassle to port the Game of Life tutorial
203+
and add these `wasm-pack` features?
204+
205+
# Unresolved Questions
206+
[unresolved]: #unresolved-questions
207+
208+
* Which local HTTP server binary should we use?
209+
210+
| Server | Windows/macOs/Linux Binary Releases? | `application/wasm` MIME type? |
211+
|-------------------------------------|--------------------------------------|-------------------------------|
212+
| [`miniserve`][miniserve] | Yes | Yes |
213+
| [`httplz`][https] | No | Yes |
214+
| [`simple-http-server`][simple-http] | Yes | No |
215+
216+
There are probably even more options on crates.io than this, but these were
217+
the ones that I found in a quick search and seemed actively maintained.
218+
219+
Given these results, I think we should pursue `miniserve` further: reach out
220+
to the maintainers to make sure they are cool with it and don't intend on
221+
ditching the project any time soon.
222+
223+
We *could* also write our own local server binary using existing crates for
224+
writing Web servers, which shouldn't be *too* hard given our limited need for
225+
features. But ideally we shouldn't need to do this given that `miniserve`
226+
seems to fulfill all of our requirements.
227+
228+
[https]: https://crates.io/crates/https
229+
[miniserve]: https://crates.io/crates/miniserve
230+
[simple-http]: https://crates.io/crates/simple-http-server

0 commit comments

Comments
 (0)