Skip to content

Commit ff4be7e

Browse files
authored
Introduce the build command in the CLI (#721)
* Introduce the `build` command in the CLI This commit introduces a `build` command in the CLI, which behaves exactly as the compile command and introduces a deprecation warning to the existing `compile` command. Additionally, as a preparation for the CLI redesign discussed in #702, this commit introduces a small refactoring of the code generation process, by: * Introducing a code generator builder, to abstract and validate all the code generation option combinations. * Introducing proper static and dynamic code generator modules, making it easier to divide the responsilibities of each. The main motivation for the refactoring is to: * Make it easier to finalize the CLI redesign. * Share code between the `compile` and `build` command while they must be equivalent. * Make it easier to keep the `compile` command frozen while it becomes deprecated and at the same time evolve the `build` command independently. NB: Given that the `compile` and `build` command are exactly the same, and that this change is purely mechanical; this change doesn't introduce integration tests for the `build` command. The plan is to introduce tests once other options are added to the `build` command as part of the CLI redesign. Alternatively, tests can be added, however, it would require either duplicating the entire test suite or adding testing infrastructure to minimize duplication, which will increase the size of the change. * Collapse `provider_version` call in `builder` * Improve some documentation * Clarify `source_compression` docs * Stylistic changes * Add NOTICE to help text of `compile` * Use `eprintln!` instead of `println!` * Use `build` in the README.md
1 parent c2135a0 commit ff4be7e

File tree

12 files changed

+749
-371
lines changed

12 files changed

+749
-371
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function writeOutput(output) {
132132
Create a WebAssembly binary from your JavaScript by:
133133

134134
```bash
135-
javy compile index.js -o destination/index.wasm
135+
javy build index.js -o destination/index.wasm
136136
```
137137

138138
For more information on the commands you can run `javy --help`
@@ -147,12 +147,12 @@ $ echo '{ "n": 2, "bar": "baz" }' | wasmtime index.wasm
147147
If you have a lot of JavaScript and you want to reduce compile times, try using the `--no-source-compression` flag. It will skip compressing the JavaScript source code when generating the Wasm module but will result in the Wasm module being larger.
148148

149149
```bash
150-
javy compile index.js -o destination/index.wasm --no-source-compression
150+
javy build index.js -o destination/index.wasm --no-source-compression
151151
```
152152

153153
### Exporting functions
154154

155-
To export exported JavaScript functions, you can pass a WIT file and WIT world when running `javy compile`. Only ESM exports are supported (that is, Node.js/CommonJS exports are _not_ supported). For each exported JavaScript function, Javy will add an additional function export to the WebAssembly module. Exported functions with arguments and generators are not supported. Return values will also be dropped and not returned. The Wasm module generated is a core Wasm module, **not** a Wasm component.
155+
To export exported JavaScript functions, you can pass a WIT file and WIT world when running `javy build`. Only ESM exports are supported (that is, Node.js/CommonJS exports are _not_ supported). For each exported JavaScript function, Javy will add an additional function export to the WebAssembly module. Exported functions with arguments and generators are not supported. Return values will also be dropped and not returned. The Wasm module generated is a core Wasm module, **not** a Wasm component.
156156

157157
An example looks like:
158158

@@ -176,13 +176,13 @@ world index-world {
176176

177177
In the terminal:
178178
```bash
179-
$ javy compile index.js --wit index.wit -n index-world -o index.wasm
179+
$ javy build index.js --wit index.wit -n index-world -o index.wasm
180180
$ wasmtime run --invoke foo index.wasm
181181
Hello world!
182182
Hello from foo!
183183
```
184184

185-
The WIT package name and WIT world name do not matter as long as they are present and syntactically correct WIT (that is, it needs to be two names separated by a `:`). The name of the WIT world (that is, the value after `world` and before `{`) must be passed as the `-n` argument. The `-n` argument identifies the WIT world in the WIT file for the Wasm module generated by `javy compile`.
185+
The WIT package name and WIT world name do not matter as long as they are present and syntactically correct WIT (that is, it needs to be two names separated by a `:`). The name of the WIT world (that is, the value after `world` and before `{`) must be passed as the `-n` argument. The `-n` argument identifies the WIT world in the WIT file for the Wasm module generated by `javy build`.
186186

187187
#### Exports with multiple words
188188

@@ -206,7 +206,7 @@ world index {
206206

207207
In the terminal:
208208
```bash
209-
$ javy compile index.js --wit index.wit -n index -o index.wasm
209+
$ javy build index.js --wit index.wit -n index -o index.wasm
210210
$ wasmtime run --invoke foo-bar index.wasm
211211
In foo-bar
212212
```
@@ -233,7 +233,7 @@ world index {
233233

234234
In the terminal:
235235
```bash
236-
$ javy compile index.js --wit index.wit -n index -o index.wasm
236+
$ javy build index.js --wit index.wit -n index -o index.wasm
237237
$ wasmtime run --invoke default index.wasm
238238
In default
239239
```
@@ -271,7 +271,7 @@ The `javy_quickjs_provider.wasm` module is available as an asset on the Javy rel
271271

272272
```
273273
$ echo 'console.log("hello world!");' > my_code.js
274-
$ javy compile -d -o my_code.wasm my_code.js
274+
$ javy build -d -o my_code.wasm my_code.js
275275
$ javy emit-provider -o provider.wasm
276276
$ wasmtime run --preload javy_quickjs_provider_v2=provider.wasm my_code.wasm
277277
hello world!

crates/cli/src/codegen/builder.rs

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::codegen::{CodeGen, CodeGenType, DynamicGenerator, StaticGenerator};
2+
use anyhow::{bail, Result};
3+
use std::path::PathBuf;
4+
5+
/// Options for using WIT in the code generation process.
6+
#[derive(Default)]
7+
pub(crate) struct WitOptions {
8+
/// The path of the .wit file to use.
9+
pub path: Option<PathBuf>,
10+
/// The name of the wit world to use.
11+
pub world: Option<String>,
12+
}
13+
14+
impl WitOptions {
15+
pub fn from_tuple(opts: (Option<PathBuf>, Option<String>)) -> Result<Self> {
16+
match opts {
17+
(None, None) => Ok(Self {
18+
path: None,
19+
world: None,
20+
}),
21+
(None, Some(_)) => Ok(Self {
22+
path: None,
23+
world: None,
24+
}),
25+
(Some(_), None) => bail!("Must provide WIT world when providing WIT file"),
26+
(path, world) => Ok(Self { path, world }),
27+
}
28+
}
29+
30+
/// Whether WIT options were defined.
31+
pub fn defined(&self) -> bool {
32+
self.path.is_some() && self.world.is_some()
33+
}
34+
35+
/// Unwraps a refernce to the .wit file path.
36+
pub fn unwrap_path(&self) -> &PathBuf {
37+
self.path.as_ref().unwrap()
38+
}
39+
40+
/// Unwraps a reference to the WIT world name.
41+
pub fn unwrap_world(&self) -> &String {
42+
self.world.as_ref().unwrap()
43+
}
44+
}
45+
46+
/// A code generation builder.
47+
#[derive(Default)]
48+
pub(crate) struct CodeGenBuilder {
49+
/// The QuickJS provider module version.
50+
provider_version: Option<&'static str>,
51+
/// WIT options for code generation.
52+
wit_opts: WitOptions,
53+
/// Whether to compress the original JS source.
54+
source_compression: bool,
55+
}
56+
57+
impl CodeGenBuilder {
58+
/// Create a new [`CodeGenBuilder`].
59+
pub fn new() -> Self {
60+
Self::default()
61+
}
62+
63+
/// Set the provider version.
64+
pub fn provider_version(&mut self, v: &'static str) -> &mut Self {
65+
self.provider_version = Some(v);
66+
self
67+
}
68+
69+
/// Set the wit options.
70+
pub fn wit_opts(&mut self, opts: WitOptions) -> &mut Self {
71+
self.wit_opts = opts;
72+
self
73+
}
74+
75+
/// Whether to compress the JS source.
76+
pub fn source_compression(&mut self, compress: bool) -> &mut Self {
77+
self.source_compression = compress;
78+
self
79+
}
80+
81+
/// Build a [`CodeGenerator`].
82+
pub fn build<T>(self) -> Result<Box<dyn CodeGen>>
83+
where
84+
T: CodeGen,
85+
{
86+
match T::classify() {
87+
CodeGenType::Static => self.build_static(),
88+
CodeGenType::Dynamic => self.build_dynamic(),
89+
}
90+
}
91+
92+
fn build_static(self) -> Result<Box<dyn CodeGen>> {
93+
let mut static_gen = Box::new(StaticGenerator::new());
94+
95+
static_gen.source_compression = self.source_compression;
96+
static_gen.wit_opts = self.wit_opts;
97+
98+
Ok(static_gen)
99+
}
100+
101+
fn build_dynamic(self) -> Result<Box<dyn CodeGen>> {
102+
let mut dynamic_gen = Box::new(DynamicGenerator::new());
103+
104+
if let Some(v) = self.provider_version {
105+
dynamic_gen.import_namespace = String::from("javy_quickjs_provider_v");
106+
dynamic_gen.import_namespace.push_str(v);
107+
} else {
108+
bail!("Provider version not specified")
109+
}
110+
111+
dynamic_gen.wit_opts = self.wit_opts;
112+
113+
Ok(dynamic_gen)
114+
}
115+
}

0 commit comments

Comments
 (0)