build.rs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. use std::{
  2. fs::read_to_string,
  3. hash::{DefaultHasher, Hash, Hasher},
  4. process::Command,
  5. };
  6. fn main() {
  7. // If any TS changes, re-run the build script
  8. println!("cargo:rerun-if-changed=src/ts/*.ts");
  9. // Compute the hash of the ts files
  10. let hash = hash_dir("./src/ts");
  11. // If the hash matches the one on disk, we're good and don't need to update bindings
  12. if let Ok(contents) = read_to_string("./src/js/hash.txt") {
  13. if contents.trim() == hash.to_string() {
  14. return;
  15. }
  16. }
  17. // Otherwise, generate the bindings and write the new hash to disk
  18. // Generate the bindings for both native and web
  19. gen_bindings("common", "common");
  20. gen_bindings("native", "native");
  21. gen_bindings("core", "core");
  22. std::fs::write("src/js/hash.txt", hash.to_string()).unwrap();
  23. }
  24. /// Hashes the contents of a directory
  25. fn hash_dir(dir: &str) -> u64 {
  26. let mut hasher = DefaultHasher::new();
  27. for entry in std::fs::read_dir(dir).unwrap() {
  28. let entry = entry.unwrap();
  29. let path = entry.path();
  30. let Some(ext) = path.extension() else {
  31. continue;
  32. };
  33. if ext != "ts" {
  34. continue;
  35. }
  36. let contents = std::fs::read(&path).unwrap();
  37. contents.hash(&mut hasher);
  38. }
  39. hasher.finish()
  40. }
  41. // okay...... so tsc might fail if the user doesn't have it installed
  42. // we don't really want to fail if that's the case
  43. // but if you started *editing* the .ts files, you're gonna have a bad time
  44. // so.....
  45. // we need to hash each of the .ts files and add that hash to the JS files
  46. // if the hashes don't match, we need to fail the build
  47. // that way we also don't need
  48. fn gen_bindings(input_name: &str, output_name: &str) {
  49. // If the file is generated, and the hash is different, we need to generate it
  50. let status = Command::new("bun")
  51. .arg("build")
  52. .arg(format!("src/ts/{input_name}.ts"))
  53. .arg("--outfile")
  54. .arg(format!("src/js/{output_name}.js"))
  55. .arg("--minify-whitespace")
  56. .arg("--minify-syntax")
  57. .status()
  58. .unwrap();
  59. if !status.success() {
  60. panic!(
  61. "Failed to generate bindings for {}. Make sure you have tsc installed",
  62. input_name
  63. );
  64. }
  65. }