fix: hotpatching fullstack (#4730)

* fix: hotpatching fullstack

* add hot-patching fullstack test

* add caching to playwright apt-get

* only run playwright on beta

* install binutils?

* dont commit lockfile

* ignore lockfiles

* make sure ld is in path
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2025-10-06 16:12:18 -07:00
1 parent a4aef33369
commit bee89b795d
15 files changed
+265 -38

No files matched your search

@@ -207,5 +207,13 @@ module.exports = defineConfig({
reuseExistingServer: !process.env.CI,
stdout: "pipe",
},
{
command:
'rm -rf ./web-hot-patch-fullstack-temp && cp -r ./web-hot-patch-fullstack ./web-hot-patch-fullstack-temp && cd web-hot-patch-fullstack-temp && cargo run --manifest-path ../../cli/Cargo.toml --release -- serve --verbose --force-sequential --web --addr "127.0.0.1" --port 9981 --hot-patch --exit-on-error',
port: 9981,
timeout: 50 * 60 * 1000,
reuseExistingServer: !process.env.CI,
stdout: "pipe",
},
],
});
@@ -0,0 +1,2 @@
dist
target
@@ -0,0 +1,16 @@
[package]
name = "dioxus-playwright-fullstack-patch-test"
version = "0.0.1"
edition = "2021"
description = "Playwright test for Dioxus Web"
license = "MIT OR Apache-2.0"
publish = false
[dependencies]
dioxus = { path = "../../dioxus", features = ["fullstack"] }
[features]
web = ["dioxus/web"]
server = ["dioxus/server"]
[workspace]
@@ -0,0 +1,3 @@
body {
background-color: rgb(100, 100, 100);
}
@@ -0,0 +1,3 @@
#main {
background-color: red;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,36 @@
use dioxus::prelude::*;
const CSS: Asset = asset!("/assets/style.css");
const IMAGE: Asset = asset!("/assets/toasts.png");
fn app() -> Element {
let mut num = use_signal(|| 0);
rsx! {
document::Link {
href: CSS,
rel: "stylesheet",
}
img {
id: "toasts",
src: IMAGE,
}
button {
id: "increment-button",
onclick: move |_| async move {
let increment_amount = get_count().await.unwrap();
*num.write() += increment_amount;
},
"Click me! Count: {num}"
}
}
}
#[post("/api/get_count")]
async fn get_count() -> Result<i32> {
Ok(1)
}
fn main() {
dioxus::launch(app);
}
@@ -7,6 +7,6 @@ license = "MIT OR Apache-2.0"
publish = false
[dependencies]
dioxus = { path = "../../dioxus", features = ["web"]}
dioxus = { path = "../../dioxus", features = ["web"] }
[workspace]
[workspace]
@@ -0,0 +1,113 @@
// @ts-check
const { test, expect } = require("@playwright/test");
const hotPatchTimeout = {
timeout: 1000 * 60 * 2, // 2 minute
};
test("button click", async ({ page }) => {
const fs = require("fs");
const mainPath = "web-hot-patch-fullstack-temp/src/main.rs";
var mainContent = fs.readFileSync(mainPath, "utf8");
const stylePath = "web-hot-patch-fullstack-temp/assets/style.css";
var styleContent = fs.readFileSync(stylePath, "utf8");
// Reset any changes made to the main.rs and style.css files.
mainContent = mainContent.replace(/Ok\(\s*2\s*\)/g, "Ok(1)");
mainContent = mainContent.replace("Click button! Count:", "Click me! Count:");
mainContent = mainContent.replace("asset!('/assets/alternative-style.css')", "asset!('/assets/style.css')");
fs.writeFileSync(mainPath, mainContent);
styleContent = styleContent.replace(
"background-color: blue;",
"background-color: red;"
);
fs.writeFileSync(stylePath, styleContent);
await page.goto("http://localhost:9981");
// wait a sec for the serverfn to process
// give the page time to finish loading resources
await page.waitForLoadState("networkidle");
await page.waitForTimeout(2000);
// ** First test make sure the initial fat build is working **
// Expect the page to contain the counter text.
const main = page.locator("#main");
await expect(main).toContainText("Click me! Count: 0");
// Click the increment button.
let button = page.locator("button#increment-button");
await button.click();
await page.waitForTimeout(1000);
// Expect the page to contain the updated counter text.
await expect(main).toContainText("Click me! Count: 1");
// Make sure the css is applied correctly.
await expect(main).toHaveCSS("background-color", "rgb(255, 0, 0)");
// Make sure the image is loaded.
const headerImage = page.locator("#toasts");
// expect the attribute src to start with /assets/toasts-
await expect(headerImage).toHaveAttribute("src", /\/assets\/toasts-/);
// ** Then make sure the hot patch is working **
// Then change the file to increment by 2.
const updatedContent = mainContent.replace(/Ok\(\s*1\s*\)/g, "Ok(2)");
// Change the click me text to reflect the new increment.
const updatedContentWithText = updatedContent.replace(
"Click me! Count:",
"Click button! Count:"
);
fs.writeFileSync(mainPath, updatedContentWithText);
// Wait for the page to update and show the new text.
await expect(main).toContainText("Click button! Count: 1", hotPatchTimeout);
// Now click the button again.
await button.click();
// wait a sec for the serverfn to process
await page.waitForTimeout(1000);
// Expect the count to update by 2.
await expect(main).toContainText("Click button! Count: 3");
// Next change just the css file to change the background color to blue.
const updatedStyleContent = styleContent.replace(
"background-color: red;",
"background-color: blue;"
);
fs.writeFileSync(stylePath, updatedStyleContent);
// Wait for the page to update the background color.
await expect(main).toHaveCSS(
"background-color",
"rgb(0, 0, 255)",
hotPatchTimeout
);
// Make sure the image is still loaded.
// expect the attribute src to start with /assets/toasts-
await expect(headerImage).toHaveAttribute("src", /\/assets\/toasts-/);
// ** Then add a new asset to the page **
// Switch from style to alternative-style
const updatedContentWithAlternativeStyle = updatedContentWithText.replace(
'asset!("/assets/style.css")',
'asset!("/assets/alternative-style.css")'
);
fs.writeFileSync(mainPath, updatedContentWithAlternativeStyle);
// Assert the page has the new alternative style applied.
const body = page.locator("body");
// Log the page content to debug if needed.
console.log(await page.content());
await expect(body).toHaveCSS(
"background-color",
"rgb(100, 100, 100)",
hotPatchTimeout
);
});