Skip to content

Commit 5011d63

Browse files
ealmloffjkelleyrtp
authored andcommitted
Move asset hashing into the CLI (DioxusLabs#3988)
* Fix deduping assets * hash assets in the linker * fix extracting assets * Fix the hashed asset name * deserialize the asset back from the link section * prevent the read from being inlined * remove some extra logs * Fix liveview routing * Only look for direct dependencies on dioxus features * fix wasm split test * On wasm, create a new object file with the asset information * Fix multiple assets * add a regression test for 3467 * fix image link * fix linker out file * fix linux linker args * add windows linker command * fix linux link args * fix windows target triple * Expose an option to build assets in the linker intercept * Fix the standalone optimizer and document it in the dx help command * include the cli opt version in the hash * fix clippy * fix ssg port * add a safety note to the read_volatile call * move found assets log * fix some merge conflicts * fix build * make most env var for the linker optional * guess the target triple when dx acts as the linker intercept * automatically find the linker for normal builds * use the right linker in wasm mode * fix mac linker * look inside archive files (rlibs) * remove out.txt * fix clippy * fix typo * fix clippy * fix build * fix dx link name in docs * ignore libcompiler_builtins warnings * fix playwright * pass typocheck * fix printing sysroot * Modify final binary * fix wasm assets * remove old link section logic * fix tests * forward manganis export args * fail to evaluate relocatable address * retain all exports in the same pattern as other platforms * Fix adding assets during a wasm hot patch * less nesting and remove logs * fix clippy * log pdb files * read from pdb * print data section contents * print with object * normal windows builds working * fix hot patch windows * clean up logs * fix clippy * clean up assets * use the most recent pdb * fix doc test * fix typo * tiny nits * make bundled a reference instead of a pointer * add helpful comment to impl * match on file format * Fix asset hashing comment --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
1 parent 96967d6 commit 5011d63

File tree

45 files changed

+1171
-759
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1171
-759
lines changed

Cargo.lock

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/asset-resolver/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn serve_asset_from_raw_path(path: &str) -> Result<Response<Vec<u8>>, AssetS
7272
/// - [ ] Linux (rpm)
7373
/// - [ ] Linux (deb)
7474
/// - [ ] Android
75-
#[allow(unused)]
75+
#[allow(unreachable_code)]
7676
fn get_asset_root() -> PathBuf {
7777
let cur_exe = std::env::current_exe().unwrap();
7878

packages/cli-opt/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,6 @@ swc_parallel = { version = "=1.0.1", default-features = false }
6767
swc_timer = { version = "=1.0.0", default-features = false }
6868
swc_visit = { version = "=2.0.0", default-features = false }
6969
browserslist-rs = { version = "=0.16.0" }
70+
71+
[build-dependencies]
72+
built = { version = "0.7.5", features = ["git2"] }

packages/cli-opt/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
built::write_built_file().expect("Failed to acquire build-time information");
3+
}

packages/cli-opt/src/build_info.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// The file has been placed there by the build script.
2+
include!(concat!(env!("OUT_DIR"), "/built.rs"));
3+
4+
pub(crate) fn version() -> String {
5+
format!(
6+
"{} ({})",
7+
PKG_VERSION,
8+
GIT_COMMIT_HASH_SHORT.unwrap_or("was built without git repository")
9+
)
10+
}

packages/cli-opt/src/css.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::Path;
1+
use std::{hash::Hasher, path::Path};
22

33
use anyhow::{anyhow, Context};
44
use codemap::SpanLoc;
@@ -146,12 +146,11 @@ pub(crate) fn minify_css(css: &str) -> anyhow::Result<String> {
146146
Ok(res.code)
147147
}
148148

149-
/// Process an scss/sass file into css.
150-
pub(crate) fn process_scss(
149+
/// Compile scss with grass
150+
pub(crate) fn compile_scss(
151151
scss_options: &CssAssetOptions,
152152
source: &Path,
153-
output_path: &Path,
154-
) -> anyhow::Result<()> {
153+
) -> anyhow::Result<String> {
155154
let style = match scss_options.minified() {
156155
true => OutputStyle::Compressed,
157156
false => OutputStyle::Expanded,
@@ -162,7 +161,18 @@ pub(crate) fn process_scss(
162161
.quiet(false)
163162
.logger(&ScssLogger {});
164163

165-
let css = grass::from_path(source, &options)?;
164+
let css = grass::from_path(source, &options)
165+
.with_context(|| format!("Failed to compile scss file: {}", source.display()))?;
166+
Ok(css)
167+
}
168+
169+
/// Process an scss/sass file into css.
170+
pub(crate) fn process_scss(
171+
scss_options: &CssAssetOptions,
172+
source: &Path,
173+
output_path: &Path,
174+
) -> anyhow::Result<()> {
175+
let css = compile_scss(scss_options, source)?;
166176
let minified = minify_css(&css)?;
167177

168178
std::fs::write(output_path, minified).with_context(|| {
@@ -199,3 +209,19 @@ impl grass::Logger for ScssLogger {
199209
);
200210
}
201211
}
212+
213+
/// Hash the inputs to the scss file
214+
pub(crate) fn hash_scss(
215+
scss_options: &CssAssetOptions,
216+
source: &Path,
217+
hasher: &mut impl Hasher,
218+
) -> anyhow::Result<()> {
219+
// Grass doesn't expose the ast for us to traverse the imports in the file. Instead of parsing scss ourselves
220+
// we just hash the expanded version of the file for now
221+
let css = compile_scss(scss_options, source)?;
222+
223+
// Hash the compiled css
224+
hasher.write(css.as_bytes());
225+
226+
Ok(())
227+
}

packages/cli-opt/src/file.rs

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::Context;
2+
use manganis::{CssModuleAssetOptions, FolderAssetOptions};
23
use manganis_core::{AssetOptions, CssAssetOptions, ImageAssetOptions, JsAssetOptions};
34
use std::path::Path;
45

@@ -33,7 +34,7 @@ pub(crate) fn process_file_to_with_options(
3334
}
3435
if let Some(parent) = output_path.parent() {
3536
if !parent.exists() {
36-
std::fs::create_dir_all(parent)?;
37+
std::fs::create_dir_all(parent).context("Failed to create directory")?;
3738
}
3839
}
3940

@@ -47,63 +48,94 @@ pub(crate) fn process_file_to_with_options(
4748
.unwrap_or_default()
4849
.to_string_lossy()
4950
));
51+
let resolved_options = resolve_asset_options(source, options);
5052

51-
match options {
52-
AssetOptions::Unknown => match source.extension().map(|e| e.to_string_lossy()).as_deref() {
53-
Some("css") => {
54-
process_css(&CssAssetOptions::new(), source, &temp_path)?;
55-
}
56-
Some("scss" | "sass") => {
57-
process_scss(&CssAssetOptions::new(), source, &temp_path)?;
58-
}
59-
Some("js") => {
60-
process_js(&JsAssetOptions::new(), source, &temp_path, !in_folder)?;
61-
}
62-
Some("json") => {
63-
process_json(source, &temp_path)?;
64-
}
65-
Some("jpg" | "jpeg" | "png" | "webp" | "avif") => {
66-
process_image(&ImageAssetOptions::new(), source, &temp_path)?;
67-
}
68-
Some(_) | None => {
69-
if source.is_dir() {
70-
process_folder(source, &temp_path)?;
71-
} else {
72-
let source_file = std::fs::File::open(source)?;
73-
let mut reader = std::io::BufReader::new(source_file);
74-
let output_file = std::fs::File::create(&temp_path)?;
75-
let mut writer = std::io::BufWriter::new(output_file);
76-
std::io::copy(&mut reader, &mut writer).with_context(|| {
77-
format!(
78-
"Failed to write file to output location: {}",
79-
temp_path.display()
80-
)
81-
})?;
82-
}
83-
}
84-
},
85-
AssetOptions::Css(options) => {
53+
match &resolved_options {
54+
ResolvedAssetType::Css(options) => {
8655
process_css(options, source, &temp_path)?;
8756
}
88-
AssetOptions::CssModule(options) => {
57+
ResolvedAssetType::CssModule(options) => {
8958
process_css_module(options, source, output_path, &temp_path)?;
9059
}
91-
AssetOptions::Js(options) => {
60+
ResolvedAssetType::Scss(options) => {
61+
process_scss(options, source, &temp_path)?;
62+
}
63+
ResolvedAssetType::Js(options) => {
9264
process_js(options, source, &temp_path, !in_folder)?;
9365
}
94-
AssetOptions::Image(options) => {
66+
ResolvedAssetType::Image(options) => {
9567
process_image(options, source, &temp_path)?;
9668
}
97-
AssetOptions::Folder(_) => {
69+
ResolvedAssetType::Json => {
70+
process_json(source, &temp_path)?;
71+
}
72+
ResolvedAssetType::Folder(_) => {
9873
process_folder(source, &temp_path)?;
9974
}
100-
_ => {
101-
tracing::warn!("Unknown asset options: {:?}", options);
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+
})?;
10286
}
10387
}
10488

10589
// If everything was successful, rename the temp file to the final output path
106-
std::fs::rename(temp_path, output_path)?;
90+
std::fs::rename(temp_path, output_path).context("Failed to rename output file")?;
10791

10892
Ok(())
10993
}
94+
95+
pub(crate) enum ResolvedAssetType {
96+
/// An image asset
97+
Image(ImageAssetOptions),
98+
/// A css asset
99+
Css(CssAssetOptions),
100+
/// A css module asset
101+
CssModule(CssModuleAssetOptions),
102+
/// A SCSS asset
103+
Scss(CssAssetOptions),
104+
/// A javascript asset
105+
Js(JsAssetOptions),
106+
/// A json asset
107+
Json,
108+
/// A folder asset
109+
Folder(FolderAssetOptions),
110+
/// A generic file
111+
File,
112+
}
113+
114+
pub(crate) fn resolve_asset_options(source: &Path, options: &AssetOptions) -> ResolvedAssetType {
115+
match options {
116+
AssetOptions::Image(image) => ResolvedAssetType::Image(*image),
117+
AssetOptions::Css(css) => ResolvedAssetType::Css(*css),
118+
AssetOptions::CssModule(css) => ResolvedAssetType::CssModule(*css),
119+
AssetOptions::Js(js) => ResolvedAssetType::Js(*js),
120+
AssetOptions::Folder(folder) => ResolvedAssetType::Folder(*folder),
121+
AssetOptions::Unknown => resolve_unknown_asset_options(source),
122+
_ => {
123+
tracing::warn!("Unknown asset options... you may need to update the Dioxus CLI. Defaulting to a generic file: {:?}", options);
124+
resolve_unknown_asset_options(source)
125+
}
126+
}
127+
}
128+
129+
fn resolve_unknown_asset_options(source: &Path) -> ResolvedAssetType {
130+
match source.extension().map(|e| e.to_string_lossy()).as_deref() {
131+
Some("scss" | "sass") => ResolvedAssetType::Scss(CssAssetOptions::new()),
132+
Some("css") => ResolvedAssetType::Css(CssAssetOptions::new()),
133+
Some("js") => ResolvedAssetType::Js(JsAssetOptions::new()),
134+
Some("json") => ResolvedAssetType::Json,
135+
Some("jpg" | "jpeg" | "png" | "webp" | "avif") => {
136+
ResolvedAssetType::Image(ImageAssetOptions::new())
137+
}
138+
_ if source.is_dir() => ResolvedAssetType::Folder(FolderAssetOptions::new()),
139+
_ => ResolvedAssetType::File,
140+
}
141+
}

0 commit comments

Comments
 (0)