1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::path::PathBuf;

use crate::commons::models::IndexModel;

use super::{
    build_opts::BuildOpts,
    cargo_build::run_cargo_build,
    cargo_workspace::{get_workspace, Workspace},
    wasm_opt::run_wasm_opt,
    wasm_path::WasmPath,
    check_env::check_env,
    find_target::{find_package_rlib_in_target, find_wasm_in_target},
};

pub fn run(opts: BuildOpts) -> Result<(), i32> {
    let ws = get_workspace().expect("Can't read workspace");

    run_with_ws(opts, &ws)
}

pub fn run_with_ws(opts: BuildOpts, ws: &Workspace) -> Result<(), i32> {
    let package_name = match opts.inner.package_name.as_deref() {
        Some(name) => name.to_string(),
        None => match ws.infer_package_name() {
            Some(name) => {
                log::info!("Inferred package name = {}", name);
                name
            }
            None => {
                log::error!(
                    "Can't find vertigo project in {} (no cdylib member)",
                    ws.get_root_dir()
                );
                return Err(-1);
            }
        },
    };

    check_env()?;

    let dest_dir = WasmPath::new(PathBuf::from(&opts.common.dest_dir));

    // Clean destination

    dest_dir.remove_dir_all();
    dest_dir.create_dir_all();

    // Delete rlibs to re-generate static files

    find_package_rlib_in_target(&package_name).remove_file();

    // Run build

    let target_path = match run_cargo_build(&package_name, &opts.inner.public_path, ws) {
        Ok(path) => path,
        Err(_) => return Err(-2),
    };

    // Get wasm_run.js and index.template.html from vertigo build

    let vertigo_statics_dir = target_path.join("static");

    let run_script_content = std::fs::read(vertigo_statics_dir.join("wasm_run.js"))
        .expect("No wasm_run in statics directory");

    let run_script_hash_name = opts
        .new_path_in_static_make(&["wasm_run.js"])
        .save_with_hash(&run_script_content);

    if opts.inner.wasm_run_source_map {
        let run_script_sourcemap_content = std::fs::read_to_string(vertigo_statics_dir.join("wasm_run.js.map"))
            .expect("No wasm_run sourcemap in statics directory")
            // Replace original script filename in sourcemap with the hashed one
            .replace("wasm_run.js", &run_script_hash_name);

        opts
            .new_path_in_static_make(&["wasm_run.js.map"])
            .save(&run_script_sourcemap_content.into_bytes());
    }

    // Copy .wasm to destination

    let wasm_path_target = find_wasm_in_target(&package_name);
    let wasm_path = opts.new_path_in_static_from(&wasm_path_target);

    // Optimize .wasm

    let wasm_path_hash =
        if !opts.inner.disable_wasm_opt && run_wasm_opt(&wasm_path_target, &wasm_path) {
            // optimized
            let wasm_path_hash = wasm_path.save_with_hash(wasm_path.read().as_slice());
            wasm_path.remove_file();
            wasm_path_hash
        } else {
            // copy without optimization
            let wasm_content = wasm_path_target.read();
            wasm_path.save_with_hash(wasm_content.as_slice())
        };

    // Generate index.json in destination

    let index = IndexModel {
        run_js: opts.public_path_to(run_script_hash_name),
        wasm: opts.public_path_to(wasm_path_hash),
    };

    let index_content = serde_json::to_string_pretty(&index).unwrap();
    opts.new_path_in_static_make(&["index.json"])
        .save(index_content.as_bytes());

    // Copy statics generated by dom macro invocations

    if let Ok(dir) = std::fs::read_dir(vertigo_statics_dir.join("included")) {
        dir.for_each(|entry| {
            if let Ok(entry) = entry {
                let src_file_path = WasmPath::new(entry.path());
                let content = src_file_path.read();
                let dest_file_path = opts.new_path_in_static_from(&src_file_path);
                dest_file_path.save(&content);
            }
        });
    }

    Ok(())
}