diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 25f4397..f4bf8f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macOS-latest] # todo: add 'windows-latest' + os: [ubuntu-latest, macOS-latest, windows-latest] rust: [stable] experimental: [false] # Note: We're no longer reliant on nightly, so we can remove this. @@ -37,6 +37,7 @@ jobs: toolchain: ${{ matrix.rust }} - uses: actions/checkout@master - name: Install npm packages for examples & tests + shell: bash run: | (cd ./crates/vite-rs/test_projects && npm ci) (cd ./crates/vite-rs-axum-0-8/test_projects/basic_usage_test/app && npm ci) @@ -53,6 +54,7 @@ jobs: cargo test -p vite-rs-axum-0-8 cargo test -p vite-rs-axum-0-8 --release - name: Run/compile examples + shell: bash run: | # VITE-RS cargo run -p vite-rs --example basic_usage diff --git a/crates/vite-rs-axum-0-8/tests/basic_usage_test.rs b/crates/vite-rs-axum-0-8/tests/basic_usage_test.rs index 6c1a5b1..4f4530d 100644 --- a/crates/vite-rs-axum-0-8/tests/basic_usage_test.rs +++ b/crates/vite-rs-axum-0-8/tests/basic_usage_test.rs @@ -185,10 +185,18 @@ async fn ensure_serves_index(app: axum::Router) { let body_bytes = body::to_bytes(response.into_body(), 2048).await.unwrap(); #[cfg(all(debug_assertions, not(feature = "debug-prod")))] - assert_eq!(body_bytes, "\n\n \n \n\n \n\n Hello World\n \n \n \n

Loading...

\n \n \n\n"); + if cfg!(windows) { + assert_eq!(body_bytes, "\r\n\r\n \n \n\n \n\r\n Hello World\r\n \r\n \r\n \r\n

Loading...

\r\n \r\n \r\n\r\n"); + } else { + assert_eq!(body_bytes, "\n\n \n \n\n \n\n Hello World\n \n \n \n

Loading...

\n \n \n\n"); + } #[cfg(not(all(debug_assertions, not(feature = "debug-prod"))))] - assert_eq!(body_bytes, "\n\n \n Hello World\n \n \n \n \n

Loading...

\n \n\n"); + if cfg!(windows) { + assert_eq!(body_bytes, "\r\n\r\n \r\n Hello World\r\n \r\n \n \r\n \r\n

Loading...

\r\r\n \r\n\r\n"); + } else { + assert_eq!(body_bytes, "\n\n \n Hello World\n \n \n \n \n

Loading...

