Skip to content
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

## 4.0.0.beta.4

- Update documentation #94
- Add cargo build config and prebuilt support #91
- Prevent leaking source code in examples #90
- Add tests and docs for configurable toolchain overrides #89

## 4.0.0.beta.3

- Execute cargo build inside `workPath` #85
Expand Down
95 changes: 53 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ Community-maintained package to support using [Rust](https://www.rust-lang.org/)

The below documentation is for the `vercel_runtime` crate (in beta). If you are looking for the legacy runtime instructions using `vercel_lambda` see [tree/a9495a0](https://github.com/vercel-community/rust/tree/a9495a0f0d882a36ea165f1629fcc79c30bc3108).

## Usage
## Getting Started

First, you'll need a `vercel.json` file in your project:
> Please ensure [Vercel CLI](https://vercel.com/docs/cli#installing-vercel-cli) and the Rust toolchain is already installed on your system. We recommended setting up Rust with [rustup](https://rustup.rs/).

[Prefer looking at examples?](https://github.com/vercel-community/rust/tree/main/examples)

**Step 1** - Add a `vercel.json` file to your project.

```json
{
Expand All @@ -34,9 +38,11 @@ First, you'll need a `vercel.json` file in your project:
}
```

A Vercel Function will be created for every file that matches `api/**/*.rs`.
This turns every file matching `api/**/*.rs` into a Vercel Function.

Example:
> **Note:** The npm dependency `vercel-rust` defined in [functions](https://vercel.com/docs/concepts/projects/project-configuration#functions) **does not** have to be installed manually.

**Step 2** - Create a function. As an example, here is `api/handler.rs`.

```rust
use serde_json::json;
Expand All @@ -61,10 +67,13 @@ pub async fn handler(_req: Request) -> Result<Response<Body>, Error> {
}
```

Finally we need a `Cargo.toml` file at the root of your repository.
**Step 3** - Create a `Cargo.toml` in the root directory of your project.

```toml
# --snip--
[package]
name = "my-vercel-api"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1", features = ["macros"] }
Expand All @@ -81,27 +90,39 @@ vercel_runtime = { version = "0.2.1" }
name = "handler"
path = "api/handler.rs"

# Note that you need to provide unique names for each binary
[[bin]]
name = "user-id"
path = "api/user/[id].rs"
# Note that you need to provide unique names for each binary:
# [[bin]]
# name = "user-id"
# path = "api/user/[id].rs"
#
# [[bin]]
# name = "group-id"
# path = "api/group/[id].rs"
```

[[bin]]
name = "group-id"
path = "api/group/[id].rs"
**Step 4** - Create a `.vercelignore` in the root directory of your project to ignore build artifacts.

# --snip--
```shell
target/
```

**Step 5** - You're all set. Run `vercel dev` to develop your project locally. You can connect a Git repository to Vercel, or use `vercel` to start deploying your project on Vercel.

## Advanced Usage

### Toolchain Overrides

An example on how this can be achieved is using a `rust-toolchain` file adjacent to your `Cargo.toml`. Please refer to [Rust Documentation](https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file) for more details.

### Dependencies

This Builder supports installing dependencies defined in the `Cargo.toml` file.
By default builder module supports installing dependencies defined in the `Cargo.toml` file.

Furthermore, more system dependencies can be installed at build time with the presence of a shell `build.sh` file in the same directory as the entrypoint file.
More system dependencies can be installed at build time with the presence of a shell `build.sh` file in the root directory of your project.

## Prebuilt Deployments
### Prebuilt Deployments

When creating a prebuilt deployment, the build output must be for x86_64 linux. To do this, create a Cargo build configuration at `.cargo/config.toml` with the following contents:
When creating a prebuilt deployment, the build output must be for `x86_64 linux`. To do this, create a Cargo build configuration at `.cargo/config.toml` with the following contents:

```toml
[build]
Expand All @@ -113,17 +134,17 @@ target = "x86_64-unknown-linux-musl"
# linker = "x86_64-unknown-linux-gnu-gcc"
```

You then can build the file and trigger the deployment with the Vercel CLI.
You then can build the file and trigger the deployment via [Vercel CLI](https://vercel.com/docs/cli#installing-vercel-cli).

```shell
vercel build && vercel deploy --prebuilt
```

## Local Development
### Musl/Static linking

With `vercel dev` and `vercel-rust`, you can develop your Rust-based lambdas on your own machine.
Unfortunately, the AWS Lambda Runtime for Rust relies (tangentially) on `proc_macro`, which won't compile on musl targets. Without `musl`, all linking must be dynamic. If you have a crate that relies on system libraries like `postgres` or `mysql`, you can include those library files with the `includeFiles` config option and set the proper environment variables, config, etc. that you need to get the library to compile.

During local development with `vercel dev`, ensure `rust` and `cargo` are already installed and available in your `PATH`, since they will not be installed automatically. The recommended way to install is with [rustup](https://rustup.rs/).
For more information, please see [this issue](https://github.com/mike-engel/vercel-rust/issues/2).

## Contributing

Expand All @@ -137,29 +158,19 @@ pnpm install
cargo fetch
```

## Invocation Flowchart
### Builder Module

The _npm_ module `vercel-rust` is implementing an interface which is primarily taking care of spawning a development server, caching between consecutive builds, and running the compilation. You can read more about the in-depths of implementing a builder [here](https://github.com/vercel/vercel/blob/main/DEVELOPING_A_RUNTIME.md).

Note that this dependency **does not** have to be installed manually as it is pulled automatically.

### Runtime Crate

The crate `vercel_runtime` is what you will consume in your Rust functions. As the name suggests, the runtime crate takes care of everything that happens during run-time. In specific it takes care of creating a [Tower](https://docs.rs/tower/latest/tower/trait.Service.html) service, which expects a specific handler signature. The flow of an invocation can be visualized as the following:

```mermaid
graph TD
A["Lambda Invocation"] --> |"process_request(event: LambdaEvent&lt;VercelEvent&gt;) → Request"| B[Request]
A["Function Invocation"] --> |"process_request(event: InvocationEvent&lt;VercelEvent&gt;) → Request"| B[Request]
B --> |"handler_fn(req: Request) → Future&lt;Output = Result&lt;Response&lt;Body&gt;, Error&gt;&gt;"| C["Runtime calls handler_fn"]
C --> |"Ok(r) => process_response(r)"| D["Response"]
```

## FAQ

<details>
<summary>How to specify toolchain overrides</summary>

An example on how this can be achieved is using a `rust-toolchain` file adjacent to your `Cargo.toml`. Please refer to [Rust Documentation](https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file) for more details.

</details>

<details>
<summary>Can I use musl/static linking?</summary>

Unfortunately, the AWS Lambda Runtime for Rust relies (tangentially) on `proc_macro`, which won't compile on musl targets. Without `musl`, all linking must be dynamic. If you have a crate that relies on system libraries like `postgres` or `mysql`, you can include those library files with the `includeFiles` config option and set the proper environment variables, config, etc. that you need to get the library to compile.

For more information, please see [this issue](https://github.com/mike-engel/vercel-rust/issues/2).

</details>