MCPcopy Index your code
hub / github.com/Wulf/vite-rs

github.com/Wulf/vite-rs @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
111 symbols 244 edges 50 files 11 documented · 10%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Cargo, please compile & bundle the frontend too. Thanks.

vite-rs

Crates.io Tests

⚡ Seamlessly integrate ViteJS into your Rust project.

  • Embeds Vite output in your binary.
  • Optionally manages the Vite dev server lifecycle in Rust.
  • Low-touch;
  • No build script changes required.
  • No package.json changes required.
  • No Vite config changes (except one for HMR), and:

[!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());
}

Table of Contents

Quick Start (all frameworks)

  1. You'll need a ViteJS project.

  2. Option A: You already have one. Move on to step 2.

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

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

  5. Add this crate as a dependency.

sh cargo add vite-rs

  1. Use the crate!

```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());
}

```

  1. Run your binary!

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

Quick Start (Use with Axum 0.8)

  1. Follow the "Quick Start" guide for all frameworks.

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

  1. Run your binary and see your app being served at http://localhost:3000/!

```sh # Assets served from a Vite dev server: cargo run

# or, to see the embedded assets in action: cargo run --release ```

Feature Flags

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

API

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;

In release builds:

  • GET ASSET: Get an asset by its path. Fetches assets embedded into the binary.

rust Assets::get(path: &str) -> Option<vite_rs::ViteFile>

  • ITERATE OVER ASSETS: Get an iterator over all assets.

rust Assets::iter() -> impl Iterator<Item = Cow<'static, str>>

  • REFERENCE ALL ASSETS: Get a reference to all assets. Useful for passing your assets around.

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.

In development builds:

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

  • STOP DEV SERVER: Stops the ViteJS dev server.

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.

Options

The derive macro (#[vite_rs::Embed]) supports the following options:

#[root = "<path>"]

  • Specifies the directory where your Vite config lives.

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

    [vite_rs::Embed]

    [root = "./app"]

    struct Assets; ```

#[output = "<path>"]

  • Specifies the directory where Vite outputs build files.

Notes:

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

    [vite_rs::Embed]

    [output = "./build"] // the outDir from your vite config

    struct Assets; ```

#[dev_server_port = "<port>"]

  • Specifies which port the Vite dev server is running on.

Notes:

Example Usage:

  • If our Vite dev server was running on port 3001:

    ```rust

    [vite_rs::Embed]

    [dev_server_port = "3001"]

    struct Assets; ```

#[crate_path = "<path>"]

  • Specifies a custom path to the 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;

    [vite_rs::Embed]

    [crate_path = "my::path::to::vite_rs"]

    struct Assets; ```

Framework Integrations

Axum 0.8

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.

Full Guide

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

Extension points exported contracts — how you extend this code

GetFromVite (Interface)
(no doc)
crates/vite-rs-interface/src/lib.rs

Core symbols most depended-on inside this repo

start_dev_server
called by 12
crates/vite-rs-dev-server/src/lib.rs
clone
called by 11
crates/vite-rs-axum-0-8/src/vite_serve.rs
stop_dev_server
called by 8
crates/vite-rs-dev-server/src/lib.rs
find_attribute_values
called by 4
crates/vite-rs-embed-macro/src/syn_utils.rs
unset_dev_server
called by 3
crates/vite-rs-dev-server/src/lib.rs
is_port_free
called by 2
crates/vite-rs-dev-server/src/util.rs
with_cache_strategy
called by 2
crates/vite-rs-axum-0-8/src/vite_serve.rs
with_fallback_strategy
called by 2
crates/vite-rs-axum-0-8/src/vite_serve.rs

Shape

Function 85
Class 15
Method 8
Enum 2
Interface 1

Languages

Rust97%
TypeScript3%

Modules by API surface

crates/vite-rs-axum-0-8/tests/basic_usage_test.rs14 symbols
crates/vite-rs/tests/normal_usage_test.rs11 symbols
crates/vite-rs/tests/recompilation_test.rs10 symbols
crates/vite-rs-axum-0-8/src/vite_serve.rs8 symbols
crates/vite-rs/tests/ctrl_c_handling_test.rs7 symbols
crates/vite-rs-embed-macro/src/lib.rs7 symbols
crates/vite-rs-dev-server/src/lib.rs6 symbols
crates/vite-rs-axum-0-8/tests/ctrl_c_handling_test.rs6 symbols
crates/vite-rs/tests/dev_server_port_test.rs4 symbols
crates/vite-rs/experiments/renaming_bundles_feature/renaming_bundles.rs4 symbols
crates/vite-rs/examples/custom_ctrl_c_handler.rs3 symbols
crates/vite-rs/examples/basic_usage.rs3 symbols

For agents

$ claude mcp add vite-rs \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact