Cargo, please compile & bundle the frontend too. Thanks.
⚡ Seamlessly integrate ViteJS into your Rust project.
package.json changes required.[!CAUTION] We've written tests for Unix operating systems. Windows support is still a work-in-progress. Please report any issues you encounter!
#[derive(vite_rs::Embed)]
#[root = "./app"]
struct Assets;
fn main() {
let asset: ViteFile = Assets::get("index.html").unwrap();
println!("Content-Type: {}", asset.content_type);
println!("Content-Length: {}", asset.content_length);
println!("Content-Hash: {}", asset.content_hash);
println!("Last-Modified: {}", asset.last_modified);
println!("Content: {}", std::str::from_utf8(&asset.bytes).unwrap());
}
#[root = "<path>"]#[output = "<path>"]#[dev_server_port = "<port>"]#[crate_path = "<path>"]test_projects directory?You'll need a ViteJS project.
Option A: You already have one. Move on to step 2.
Option B: Follow the ViteJS docs to create a new project.
Example: to create a project at ./app with the react-ts template:
sh
cd your/rust/project
npm create vite@latest ./app -- --template react-ts
Option C: Create a barebones project from scratch.
sh
cd your/rust/project
npm install -D vite
Create app/vite.config.ts:
``ts
import { defineConfig } from "vite";
// if using react, uncomment below and install vianpm i -D @vitejs/plugin-react`
// import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
/ react() /
],
build: {
rollupOptions: {
input: ["index.html"],
},
},
// Uncomment this section if you're going to use start_dev_server in Rust:
// server: {
// hmr: {
// port: 21012,
// },
// },
});
```
Note 1: You can read more details about the server.hmr.port option here. HMR is important for your development experience; it allows you to see frontend changes without having to refresh your browser.
Note 2: You'll eventually have to change the input array to include all your entrypoints. Alternatively, see the section below for a way to automatically bundle all files that match a pattern.
Create app/index.html:
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
Add this crate as a dependency.
sh
cargo add vite-rs
```rust #[derive(vite_rs::Embed)] #[root = "./app"] struct Assets;
fn main() {
#[cfg(debug_assertions)]
// Optional: start the dev server and stop it on SIGINT, SIGTERM or when this guard goes out of scope
let _guard = Assets::start_dev_server(true);
// ...
let asset: vite_rs::ViteFile = Assets::get("index.html").unwrap();
println!("Content-Type: {}", asset.content_type);
println!("Content-Length: {}", asset.content_length);
println!("Content-Hash: {}", asset.content_hash);
println!("Last-Modified: {:?}", asset.last_modified);
println!("Content: {}", std::str::from_utf8(&asset.bytes).unwrap());
}
```
```sh # Assets served from a Vite dev server: cargo run
# or, to see the embedded assets in action: cargo run --release ```
See the crates/vite-rs/examples and crates/vite-rs/tests folders for more examples.
Follow the "Quick Start" guide for all frameworks.
Replace src/main.rs with:
```rust use axum::Router; use vite_rs_axum_0_8::ViteServe; use tokio::net::TcpListener;
#[derive(vite_rs::Embed)] #[root = "./app"] struct Assets;
#[tokio::main] async fn main() { #[cfg(debug_assertions)] let _guard = Assets::start_dev_server(true);
println!("Starting server on http://localhost:3000");
let _ = axum::serve(
TcpListener::bind("0.0.0.0:3000").await.unwrap(),
Router::new()
.route_service("/", ViteServe::new(Assets::boxed()))
.route_service("/{*path}", ViteServe::new(Assets::boxed()))
.into_make_service(),
)
.await;
} ```
Note: If you'd like to handle graceful shutdown and also manage the ViteJS dev server lifecycle in Rust, see the example binary in crates/vite-rs-axum-0-8/test_projects/ctrl_c_handling_test. Alternatively, you can manage the ViteJS dev server lifecycle yourself in a separate terminal. Make sure your HMR port is set correctly.
http://localhost:3000/!```sh # Assets served from a Vite dev server: cargo run
# or, to see the embedded assets in action: cargo run --release ```
ctrlc: (enabled by default) Handles Ctrl-C handling if you manage the ViteJS dev server in Rust.
content-hash: (enabled by default) Computes a SHA-256 content hash in release builds for all files. See the ViteFile struct's fields for more information. Useful for cache busting. In dev, this will use a weak hash that Vite generates internally using the content length and last modified time of the file.
debug-prod: Builds and embeds ViteJS content instead of serving from a dev server. Used to make non-release builds behave exactly like release builds.
When you derive the vite_rs::Embed trait, some methods are generated for your struct which allow you to interact with your Vite assets. In development, the methods differ in behavior from release builds.
#[derive(vite_rs::Embed)]
struct Assets;
rust
Assets::get(path: &str) -> Option<vite_rs::ViteFile>
rust
Assets::iter() -> impl Iterator<Item = Cow<'static, str>>
rust
Assets::boxed() -> Box<dyn vite_rs::GetFromVite>
When you have a boxed reference, you can access individual assets like so:
```rust let assets = Assets::boxed();
let asset = assets.get("index.html").unwrap(); ```
ViteFile STRUCT: See Rust doc for vite_rs::ViteFile. Note: Rust docs only shows dev build fields. You'll have to click 'Source' to see the release build fields.GET ASSET: Get an asset by its path. Fetches assets from the dev server over HTTP. See the release build API for Assets::get() above.
REFERENCE ALL ASSETS: Get a reference to all assets. See the release build API for Assets::boxed() above.
START DEV SERVER: Starts the ViteJS dev server. This function returns an RAII guard that stops the dev server when it goes out of scope.
``rust
// withctrlc` feature enabled:
Assets::start_dev_server(register_ctrl_c_handler: bool) -> vite_rs::ViteProcess
// without ctrlc feature:
Assets::start_dev_server() -> vite_rs::ViteProcess
```
Note: The ctrlc feature is enabled by default. If you pass in true for register_ctrl_c_handler, it will stop the dev server on SIGTERM/SIGINT/SIGHUP.
rust
Assets::stop_dev_server()
ViteFile STRUCT: See Rust doc for vite_rs::ViteFile.Note: In development, you cannot iterate over all assets because there is no way to do so using the Vite dev server.
The derive macro (#[vite_rs::Embed]) supports the following options:
#[root = "<path>"]Notes:
Defaults to CARGO_MANIFEST_DIR.
If your Vite config is in the same directory as your Cargo.toml file, you don't need to specify this.
The root directory is where the vite commands are run from; that means node_modules should be in this directory (or any parent).
Example Usage:
If our vite config was located in ./app:
```rust
struct Assets; ```
#[output = "<path>"]Notes:
Defaults to ./dist (Vite's default output directory)
Required if you change build.outDir in your Vite config.
Example Usage:
If we had a custom value for build.outDir in our Vite config:
```ts // vite.config.ts import { defineConfig } from "vite";
export default defineConfig({ build: { outDir: "build", }, }); ```
We would use the attribute like so:
```rust
struct Assets; ```
#[dev_server_port = "<port>"]Notes:
Defaults to 3000.
Example Usage:
If our Vite dev server was running on port 3001:
```rust
struct Assets; ```
#[crate_path = "<path>"]vite_rs crate.Notes:
Defaults to vite_rs.
This is useful when vite_rs is not in the same crate as the struct you're embedding assets in.
Example Usage:
If we had a struct in a different crate:
```rust use my::path::to::vite_rs;
struct Assets; ```
The vite-rs-axum-0-8 crate provides an integration with Axum 0.8. It exposes a Tower service that serves embedded files similar to how you might serve static files in Axum. Go to the Crate's README for more details here: crates/vite-rs-axum-0-8.
vite-rs makes it easy to use ViteJS in your Rust project. It tries to be simple by not requiring any changes to build scripts, Vite config files, or introduce additional tools/CLI. Everything is done via cargo:
cargo build --release embeds the ViteJS-compiled artifacts into your binary. This means you don't have to copy any files around and manage how they are deployed. They ship with your binary.
cargo run also starts the ViteJS dev server for you. This means you don't have to run a command to start the dev server (ex: npm run dev) in a separate terminal. You'll still need your source files for this though; it's meant to be used in development. If you prefer running i
$ claude mcp add vite-rs \
-- python -m otcore.mcp_server <graph>