Building My Portfolio Website with Rust and Leptos: A Journey into WebAssembly

Vasantha Kumar
Google Cloud - Community
4 min readMar 5, 2024
Rust + Wasm + Leptos

As a software engineer, having a strong portfolio website is crucial for showcasing your skills and attracting potential employers. While there are many tools and frameworks available, I wanted to take a different approach and build my portfolio using Rust and the Leptos web framework. This decision was driven by several factors:

  • Learning Rust: I’ve been fascinated by Rust’s potential for web development and wanted to gain practical experience with the language.
  • Exploring WebAssembly: Leptos leverages WebAssembly (WASM), which allows for near-native performance in web applications. I was eager to explore this technology and its benefits.
  • Tailwind CSS: I appreciate Tailwind’s utility-first approach to styling, which makes it easy to create a clean and responsive website.
  • GCP: Google Cloud Platform provides a broad range of modular services including compute, storage, data analytics, machine learning, and many more. I’ll be deploying this application in the App Engine.

The Development Process

The project involved several key steps:

  1. Defining Components: I broke down the website into reusable components like About, Experience, and Skills. This modular approach made development and maintenance easier.
  2. Data Modeling: I created data structures in Rust to represent the information displayed on the website, such as my bio, skills, and experience details. This data is loaded from a JSON file, allowing for easy updates.
  3. Server-Side Rendering (SSR) and Hydration: Leptos provides excellent support for SSR, which improves SEO and initial page load times. It also allows for client-side hydration, ensuring a smooth and interactive user experience.
  4. Styling with Tailwind CSS: Tailwind’s utility classes made it easy to style the website and achieve a clean and responsive design.
  5. Deployment on GCP: I chose Google Cloud Platform to host the website, leveraging its scalability and reliability.

Challenges and Learnings

While the project was a rewarding experience, it also presented some challenges:

  • Learning Curve: Rust and Leptos are relatively new technologies, and the learning curve was steeper compared to more established web development tools. However, the supportive community and excellent documentation helped me overcome these hurdles.
  • Debugging WASM: Debugging WASM code can be tricky, but Leptos provides helpful tools and techniques to identify and resolve issues.

Despite the challenges, I learned a great deal about Rust, WebAssembly, and modern web development practices. I’m thrilled with the final result, a performant and visually appealing portfolio website that showcases my skills and interests.

Code Snippets: A Glimpse into the Project

To give you a better understanding of the development process, let’s look at some critical code snippets:

1. Defining a Component:

Here’s how I defined the Hero component, which displays my name and title:

#[component]
pub fn Hero(name: ReadSignal<String>, title: ReadSignal<String>) -> impl IntoView {
...
view! {
<section id="hero" class="...">
<div class="container mx-auto">
<h2 class="text-4xl ...">{name}</h2>
<h3 class="text-xl ...">{title}</h3>
</div>
</section>
}
}

This code uses Lepto’s view! macro to define the HTML structure of the component. It also demonstrates how to use reactive signals (name and title) to dynamically update the content.

2. Data Loading and Reactivity:

The following snippet shows how I loaded user data from a JSON file and ensured reactivity:

#[server(name = LoadData, prefix = "/api",
endpoint = "load-data", input = GetUrl,
output = Json)]
pub async fn load_data() -> Result<User, ServerFnError> {
let file = File::open("./data/data.json")?;
let data: User = serde_json::from_reader(file)?;
Ok(data)
}

This function utilizes Rust’s file I/O capabilities and the serde_json crate to parse the JSON data into a User struct.

let (data_loaded, set_data_loaded) = create_signal(false);
let (data, set_data) = create_signal(User::new());

create_local_resource(
|| (),
move |_| async move {
let data_result = load_data().await;
if let Ok(data) = data_result {
set_data.update(|user_data: &mut User| *user_data = data);
set_data_loaded.update(|_| true);
}
...
},
);

This code uses Lepto’s create_local_resource and create_signal functions to manage data loading and reactivity, ensuring the UI updates automatically when data changes.

Deployment on Google Cloud Platform (GCP)

For hosting my portfolio website, I chose Google Cloud Platform (GCP) due to its scalability, reliability, and ease of use. Here’s a brief overview of the deployment process:

Dockerizing the Application: I created a Dockerfile to containerize the Rust application and its dependencies. This ensures consistent deployment across different environments.

FROM rustlang/rust:nightly-bullseye as builder

# Install dependencies and build the application

FROM rustlang/rust:nightly-bullseye as runner

# Copy the built application and static assets

WORKDIR /app

# Set environment variables and expose port

CMD ["/app/portfolio"]

Building and Pushing the Docker Image: Using Cloud Build, I automated the process of building the Docker image and pushing it to the Google Container Registry (GCR). This allows for easy versioning and rollbacks.

steps:
- name: "gcr.io/cloud-builders/docker"
args: ["build", "-t", "gcr.io/$PROJECT_ID/portfolio:$TAG_NAME", "."]
- name: "gcr.io/cloud-builders/docker"
args: ["push", "gcr.io/$PROJECT_ID/portfolio:$TAG_NAME"]

Deploying to Google App Engine: Finally, I deployed the Docker image to Google App Engine, which provides a fully managed platform for hosting web applications. App Engine automatically scales the application based on traffic, ensuring optimal performance and cost efficiency.

gcloud app deploy --image-url=gcr.io/$PROJECT_ID/portfolio:$TAG_NAME

This deployment setup allows me to easily update and manage my portfolio website while ensuring high availability and performance for visitors.

Conclusion

Building my portfolio website with Rust and Leptos was a valuable learning experience. It allowed me to explore exciting new technologies and create a website that stands out from the crowd. If you’re a developer looking to challenge yourself and learn something new, I highly recommend giving Rust and Leptos a try.

Check out the website: https://www.vasanthakumar.dev/

Leave a star on the GitHub repository: https://github.com/iamvasanth07/portfolio-leptos

I hope this blog post inspires you to explore new technologies and build something awesome!

--

--