Skip to content

Introduce the build command in the CLI #721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function writeOutput(output) {
Create a WebAssembly binary from your JavaScript by:

```bash
javy compile index.js -o destination/index.wasm
javy build index.js -o destination/index.wasm
```

For more information on the commands you can run `javy --help`
Expand All @@ -147,12 +147,12 @@ $ echo '{ "n": 2, "bar": "baz" }' | wasmtime index.wasm
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.

```bash
javy compile index.js -o destination/index.wasm --no-source-compression
javy build index.js -o destination/index.wasm --no-source-compression
```

### Exporting functions

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

An example looks like:

Expand All @@ -176,13 +176,13 @@ world index-world {

In the terminal:
```bash
$ javy compile index.js --wit index.wit -n index-world -o index.wasm
$ javy build index.js --wit index.wit -n index-world -o index.wasm
$ wasmtime run --invoke foo index.wasm
Hello world!
Hello from foo!
```

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

#### Exports with multiple words

Expand All @@ -206,7 +206,7 @@ world index {

In the terminal:
```bash
$ javy compile index.js --wit index.wit -n index -o index.wasm
$ javy build index.js --wit index.wit -n index -o index.wasm
$ wasmtime run --invoke foo-bar index.wasm
In foo-bar
```
Expand All @@ -233,7 +233,7 @@ world index {

In the terminal:
```bash
$ javy compile index.js --wit index.wit -n index -o index.wasm
$ javy build index.js --wit index.wit -n index -o index.wasm
$ wasmtime run --invoke default index.wasm
In default
```
Expand Down Expand Up @@ -271,7 +271,7 @@ The `javy_quickjs_provider.wasm` module is available as an asset on the Javy rel

```
$ echo 'console.log("hello world!");' > my_code.js
$ javy compile -d -o my_code.wasm my_code.js
$ javy build -d -o my_code.wasm my_code.js
$ javy emit-provider -o provider.wasm
$ wasmtime run --preload javy_quickjs_provider_v2=provider.wasm my_code.wasm
hello world!
Expand Down
115 changes: 115 additions & 0 deletions crates/cli/src/codegen/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::codegen::{CodeGen, CodeGenType, DynamicGenerator, StaticGenerator};
use anyhow::{bail, Result};
use std::path::PathBuf;

/// Options for using WIT in the code generation process.
#[derive(Default)]
pub(crate) struct WitOptions {
/// The path of the .wit file to use.
pub path: Option<PathBuf>,
/// The name of the wit world to use.
pub world: Option<String>,
}

impl WitOptions {
pub fn from_tuple(opts: (Option<PathBuf>, Option<String>)) -> Result<Self> {
match opts {
(None, None) => Ok(Self {
path: None,
world: None,
}),
(None, Some(_)) => Ok(Self {
path: None,
world: None,
}),
(Some(_), None) => bail!("Must provide WIT world when providing WIT file"),
(path, world) => Ok(Self { path, world }),
}
}

/// Whether WIT options were defined.
pub fn defined(&self) -> bool {
self.path.is_some() && self.world.is_some()
}

/// Unwraps a refernce to the .wit file path.
pub fn unwrap_path(&self) -> &PathBuf {
self.path.as_ref().unwrap()
}

/// Unwraps a reference to the WIT world name.
pub fn unwrap_world(&self) -> &String {
self.world.as_ref().unwrap()
}
}

/// A code generation builder.
#[derive(Default)]
pub(crate) struct CodeGenBuilder {
/// The QuickJS provider module version.
provider_version: Option<&'static str>,
/// WIT options for code generation.
wit_opts: WitOptions,
/// Whether to compress the original JS source.
source_compression: bool,
}

impl CodeGenBuilder {
/// Create a new [`CodeGenBuilder`].
pub fn new() -> Self {
Self::default()
}

/// Set the provider version.
pub fn provider_version(&mut self, v: &'static str) -> &mut Self {
self.provider_version = Some(v);
self
}

/// Set the wit options.
pub fn wit_opts(&mut self, opts: WitOptions) -> &mut Self {
self.wit_opts = opts;
self
}

/// Whether to compress the JS source.
pub fn source_compression(&mut self, compress: bool) -> &mut Self {
self.source_compression = compress;
self
}

/// Build a [`CodeGenerator`].
pub fn build<T>(self) -> Result<Box<dyn CodeGen>>
where
T: CodeGen,
{
match T::classify() {
CodeGenType::Static => self.build_static(),
CodeGenType::Dynamic => self.build_dynamic(),
}
}

fn build_static(self) -> Result<Box<dyn CodeGen>> {
let mut static_gen = Box::new(StaticGenerator::new());

static_gen.source_compression = self.source_compression;
static_gen.wit_opts = self.wit_opts;

Ok(static_gen)
}

fn build_dynamic(self) -> Result<Box<dyn CodeGen>> {
let mut dynamic_gen = Box::new(DynamicGenerator::new());

if let Some(v) = self.provider_version {
dynamic_gen.import_namespace = String::from("javy_quickjs_provider_v");
dynamic_gen.import_namespace.push_str(v);
} else {
bail!("Provider version not specified")
}

dynamic_gen.wit_opts = self.wit_opts;

Ok(dynamic_gen)
}
}
Loading
Loading