DEV Community

Cover image for Integrating UnoCSS with Yew
Anish Pallati
Anish Pallati

Posted on

Integrating UnoCSS with Yew

If you'd like to just use a template repository to get started faster, I've prepared one here.

Intro

If you're anything like me, you often find yourself experimenting with the latest web technologies. Unfortunately, a lot of these up-and-coming frameworks aren't compatible with each other. My latest project is a Jupyter Notebook clone, written in Rust, that runs entirely on the browser. Naturally, I looked toward Yew to create the web application.

Even using Rust, though, I didn't want to give up my Atomic CSS classes. I'm accustomed to using Tailwind CSS with frameworks like Next and Astro, but recently I've replaced it with UnoCSS. It has a preset for Tailwind, but it's significantly faster.

This guide aims to provide step-by-step instructions for integrating UnoCSS and Yew.

Setting up a Yew Project

To start off, we can create a new Yew project: asciicast

  1. I won't go into depth here, but you need to enable the wasm32-unknown-unknown compilation target for WebAssembly to work.
  2. Trunk is a bundler for Yew. You can install it using cargo, but I opted for a prebuilt binary. I used brew, but there are a number of methods available.
  3. Create a new cargo project and add Yew as a dependency. You need to enable the “csr” (short for client-side rendering) feature, because we're building a web application.

If you did everything correctly, you should have a Cargo.toml with the following:

[dependencies]
yew = { version = "0.20.0", features = ["csr"] }
Enter fullscreen mode Exit fullscreen mode

Note that your version number may be different.

Now, we just have to add a few things to get a functional Yew app. Start by creating a boilerplate index.html file in the root of your project:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body></body>
</html>
Enter fullscreen mode Exit fullscreen mode

When we run Yew, it will create static files for us in ./dist. We don't want to keep these under version control, so we can add /dist to our .gitignore.

Editor setup

This next step is optional, but if you're using VSCode, you might find it useful to enable HTML Intellisense for Rust files. Create .vscode/settings.json in the project root with the following content:

{
    "emmet.includeLanguages": {
        "rust": "html"
    }
}
Enter fullscreen mode Exit fullscreen mode

Starting the App

From there, you can populate main.rs with a dummy Yew app:

use yew::prelude::*;

#[function_component]
fn App() -> Html {
    html! {
        <p class="text-5xl">{ "Hello World!" }</p>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
Enter fullscreen mode Exit fullscreen mode

Try running your app now to see if everything's working correctly. You'll need to use trunk serve.

Initial preview

Installing UnoCSS

See that text-5xl class there? That doesn't do anything yet. The next stage is to install UnoCSS: asciicast

  1. UnoCSS runs on JavaScript, so we'll need to create a Node project. I prefer pnpm, but you can also use npm or yarn.
  2. We're going to add two devDependencies: @unocss/cli and concurrently.

If you did that correctly, you should now have a package.json with the following:

"devDependencies": {
    "@unocss/cli": "^0.48.4",
    "concurrently": "^7.6.0"
}
Enter fullscreen mode Exit fullscreen mode

Again, your version numbers may vary. Now is a good point to pop node_modules into your .gitignore.

This is also optional, but since I'm using pnpm, I'm going to add a special little script to my package.json:

"scripts": {
    ...
    "preinstall": "npx only-allow pnpm"
},
Enter fullscreen mode Exit fullscreen mode

Tying it Together

Now that the setup is out of the way, we can properly integrate UnoCSS with Yew. The reason we used @unocss/cli was because we're going to use the unocss command to scan our Rust files and generate the necessary classes. Then, all we have to do is link the generated CSS to Yew's index.html.

Create a new script in your package.json:

"uno": "unocss src/**/*.rs index.html --out-file static/uno.css",
Enter fullscreen mode Exit fullscreen mode
  1. We're telling UnoCSS to search through index.html as well as every Rust file in src.
  2. It's going to spit out the generated CSS file (uno.css) in the static directory.

Linking uno.css

To link this file in our HTML, we can add the following line to the <head> of the index.html file in our project root:

<link data-trunk rel="css" href="./static/uno.css" />
Enter fullscreen mode Exit fullscreen mode
  1. This is a special <link>. data-trunk is how we tell Trunk to process assets.
  2. Trunk supports a few types of assets. The rel="{type}" we're looking for here is css.
  3. We're setting the href attribute to the uno.css file from earlier.

Adding a CSS Reset

While we're at it, we should also implement one of the UnoCSS resets. You can pick whichever one you want, but I'm going with antfu.css, which is an extension of Tailwind CSS's Preflight. You have a couple options for linking them:

  1. Directly from the unocss repository
  2. From jsDelivr (what I recommend).

Here's all we needed to add to index.html:

<link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/@unocss/reset@0.48.4/antfu.css"
/>
<link data-trunk rel="css" href="./static/uno.css" />
Enter fullscreen mode Exit fullscreen mode

Finally, let's add /static/uno.css to our .gitignore. We'll keep a .gitkeep file in there for now, since its only file is being gitignored.

Running UnoCSS with Trunk

Remember when we installed concurrently as a devDependency? That's how we're going to run UnoCSS alongside Yew. Let's first create a “dev” script:

"dev": "concurrently 'trunk serve' 'npm run uno -- --watch'",
Enter fullscreen mode Exit fullscreen mode

Here, we're still using trunk serve to start our Yew app. We're going to run UnoCSS in watch mode so that it automatically updates ./static/uno.css when you update index.html or a Rust file in src. The extra set of dashes is necessary to pass the --watch argument.

Next, we can create a “build” script for production:

"build": "concurrently 'trunk build --release' 'npm run uno'",
Enter fullscreen mode Exit fullscreen mode

Now, we need neither UnoCSS nor Trunk in watch mode, so we can adjust both commands accordingly.

Testing our App

Now, the command to run our Yew app is pnpm run dev (you can modify this with npm or yarn if you're using those). Let's try it:

Items generated in our Yew project

  1. It worked! An uno.css file was generated in the static directory.
  2. We can see that trunk successfully processed the asset, too. If you check ./dist/index.html, you'll notice that it even updated the import to the CSS file.

Finished preview

Try changing text-5xl to other UnoCSS classes. You'll see the styles get refreshed automatically.

The full source code is available here.

Top comments (0)