build.rs 2.7 KB

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