CroftSoft / Library / Tutorials

Rust-Dioxus Project Setup

2023 Nov 04 Sat

David Wallace Croft


Contents

Summary

This article provides step-by-step instructions for using the Rust programming language and the Dioxus user interface (UI) library to make a web application. As explained in the overview, the project structure supports static prerendering with client-side hydration.

Overview

A single page application (SPA) is a web application that downloads to the client web browser as JavaScript or WebAssembly (Wasm) code with minimal HTML. Once the code starts running in the browser, it generates the HTML that it needs for the SPA dynamically as the user navigates through the application. The SPA code can also request data from a server and integrate into the dynamically generated webpages client-side.

In contrast to web applications that require server-side rendering (SSR) to integrate the HTML and data, an SPA can be served from a Content Delivery Network (CDN). Unlike a static website served from a CDN, a search engine crawler cannot load and read the webpages directly to find content since the SPA is delivered as code which must be run in a client to dynamically generate the HTML. For this reason, some prefer SSR for search engine optimization (SEO).

For SEO, some tools let you prerender the static webpages for an SPA. Once a static webpage and the SPA code are downloaded into the browser, the SPA code integrates with the static webpage in a process called client-side hydration. This allows search engine crawlers to find HTML content directly from the CDN while also permitting the SPA code to run in the browser.

Dioxus is a UI library for the Rust programming language which can be deployed as an SPA by compiling the Rust source code to Wasm. This article provides step-by-step instructions for setting up a Rust-Dioxus project to make an SPA. The project structure supports static prerendering with client-side hydration so that the SPA can be served from a CDN.

