vertigo_cli/build/
build_run.rs

1use std::path::PathBuf;
2
3use crate::commons::{models::IndexModel, ErrorCode};
4
5use super::{
6    build_opts::BuildOpts,
7    cargo_build::run_cargo_build,
8    cargo_workspace::{get_workspace, Workspace},
9    check_env::check_env,
10    find_target::{find_package_rlib_in_target, find_wasm_in_target},
11    wasm_opt::run_wasm_opt,
12    wasm_path::WasmPath,
13};
14
15pub fn run(opts: BuildOpts) -> Result<(), ErrorCode> {
16    let ws = match get_workspace() {
17        Ok(ws) => ws,
18        Err(err) => {
19            log::error!("Can't read workspace");
20            return Err(err);
21        }
22    };
23
24    run_with_ws(opts, &ws, false)
25}
26
27pub fn run_with_ws(opts: BuildOpts, ws: &Workspace, allow_error: bool) -> Result<(), ErrorCode> {
28    let package_name = match opts.inner.package_name.as_deref() {
29        Some(name) => name.to_string(),
30        None => match ws.infer_package_name() {
31            Some(name) => {
32                log::info!("Inferred package name = {name}");
33                name
34            }
35            None => {
36                log::error!(
37                    "Can't find vertigo project in {} (no cdylib member)",
38                    ws.get_root_dir()
39                );
40                return Err(ErrorCode::CantFindCdylibMember);
41            }
42        },
43    };
44
45    check_env()?;
46
47    let dest_dir = WasmPath::new(PathBuf::from(&opts.common.dest_dir));
48
49    // Clean destination
50
51    dest_dir.remove_dir_all();
52    dest_dir.create_dir_all();
53
54    // Delete rlibs to re-generate static files
55
56    find_package_rlib_in_target(&package_name).remove_file();
57
58    // Run build
59
60    let target_path =
61        match run_cargo_build(&package_name, &opts.get_public_path(), ws, allow_error)? {
62            Ok(path) => path,
63            Err(_) => return Err(ErrorCode::BuildFailed),
64        };
65
66    // Get wasm_run.js and index.template.html from vertigo build
67
68    let vertigo_statics_dir = target_path.join("static");
69
70    let run_script_content = match std::fs::read(vertigo_statics_dir.join("wasm_run.js")) {
71        Ok(content) => content,
72        Err(err) => {
73            log::error!("Can't read wasm_run from statics directory: {err}");
74            return Err(ErrorCode::CantReadWasmRunFromStatics);
75        }
76    };
77
78    let run_script_hash_name = opts
79        .new_path_in_static_make(&["wasm_run.js"])
80        .save_with_hash(&run_script_content);
81
82    if opts.inner.wasm_run_source_map {
83        let run_script_sourcemap_content =
84            match std::fs::read_to_string(vertigo_statics_dir.join("wasm_run.js.map")) {
85                Ok(content) => {
86                    // Replace original script filename in sourcemap with the hashed one
87                    content.replace("wasm_run.js", &run_script_hash_name)
88                }
89                Err(err) => {
90                    log::error!("Can't read wasm_run sourcemap from statics directory: {err}");
91                    return Err(ErrorCode::CantReadWasmRunSourcemapFromStatics);
92                }
93            };
94
95        opts.new_path_in_static_make(&["wasm_run.js.map"])
96            .save(&run_script_sourcemap_content.into_bytes());
97    }
98
99    // Copy .wasm to destination
100
101    let wasm_path_target = find_wasm_in_target(&package_name);
102    let wasm_path = opts.new_path_in_static_from(&wasm_path_target);
103
104    // Optimize .wasm
105
106    let wasm_path_hash =
107        if !opts.inner.disable_wasm_opt && run_wasm_opt(&wasm_path_target, &wasm_path) {
108            // optimized
109            let wasm_path_hash = wasm_path.save_with_hash(wasm_path.read().as_slice());
110            wasm_path.remove_file();
111            wasm_path_hash
112        } else {
113            // copy without optimization
114            let wasm_content = wasm_path_target.read();
115            wasm_path.save_with_hash(wasm_content.as_slice())
116        };
117
118    // Generate index.json in destination
119
120    let index = IndexModel {
121        run_js: opts.public_path_to(run_script_hash_name),
122        wasm: opts.public_path_to(wasm_path_hash),
123    };
124
125    let index_content = serde_json::to_string_pretty(&index).unwrap();
126    opts.new_path_in_static_make(&["index.json"])
127        .save(index_content.as_bytes());
128
129    // Copy statics generated by dom macro invocations
130
131    if let Ok(dir) = std::fs::read_dir(vertigo_statics_dir.join("included")) {
132        dir.for_each(|entry| {
133            if let Ok(entry) = entry {
134                let src_file_path = WasmPath::new(entry.path());
135                let content = src_file_path.read();
136                let dest_file_path = opts.new_path_in_static_from(&src_file_path);
137                dest_file_path.save(&content);
138            }
139        });
140    }
141
142    Ok(())
143}