rspack_style/interceptor/
less_interceptor.rs

1use crate::util::file::path_resolve;
2use serde_json::Value;
3use std::collections::HashMap;
4use std::path::Path;
5use std::process::{Command, Stdio};
6use std::{env, fs};
7
8pub struct LessInterceptor;
9
10impl LessInterceptor {
11  ///
12  /// 复制js-lib
13  /// 检查有文件的话 不进行调用
14  ///
15  fn copy_js_lib(target_dir: &str) {
16    // 清空dir
17    let command = format!("rm -rf {}/**", target_dir);
18    let mut rm_task = Command::new("sh");
19    rm_task.arg("-c").arg(command);
20    rm_task.current_dir(target_dir).status().unwrap();
21    // 拷贝js-lib
22    let js_lib_dir = format!("{}/**", path_resolve("js-lib"));
23    let command = format!("cp -rf {} {}", js_lib_dir, target_dir);
24    let mut cp_task = Command::new("sh");
25    cp_task.arg("-c").arg(command);
26    cp_task.current_dir(target_dir).status().unwrap();
27  }
28
29  ///
30  /// js-lib 文件管理
31  /// 用来支持 less.js cwd require.resolve js-plugin
32  ///
33  fn filemanger() -> Result<String, String> {
34    let cwd = env::current_dir().unwrap();
35    let temp_rspack_style_dir = cwd.join(".rspack-style");
36    let js_main_file = temp_rspack_style_dir.join("dist/main.js");
37
38    return if temp_rspack_style_dir.exists() && temp_rspack_style_dir.is_dir() {
39      if js_main_file.exists() {
40        // 主文件存在 则返回
41        Ok(js_main_file.into_os_string().into_string().unwrap())
42      } else {
43        // 主文件不存在 则 从 自己 js-lib 中进行复制
44        Self::copy_js_lib(temp_rspack_style_dir.to_str().unwrap());
45        Ok(js_main_file.into_os_string().into_string().unwrap())
46      }
47    } else if !temp_rspack_style_dir.exists() {
48      fs::create_dir_all(temp_rspack_style_dir.clone()).unwrap();
49      Self::copy_js_lib(temp_rspack_style_dir.to_str().unwrap());
50      Ok(js_main_file.into_os_string().into_string().unwrap())
51    } else {
52      // maybe .rspack-style is link or file
53      Err(format!(
54        "rspack-style LessInterceptor filemanger call ->  {} must be dir",
55        temp_rspack_style_dir
56          .into_os_string()
57          .into_string()
58          .unwrap()
59      ))
60    };
61  }
62
63  pub fn handle(filepath: &str, content: &str) -> Result<String, String> {
64    let path = Path::new(filepath);
65    if path.extension() == Some("less".to_string().as_ref()) {
66      let self_dir = Path::new(filepath).to_str().unwrap().to_string();
67      let cwd = path_resolve("");
68      let include_path = vec![
69        Value::String(self_dir),
70        Value::String(cwd.clone()),
71        Value::String("node_modules".to_string()),
72      ];
73      let mut option_map = HashMap::new();
74      option_map.insert("paths", Value::Array(include_path));
75      option_map.insert("filename", Value::String(filepath.to_string()));
76      let option_arg = serde_json::to_string(&option_map).unwrap();
77
78      let js_file = Self::filemanger()?;
79      let mut task = Command::new("node");
80      task.arg(js_file.as_str());
81      task.arg("--option");
82      task.arg(option_arg.as_str());
83      task.current_dir(cwd);
84      task.stdout(Stdio::piped());
85
86      // let temp_file_name = temp_file.metadata().unwrap();
87      // let _test_node_content = format!("node {} --content {} --option {}", js_file, content_arg, option_arg);
88
89      let output = task
90        .output()
91        .unwrap_or_else(|_| panic!("{}->less.js callback is failed", filepath));
92      let status = output.status.code().unwrap();
93      let less_content = std::str::from_utf8(&*output.stdout).unwrap().to_string();
94      return if status > 0 {
95        Err(format!(
96          "parse less file ->{} \n has error in interceptor,\n ex is \n {}",
97          filepath, less_content
98        ))
99      } else {
100        Ok(less_content)
101      };
102      // let content = "";
103    }
104    Ok(content.to_string())
105  }
106}