Project Setup

  1. Install Rust cargo --version
  2. Install the Dioxus CLI "dx" cargo install dioxus-cli dx --version
  3. Install Node.js
    • https://nodejs.org/
    • The Node.js installation includes the CLI for Node Package Manager (npm) and npx
    npm --version npx --version
  4. Run the Dioxus CLI command to create a new Dioxus project directory dx create
  5. When prompted, enter the following values:
    • project-name: my-project
    • What platform are you targeting?: web
    • Should the application use the dioxus router?: true
    • How do you want to create CSS?: Vanilla
  6. Change your working directory to the new project directory cd my-project/
  7. Open the project directory in your code editor code .
  8. Make an initial git commit of the default project
    • You can use git to compare the following customizations to this initial commit
    git add . git commit -m 'initial commit'
  9. Overwrite your project root directory .gitignore file with the following: /dist /node_modules /target
  10. Compile and serve the default project dx serve --hot-reload
  11. Test the code
    • Open your browser to http://localhost:8080/
    • Click on the buttons to verify that the WebAssembly (Wasm) is working
  12. Test the hot reload feature
    • In src/main.rs, change some of the text that is displayed to the user
    • Example: Change "High-Five" to "High-five"
    • Observe that the browser automatically updates when you save your change
  13. Stop the development server by pressing Control-C in the command-line terminal
  14. Overwrite your Cargo.toml file
    • The referenced "prerender" binary source code will be added in a following step
    [package] # authors = ["First Middle Last <first.middle.last@example.com>"] # description = "Dioxus SPA with static prerendering and client-side hydration" edition = "2021" # homepage = "https://www.example.com/" # keywords = ["dioxus"] # license = "MIT" name = "my-project" publish = false readme = "README.md" # repository = "https://github.com/my-github-username/my-project" version = "0.1.0" [[bin]] name = "prerender" required-features = ["prerender"] [dependencies] console_error_panic_hook = "0.1.7" dioxus = "0.4.0" dioxus-fullstack = { version = "0.4.1", optional = true } dioxus-router = "0.4.1" dioxus-web = "0.4.0" log = "0.4.20" serde = "1.0.190" tokio = { version = "1.33.0", features = ["full"], optional = true } wasm-logger = "0.2.0" [features] hydrate = ["dioxus-fullstack/router", "dioxus-web/hydrate"] prerender = ["dioxus-fullstack/router", "dioxus-fullstack/ssr", "tokio"]
  15. Rename the static assets directory mv public/ assets/
  16. Update the CSS stylesheet files rm input.css rm tailwind.config.js touch assets/stylesheet.css
  17. Overwrite your Dioxus.toml file with the following: [application] asset_dir = "assets" default_platform = "web" name = "my_project" out_dir = "dist" [web.app] title = "My Project" [web.watcher] reload_html = true watch_path = ["src", "assets"] [web.resource] style = ["/stylesheet.css"] script = [] [web.resource.dev] script = [] style = []
  18. Optionally, add a rustfmt.toml to the root of your project directory
    • This optional step will customize how your Rust source code is formatted
    • If your code editor is not already set up to use this file, use "cargo fmt"
    array_width = 1 fn_params_layout = "Vertical" hard_tabs = false match_block_trailing_comma = true max_width = 80 merge_derives = true newline_style = "Unix" remove_nested_parens = true single_line_if_else_max_width = 0 struct_lit_width = 0 struct_variant_width = 0 tab_spaces = 2 use_field_init_shorthand = true use_try_shorthand = true
  19. Replace src/main.rs use my_project::launch; #[cfg(feature = "hydrate")] fn main() { dioxus_web::launch_with_props( dioxus_fullstack::router::RouteWithCfg::<my_project::route::Route>, dioxus_fullstack::prelude::get_root_props_from_document() .expect("Failed to get root props from document"), dioxus_web::Config::default().hydrate(true), ); } #[cfg(not(feature = "hydrate"))] fn main() { launch(); }
  20. Make src/lib.rs use components::app::App; pub mod components; pub mod route; pub fn launch() { wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); dioxus_web::launch(App) }
  21. Make src/route.rs use crate::components::colophon::Colophon; use crate::components::home::Home; use crate::components::page_not_found::PageNotFound; use crate::components::page_template::PageTemplate; use dioxus::prelude::*; use dioxus_router::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, PartialEq, Routable, Serialize)] pub enum Route { #[layout(PageTemplate)] #[route("/")] Home {}, #[route("/colophon")] Colophon {}, #[end_layout] #[route("/:..route")] PageNotFound { route: Vec<String>, }, }
  22. Make the binaries subdirectory mkdir src/bin/
  23. Make src/bin/prerender.rs
    • This is the code to support static prerendering
    use dioxus_fullstack::prelude::*; use my_project::route::Route; #[tokio::main] async fn main() { pre_cache_static_routes_with_props( &ServeConfigBuilder::new_with_router( dioxus_fullstack::router::FullstackRouterConfig::<Route>::default(), ) .assets_path("dist") .incremental(IncrementalRendererConfig::default().static_dir("dist")) .build(), ) .await .unwrap(); }
  24. Make the components subdirectory mkdir src/components/
  25. Make src/components/mod.rs pub mod app; pub mod colophon; pub mod high_five; pub mod home; pub mod nav; pub mod page_not_found; pub mod page_template;
  26. Make src/components/app.rs use crate::route::Route; use dioxus::prelude::*; use dioxus_router::prelude::*; #[allow(non_snake_case)] pub fn App(cx: Scope) -> Element { render! { Router::<Route> { } } }
  27. Make src/components/colophon.rs use crate::components::high_five::HighFive; use dioxus::prelude::*; #[allow(non_snake_case)] pub fn Colophon(cx: Scope) -> Element { render! { h1 { "Colophon Page" } p { "This website was created using the Rust library ", a { href: "https://dioxuslabs.com/", target: "_blank", "Dioxus", }, "." } HighFive { } } }
  28. Make src/components/high_five.rs use dioxus::prelude::*; #[allow(non_snake_case)] pub fn HighFive(cx: Scope) -> Element { let mut count = use_state(cx, || 0); render! { h1 { "High-Five counter: {count}" } button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } } }
  29. Make src/components/home.rs use crate::components::high_five::HighFive; use dioxus::prelude::*; #[allow(non_snake_case)] pub fn Home(cx: Scope) -> Element { render! { h1 { "Home Page" } p { "This line is a placeholder for home page content." } HighFive { } } }
  30. Make src/components/nav.rs use crate::route::Route; use dioxus::prelude::*; use dioxus_router::prelude::*; #[allow(non_snake_case)] pub fn Nav(cx: Scope) -> Element { render! { nav { ul { li { Link { to: Route::Home {}, "Home" } } li { Link { to: Route::Colophon {}, "Colophon" } } } } } }
  31. Make src/components/page_not_found.rs use dioxus::prelude::*; #[allow(non_snake_case)] #[inline_props] pub fn PageNotFound( cx: Scope, route: Vec<String>, ) -> Element { render! { h1 { "Page Not Found" } pre { color: "red", "{route:?}" } } }
  32. Make src/components/page_template.rs use crate::components::nav::Nav; use crate::route::Route; use dioxus::prelude::*; use dioxus_router::prelude::*; #[allow(non_snake_case)] pub fn PageTemplate(cx: Scope) -> Element { render! { Nav { } Outlet::<Route> {} } }
  33. Compile and serve the customized project dx serve --hot-reload
  34. Test the code
    • Open your browser to http://localhost:8080/
    • Click on the buttons on the Home page to verify that the Wasm is working
    • Click on the "Colophon" link in the navigation section
    • Click on the buttons on the Colophon page to verify that the Wasm is working
  35. View the page source for the Home and Colophon pages
    • Right-click on a webpage and select "View Page Source"
    • Note how the page content is not visible within the HTML
    • This will be fixed in a later step
  36. Attempt to open the Colophon page directly in your browser
  37. Stop the development server by pressing Control-C in the command-line terminal
  38. Build the Single Page Application (SPA) with client-side hydration
    • This will recreate your distribution directory dist/
    dx build --features=hydrate --release
  39. Insert the prerendered static HyperText Markup Language (HTML)
    • This will update the HTML in dist/
    cargo run --bin prerender --features=prerender --release
  40. Serve the HTML and Wasm from your distribution directory
    • The following command will automatically open your browser
    npx http-server dist -o
  41. Verify that the webpage includes the text content
    • Press the reload button on your browser while holding the Shift key
    • Right-click on a webpage and select "View Page Source"
    • Note how the text content is visible within the HTML for search engines to find
  42. Open the Colophon page directly in your browser
    • Enter the URL http://localhost:8080/colophon/ in your browser toolbar
    • Note that the page loads without having to go to the Home page first
    • Click the buttons to verify that the Wasm is working

NPM Run Scripts

This optional section describes how to add Node Package Manager (npm) run scripts to make development and testing of your Dioxus project easier.

  1. Make a package.json file in your project root directory { "devDependencies": { "http-server": "^14.1.1", "prettier": "3.0.3", "rimraf": "^5.0.1" }, "scripts": { "clean": "rimraf dist", "dist": "npm run clean && npm run make", "format": "prettier dist --ignore-path .prettierignore --write", "hydrate": "dx build --features=hydrate --release", "prerender": "cargo run --bin prerender --features=prerender --release", "make": "npm run hydrate && npm run prerender && npm run format", "serve": "http-server dist -o", "start": "dx serve --hot-reload", "test": "npm run dist && npm run serve" } }
  2. Install the dependencies npm install
  3. Test your npm run scripts npm test
  4. Update the README.md in your project root directory # My Project - A description of My Project - Makes a Content Delivery Network (CDN)-compatible static HTML distribution - Includes static prerendering with client-side hydration ## Utilities Installation - Install the Rust command line utility "cargo" - cargo is installed when you install Rust - https://www.rust-lang.org/ - Install the Dioxus Command Line Interface (CLI) "dx" - cargo install dioxus-cli - https://github.com/DioxusLabs/dioxus/tree/master/packages/cli - Install npm - npm installs utilities such as prettier - npm scripts run the dx and cargo commands - npm can be installed by installing node.js - https://nodejs.org/ ## Hot Reload - cd my-project/ - npm install - Installs the utility http-server to serve the HTML - Installs the utility pretter to format the HTML - Installs the utility rimraf to remove distribution directory dist/ - npm start - Open your browser to http://localhost:8080/ - Make changes to the HTML in src/lib.rs or the CSS in public/stylesheet.css - Note that the changes are updated in your browser as soon as you save ## Test Static Prerendering with Hydration - npm test - Deletes the distribution directory dist/ to start clean - Makes the index.html page with the hydration code - Inserts the prerendered HTML - Formats the HTML using the prettier utility - Launches http-server to serve the HTML - Opens your browser to the home page ## Other Commands - npm run clean - Deletes the distribution directory dist/ to start clean - npm run dist - Same as npm test - Except that it does not start http-server and open the browser - npm run format - Runs the utility prettier - npm run hydrate - Makes the index.html page with the hydration code - npm run prerender - Inserts the prerendered HTML - npm run make - Makes the index.html page with the hydration code - Inserts the prerendered HTML - Runs the utility prettier - But does not start by deleting dist/ - npm run serve - Starts the http-server - Opens the browser ## Links - CroftSoft Rust-Dioxus Project Setup Tutorial - https://www.croftsoft.com/library/tutorials/rust-dioxus-project-setup/ ## History - Initial release: YYYY-MM-DD

Links

In recommended reading order:


© 2023 CroftSoft Inc

 
 
 
CroftSoft
 
 
About
Library
- Books
- Code
- Courses
- Links
- Media
- Software
- Tutorials
People
Portfolio
Update
 
 
Google
CroftSoft Web