oj_compiler 0.0.9

Fused per-file pipeline
Documentation
use std::path::Path;
use std::time::Instant;

use oj_compiler::{compile, set_import_meta_env, CompileOptions};

const SRC: &str = r#"
import { useState, useEffect } from "react";

const API = import.meta.env.VITE_API_URL;
const MODE = import.meta.env.MODE;

interface Props { label: string; count?: number }

export function Widget({ label, count = 0 }: Props) {
  const [n, setN] = useState<number>(count);
  const dev = import.meta.env.DEV;
  useEffect(() => {
    if (dev) console.log("mounted", label, API, MODE);
  }, [label]);
  return (
    <button className="widget" onClick={() => setN((v) => v + 1)} data-api={API}>
      {label}: {n} {dev ? "(dev)" : "(prod)"}
    </button>
  );
}

export function List({ items }: { items: string[] }) {
  return <ul>{items.map((it, i) => <li key={i}><Widget label={it} /></li>)}</ul>;
}
"#;

fn main() {
    set_import_meta_env(vec![
        ("import.meta.env.VITE_API_URL".into(), "\"https://api.example.com\"".into()),
        ("import.meta.env.MODE".into(), "\"development\"".into()),
        ("import.meta.env.DEV".into(), "true".into()),
        (
            "import.meta.env".into(),
            "({\"VITE_API_URL\":\"https://api.example.com\",\"MODE\":\"development\",\"DEV\":true})".into(),
        ),
    ]);

    let opts = CompileOptions::dev();
    let path = Path::new("Widget.tsx");

    let out = compile(path, SRC, &opts).expect("compile");
    assert!(out.code.contains("\"development\""), "define must be replaced");
    assert!(!out.code.contains("import.meta.env"), "no bare import.meta.env left");

    let warmup = 2_000;
    let iters = 40_000;
    for _ in 0..warmup {
        let _ = compile(path, SRC, &opts).unwrap();
    }
    let t = Instant::now();
    for _ in 0..iters {
        let _ = compile(path, SRC, &opts).unwrap();
    }
    let el = t.elapsed();
    println!(
        "{iters} compiles in {el:?}  =  {:.2} us/compile  ({:.0} compiles/sec)",
        el.as_nanos() as f64 / iters as f64 / 1000.0,
        iters as f64 / el.as_secs_f64(),
    );
}