\n \n\n"); + } } async fn ensure_serves_public_files(app: axum::Router) { @@ -204,10 +212,18 @@ async fn ensure_serves_public_files(app: axum::Router) { let body_bytes = body::to_bytes(response.into_body(), 2048).await.unwrap(); #[cfg(all(debug_assertions, not(feature = "debug-prod")))] - assert_eq!(body_bytes, "body {\n background-color: black;\n color: white;\n font-family: Arial, sans-serif;\n padding: 42px;\n}\n"); + if cfg!(windows) { + assert_eq!(body_bytes, "body {\r\n background-color: black;\r\n color: white;\r\n font-family: Arial, sans-serif;\r\n padding: 42px;\r\n}\r\n"); + } else { + assert_eq!(body_bytes, "body {\n background-color: black;\n color: white;\n font-family: Arial, sans-serif;\n padding: 42px;\n}\n"); + } #[cfg(not(all(debug_assertions, not(feature = "debug-prod"))))] - assert_eq!(body_bytes, "body {\n background-color: black;\n color: white;\n font-family: Arial, sans-serif;\n padding: 42px;\n}\n"); + if cfg!(windows) { + assert_eq!(body_bytes, "body {\r\n background-color: black;\r\n color: white;\r\n font-family: Arial, sans-serif;\r\n padding: 42px;\r\n}\r\n"); + } else { + assert_eq!(body_bytes, "body {\n background-color: black;\n color: white;\n font-family: Arial, sans-serif;\n padding: 42px;\n}\n"); + } } async fn ensure_serves_imports(app: axum::Router) { diff --git a/crates/vite-rs-dev-server/src/lib.rs b/crates/vite-rs-dev-server/src/lib.rs index 42faeef..1154f85 100644 --- a/crates/vite-rs-dev-server/src/lib.rs +++ b/crates/vite-rs-dev-server/src/lib.rs @@ -105,7 +105,30 @@ pub fn start_dev_server( // println!("Starting dev server!"); // start ViteJS dev server - let child = Arc::new(Mutex::new( + let child = Arc::new(Mutex::new(if cfg!(target_os = "windows") { + std::process::Command::new("cmd") + .arg("/C") + .arg("npx") + .arg("vite") + .arg("--host") + .arg(host) + .arg("--port") + .arg(port.to_string()) + .arg("--strictPort") + .arg("--clearScreen") + .arg("false") + // we don't want to send stdin to the dev server; this also + // hides the "press h + enter to show help" message that the dev server prints + .stdin(std::process::Stdio::null()) + .current_dir( + absolute_root_dir, /*format!( + "{}/examples/basic_usage", + std::env::var("CARGO_MANIFEST_DIR").unwrap() + )*/ + ) + .group_spawn() + .expect("failed to start ViteJS dev server") + } else { std::process::Command::new("npx") .arg("vite") .arg("--host") @@ -125,8 +148,8 @@ pub fn start_dev_server( )*/ ) .group_spawn() - .expect("failed to start ViteJS dev server"), - )); + .expect("failed to start ViteJS dev server") + })); set_dev_server(ViteProcess(child.clone())); #[cfg(feature = "ctrlc")] diff --git a/crates/vite-rs-embed-macro/src/vite/mod.rs b/crates/vite-rs-embed-macro/src/vite/mod.rs index fa8ab89..f077975 100644 --- a/crates/vite-rs-embed-macro/src/vite/mod.rs +++ b/crates/vite-rs-embed-macro/src/vite/mod.rs @@ -17,7 +17,7 @@ pub mod build { .map(|entry| { let path = entry.path(); let path = path.strip_prefix(absolute_output_path).unwrap(); - let path = path.to_str().unwrap().to_string(); + let path = path.to_str().unwrap().replace("\\", "/"); path }) @@ -45,18 +45,35 @@ pub mod build { p.to_str().unwrap().to_string() }; - let vite_build = std::process::Command::new("npx") - .arg("vite") - .arg("build") - .arg("--manifest") // force manifest generation to `.vite/manifest.json` - .arg("--outDir") - .arg(&absolute_output_path) - .current_dir(absolute_root_dir) - .spawn() - .expect("failed to build") - .wait() - .expect("failed to wait for build to complete") - .success(); + let vite_build = if cfg!(target_os = "windows") { + std::process::Command::new("cmd") + .arg("/c") + .arg("npx") + .arg("vite") + .arg("build") + .arg("--manifest") // force manifest generation to `.vite/manifest.json` + .arg("--outDir") + .arg(&absolute_output_path) + .current_dir(absolute_root_dir) + .spawn() + .expect("failed to build") + .wait() + .expect("failed to wait for build to complete") + .success() + } else { + std::process::Command::new("npx") + .arg("vite") + .arg("build") + .arg("--manifest") // force manifest generation to `.vite/manifest.json` + .arg("--outDir") + .arg(&absolute_output_path) + .current_dir(absolute_root_dir) + .spawn() + .expect("failed to build") + .wait() + .expect("failed to wait for build to complete") + .success() + }; if !vite_build { return Err(syn::Error::new( diff --git a/crates/vite-rs/examples/basic_usage.rs b/crates/vite-rs/examples/basic_usage.rs index c6cd877..eb4e4ff 100644 --- a/crates/vite-rs/examples/basic_usage.rs +++ b/crates/vite-rs/examples/basic_usage.rs @@ -74,7 +74,7 @@ fn main() { println!("{}", file_content); - #[cfg(all(debug_assertions, not(feature = "debug-prod")))] + #[cfg(all(debug_assertions, not(feature = "debug-prod"), not(windows)))] assert_eq!( strip_space(file_content), strip_space( @@ -92,6 +92,24 @@ fn main() { ) ); + #[cfg(all(debug_assertions, not(feature = "debug-prod"), windows))] + assert_eq!( + strip_space(file_content), + strip_space( + r#" + const test = (() => { + console.log("This is a test"); + const a = 3; + return a; + })(); + const num = test; + console.log("NUM: ", num); + + //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInBhY2sxLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHRlc3QgPSAoKCkgPT4ge1xyXG4gIGNvbnNvbGUubG9nKCdUaGlzIGlzIGEgdGVzdCcpXHJcblxyXG4gIGNvbnN0IGE6IG51bWJlciA9IDNcclxuXHJcbiAgcmV0dXJuIGFcclxufSkoKVxyXG5cclxuY29uc3QgbnVtID0gdGVzdFxyXG5cclxuY29uc29sZS5sb2coJ05VTTogJywgbnVtKVxyXG4iXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sUUFBUSxNQUFNO0FBQ2xCLFVBQVEsSUFBSSxnQkFBZ0I7QUFFNUIsUUFBTSxJQUFZO0FBRWxCLFNBQU87QUFDVCxHQUFHO0FBRUgsTUFBTSxNQUFNO0FBRVosUUFBUSxJQUFJLFNBQVMsR0FBRzsiLCJuYW1lcyI6W119 + "# + ) + ); + #[cfg(any(not(debug_assertions), feature = "debug-prod"))] assert_eq!( strip_space(file_content), @@ -100,5 +118,5 @@ fn main() { } fn strip_space(s: &str) -> String { - s.trim().replace(" ", "") + s.trim().replace(" ", "").replace('\r', "") } diff --git a/crates/vite-rs/examples/custom_ctrl_c_handler.rs b/crates/vite-rs/examples/custom_ctrl_c_handler.rs index a6fb230..72fda92 100644 --- a/crates/vite-rs/examples/custom_ctrl_c_handler.rs +++ b/crates/vite-rs/examples/custom_ctrl_c_handler.rs @@ -69,5 +69,5 @@ fn main() { } fn strip_space(s: &str) -> String { - s.trim().replace(" ", "") + s.trim().replace(" ", "").replace("\r", "") } diff --git a/crates/vite-rs/examples/vite-project-folder/vite.config.ts b/crates/vite-rs/examples/vite-project-folder/vite.config.ts index 7b43fc0..63a88dd 100644 --- a/crates/vite-rs/examples/vite-project-folder/vite.config.ts +++ b/crates/vite-rs/examples/vite-project-folder/vite.config.ts @@ -1,14 +1,15 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import path from 'path' export default defineConfig({ plugins: [react()], build: { rollupOptions: { - input: ['app/index.html', 'app/pack1.ts'], + input: [path.resolve(__dirname, 'app/index.html'), path.resolve(__dirname, 'app/pack1.ts')], }, manifest: true, // **IMPORTANT**: this is required. - outDir: './dist', // this is the default value + outDir: path.resolve(__dirname, './dist'), }, - publicDir: './public', // this is the default value + publicDir: path.resolve(__dirname, './public'), }) diff --git a/crates/vite-rs/test_projects/recompilation_test/app/vite.config.ts b/crates/vite-rs/test_projects/recompilation_test/app/vite.config.ts index ebfa5da..06ea488 100644 --- a/crates/vite-rs/test_projects/recompilation_test/app/vite.config.ts +++ b/crates/vite-rs/test_projects/recompilation_test/app/vite.config.ts @@ -1,11 +1,10 @@ import { defineConfig } from "vite"; -import path from "path"; import { globSync } from "glob"; export default defineConfig(() => ({ build: { rollupOptions: { - input: globSync(path.resolve(__dirname, "*.txt")), + input: globSync("*.txt"), }, manifest: true, }, diff --git a/crates/vite-rs/tests/normal_usage_test.rs b/crates/vite-rs/tests/normal_usage_test.rs index be1fb12..0b52acc 100644 --- a/crates/vite-rs/tests/normal_usage_test.rs +++ b/crates/vite-rs/tests/normal_usage_test.rs @@ -78,25 +78,49 @@ fn ensure_html_entrypoint() { assert_eq!(file.content_type, "text/html"); #[cfg(all(debug_assertions, not(feature = "debug-prod")))] - assert_eq!(file.content_length, 475); + if cfg!(windows) { + assert_eq!(file.content_length, 489); + } else { + assert_eq!(file.content_length, 475); + } #[cfg(any(not(debug_assertions), feature = "debug-prod"))] - assert_eq!(file.content_length, 470); + if cfg!(windows) { + assert_eq!(file.content_length, 484); + } else { + assert_eq!(file.content_length, 470); + } let content = std::str::from_utf8(&file.bytes).unwrap(); #[cfg(all(debug_assertions, not(feature = "debug-prod")))] - assert_eq!( - content.replace(" ", ""), - "\n\n\n\n\n\n\n\n\nvite-rs\n\n\n\n\n\n\n" - .replace(" ", "") - ); + if cfg!(windows) { + assert_eq!( + content.replace(" ", ""), + "\r\n\r\n\n\n\r\n\r\n\r\n\r\n\r\nvite-rs\r\n\r\n\r\n\r\n\r\n\r\n\r\n" + .replace(" ", "") + ); + } else { + assert_eq!( + content.replace(" ", ""), + "\n\n\n\n\n\n\n\n\nvite-rs\n\n\n\n\n\n\n" + .replace(" ", "") + ); + } #[cfg(any(not(debug_assertions), feature = "debug-prod"))] - assert_eq!( - content.replace(" ", ""), - "\n\n\n\n\n\nvite-rs\n\n\n\n\n\n\n\n" - .replace(" ", "") - ); + if cfg!(windows) { + assert_eq!( + content.replace(" ", ""), + "\r\n\r\n\r\n\r\n\r\r\n\r\nvite-rs\r\n\n\n\r\n\r\n\r\r\n\r\n\r\n" + .replace(" ", "") + ); + } else { + assert_eq!( + content.replace(" ", ""), + "\n\n\n\n\n\nvite-rs\n\n\n\n\n\n\n\n" + .replace(" ", "") + ); + } } fn ensure_ts_entrypoint() { @@ -105,12 +129,21 @@ fn ensure_ts_entrypoint() { #[cfg(all(debug_assertions, not(feature = "debug-prod")))] { - assert_eq!(file.content_type, "text/javascript"); - assert_eq!(file.content_length, 656); - assert_eq!( - content.replace(" ", ""), - "consttest=(()=>{\nconsole.log(\"Thisisatest\");\nconsta=3;\nreturna;\n})();\nconstnum=test;\nconsole.log(\"NUM:\",num);\n\n//#sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInBhY2sxLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHRlc3QgPSAoKCkgPT4ge1xuICBjb25zb2xlLmxvZygnVGhpcyBpcyBhIHRlc3QnKVxuXG4gIGNvbnN0IGE6IG51bWJlciA9IDNcblxuICByZXR1cm4gYVxufSkoKVxuXG5jb25zdCBudW0gPSB0ZXN0XG5cbmNvbnNvbGUubG9nKCdOVU06ICcsIG51bSlcbiJdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxRQUFRLE1BQU07QUFDbEIsVUFBUSxJQUFJLGdCQUFnQjtBQUU1QixRQUFNLElBQVk7QUFFbEIsU0FBTztBQUNULEdBQUc7QUFFSCxNQUFNLE1BQU07QUFFWixRQUFRLElBQUksU0FBUyxHQUFHOyIsIm5hbWVzIjpbXX0=" - ); + if cfg!(windows) { + assert_eq!(file.content_type, "text/javascript"); + assert_eq!(file.content_length, 684); + assert_eq!( + content.replace(" ", ""), + "consttest=(()=>{\nconsole.log(\"Thisisatest\");\nconsta=3;\nreturna;\n})();\nconstnum=test;\nconsole.log(\"NUM:\",num);\n\n//#sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInBhY2sxLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHRlc3QgPSAoKCkgPT4ge1xyXG4gIGNvbnNvbGUubG9nKCdUaGlzIGlzIGEgdGVzdCcpXHJcblxyXG4gIGNvbnN0IGE6IG51bWJlciA9IDNcclxuXHJcbiAgcmV0dXJuIGFcclxufSkoKVxyXG5cclxuY29uc3QgbnVtID0gdGVzdFxyXG5cclxuY29uc29sZS5sb2coJ05VTTogJywgbnVtKVxyXG4iXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sUUFBUSxNQUFNO0FBQ2xCLFVBQVEsSUFBSSxnQkFBZ0I7QUFFNUIsUUFBTSxJQUFZO0FBRWxCLFNBQU87QUFDVCxHQUFHO0FBRUgsTUFBTSxNQUFNO0FBRVosUUFBUSxJQUFJLFNBQVMsR0FBRzsiLCJuYW1lcyI6W119" + ); + } else { + assert_eq!(file.content_type, "text/javascript"); + assert_eq!(file.content_length, 656); + assert_eq!( + content.replace(" ", ""), + "consttest=(()=>{\nconsole.log(\"Thisisatest\");\nconsta=3;\nreturna;\n})();\nconstnum=test;\nconsole.log(\"NUM:\",num);\n\n//#sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInBhY2sxLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHRlc3QgPSAoKCkgPT4ge1xuICBjb25zb2xlLmxvZygnVGhpcyBpcyBhIHRlc3QnKVxuXG4gIGNvbnN0IGE6IG51bWJlciA9IDNcblxuICByZXR1cm4gYVxufSkoKVxuXG5jb25zdCBudW0gPSB0ZXN0XG5cbmNvbnNvbGUubG9nKCdOVU06ICcsIG51bSlcbiJdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxRQUFRLE1BQU07QUFDbEIsVUFBUSxJQUFJLGdCQUFnQjtBQUU1QixRQUFNLElBQVk7QUFFbEIsU0FBTztBQUNULEdBQUc7QUFFSCxNQUFNLE1BQU07QUFFWixRQUFRLElBQUksU0FBUyxHQUFHOyIsIm5hbWVzIjpbXX0=" + ); + } } #[cfg(any(not(debug_assertions), feature = "debug-prod"))] diff --git a/crates/vite-rs/tests/recompilation_test.rs b/crates/vite-rs/tests/recompilation_test.rs index 9e85c47..5e6b7d7 100644 --- a/crates/vite-rs/tests/recompilation_test.rs +++ b/crates/vite-rs/tests/recompilation_test.rs @@ -30,8 +30,10 @@ mod release_tests { add_asset("app/test2.txt", "123"); compile_test_project(); ensure_assets_exist(vec![ - /* "app/test2.txt" -> */ "assets/test2-CajEw_O3.txt", - /* "app/test.txt" -> */ "assets/test-BPR99Ku7.txt", + /* "app/test2.txt" -> */ + "assets/test2-CajEw_O3.txt", + /* "app/test.txt" -> */ + "assets/test-BPR99Ku7.txt", ]); let binary_last_modified_2 = get_compiled_binary_modified_time(); @@ -121,10 +123,15 @@ mod release_tests { // the `crates/vite-rs` directory when running the tests. // // let's make sure this comment is correct by doing this assertion: - assert!(workspace_dir.ends_with("crates/vite-rs")); - - let test_project_path = - PathBuf::from_iter(&[&workspace_dir, "test_projects/recompilation_test"]); + assert!(workspace_dir.ends_with(&format!("crates{}vite-rs", std::path::MAIN_SEPARATOR))); + + let test_project_path = PathBuf::from_iter(&[ + &workspace_dir, + &format!( + "test_projects{}recompilation_test", + std::path::MAIN_SEPARATOR + ), + ]); test_project_path } @@ -143,8 +150,16 @@ mod release_tests { } fn get_binary_asset_list() -> Vec { - let output = std::process::Command::new("./recompilation_test") - .current_dir(test_project_path().join("target/release")) + let executable_name = if cfg!(windows) { + "recompilation_test.exe" + } else { + "recompilation_test" + }; + let base_dir = test_project_path().join("target/release"); + let executable_path = base_dir.join(executable_name); + + let output = std::process::Command::new(executable_path) + .current_dir(base_dir) .output() .expect("Failed to get the list of assets") .stdout; @@ -157,7 +172,14 @@ mod release_tests { } fn get_compiled_binary_modified_time() -> u128 { - let binary_path = test_project_path().join("target/release/recompilation_test"); + let executable_name = if cfg!(windows) { + "recompilation_test.exe" + } else { + "recompilation_test" + }; + let binary_path = test_project_path() + .join("target/release") + .join(executable_name); let modified_time = binary_path .metadata()