1use anyhow::Context;
2use manganis::{AssetOptions, CssModuleAssetOptions, FolderAssetOptions};
3use manganis_core::{AssetVariant, CssAssetOptions, ImageAssetOptions, JsAssetOptions};
4use std::path::Path;
5
6use crate::css::{process_css_module, process_scss};
7
8use super::{
9 css::process_css, folder::process_folder, image::process_image, js::process_js,
10 json::process_json,
11};
12
13pub fn process_file_to(
15 options: &AssetOptions,
16 source: &Path,
17 output_path: &Path,
18) -> anyhow::Result<()> {
19 process_file_to_with_options(options, source, output_path, false)
20}
21
22pub(crate) fn process_file_to_with_options(
24 options: &AssetOptions,
25 source: &Path,
26 output_path: &Path,
27 in_folder: bool,
28) -> anyhow::Result<()> {
29 if output_path.exists() && options.hash_suffix() {
33 return Ok(());
34 }
35 if let Some(parent) = output_path.parent() {
36 if !parent.exists() {
37 std::fs::create_dir_all(parent).context("Failed to create directory")?;
38 }
39 }
40
41 let temp_path = output_path.with_file_name(format!(
45 "partial.{}",
46 output_path
47 .file_name()
48 .unwrap_or_default()
49 .to_string_lossy()
50 ));
51 let resolved_options = resolve_asset_options(source, options.variant());
52
53 match &resolved_options {
54 ResolvedAssetType::Css(options) => {
55 process_css(options, source, &temp_path)?;
56 }
57 ResolvedAssetType::CssModule(options) => {
58 process_css_module(options, source, output_path, &temp_path)?;
59 }
60 ResolvedAssetType::Scss(options) => {
61 process_scss(options, source, &temp_path)?;
62 }
63 ResolvedAssetType::Js(options) => {
64 process_js(options, source, &temp_path, !in_folder)?;
65 }
66 ResolvedAssetType::Image(options) => {
67 process_image(options, source, &temp_path)?;
68 }
69 ResolvedAssetType::Json => {
70 process_json(source, &temp_path)?;
71 }
72 ResolvedAssetType::Folder(_) => {
73 process_folder(source, &temp_path)?;
74 }
75 ResolvedAssetType::File => {
76 let source_file = std::fs::File::open(source)?;
77 let mut reader = std::io::BufReader::new(source_file);
78 let output_file = std::fs::File::create(&temp_path)?;
79 let mut writer = std::io::BufWriter::new(output_file);
80 std::io::copy(&mut reader, &mut writer).with_context(|| {
81 format!(
82 "Failed to write file to output location: {}",
83 temp_path.display()
84 )
85 })?;
86 }
87 }
88
89 if output_path.exists() {
91 if output_path.is_file() {
92 std::fs::remove_file(output_path).context("Failed to remove previous output file")?;
93 } else if output_path.is_dir() {
94 std::fs::remove_dir_all(output_path)
95 .context("Failed to remove previous output file")?;
96 }
97 }
98
99 std::fs::rename(temp_path, output_path)
101 .with_context(|| format!("Failed to rename output file to: {}", output_path.display()))?;
102
103 Ok(())
104}
105
106pub(crate) enum ResolvedAssetType {
107 Image(ImageAssetOptions),
109 Css(CssAssetOptions),
111 CssModule(CssModuleAssetOptions),
113 Scss(CssAssetOptions),
115 Js(JsAssetOptions),
117 Json,
119 Folder(FolderAssetOptions),
121 File,
123}
124
125pub(crate) fn resolve_asset_options(source: &Path, options: &AssetVariant) -> ResolvedAssetType {
126 match options {
127 AssetVariant::Image(image) => ResolvedAssetType::Image(*image),
128 AssetVariant::Css(css) => ResolvedAssetType::Css(*css),
129 AssetVariant::CssModule(css) => ResolvedAssetType::CssModule(*css),
130 AssetVariant::Js(js) => ResolvedAssetType::Js(*js),
131 AssetVariant::Folder(folder) => ResolvedAssetType::Folder(*folder),
132 AssetVariant::Unknown => resolve_unknown_asset_options(source),
133 _ => {
134 tracing::warn!("Unknown asset options... you may need to update the Dioxus CLI. Defaulting to a generic file: {:?}", options);
135 resolve_unknown_asset_options(source)
136 }
137 }
138}
139
140fn resolve_unknown_asset_options(source: &Path) -> ResolvedAssetType {
141 match source.extension().map(|e| e.to_string_lossy()).as_deref() {
142 Some("scss" | "sass") => ResolvedAssetType::Scss(CssAssetOptions::default()),
143 Some("css") => ResolvedAssetType::Css(CssAssetOptions::default()),
144 Some("js") => ResolvedAssetType::Js(JsAssetOptions::default()),
145 Some("json") => ResolvedAssetType::Json,
146 Some("jpg" | "jpeg" | "png" | "webp" | "avif") => {
147 ResolvedAssetType::Image(ImageAssetOptions::default())
148 }
149 _ if source.is_dir() => ResolvedAssetType::Folder(FolderAssetOptions::default()),
150 _ => ResolvedAssetType::File,
151 }
152}