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:
- I won't go into depth here, but you need to enable the wasm32-unknown-unknown compilation target for WebAssembly to work.
- Trunk is a bundler for Yew. You can install it using
cargo
, but I opted for a prebuilt binary. I usedbrew
, but there are a number of methods available. - 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"] }
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>
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"
}
}
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();
}
Try running your app now to see if everything's working correctly. You'll need to use trunk serve
.
Installing UnoCSS
See that text-5xl
class there? That doesn't do anything yet. The next stage is to install UnoCSS:
- UnoCSS runs on JavaScript, so we'll need to create a Node project. I prefer
pnpm
, but you can also usenpm
oryarn
. - We're going to add two devDependencies:
@unocss/cli
andconcurrently
.
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"
}
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"
},
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",
- We're telling UnoCSS to search through
index.html
as well as every Rust file insrc
. - It's going to spit out the generated CSS file (
uno.css
) in thestatic
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" />
- This is a special
<link>
.data-trunk
is how we tell Trunk to process assets. - Trunk supports a few types of assets. The
rel="{type}"
we're looking for here iscss
. - We're setting the
href
attribute to theuno.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:
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" />
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'",
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'",
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:
- It worked! An
uno.css
file was generated in thestatic
directory. - 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.
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)