Only compress web assets in the CLI (#2329)
* only compress web assets in the CLI * precompressed -> pre-compressed * only enable pre-compression in release builds
This commit is contained in:
1 parent
b147f5a737
commit
a27d4e71ed
13 files changed
+461
-468
No files matched your search
+102
-1
@@ -1,7 +1,13 @@
|
||||
use std::{fs::File, io::Write, path::PathBuf};
|
||||
use brotli::enc::BrotliEncoderParams;
|
||||
use std::path::Path;
|
||||
use std::{ffi::OsString, path::PathBuf};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use std::{fs::File, io::Write};
|
||||
|
||||
use crate::Result;
|
||||
use dioxus_cli_config::CrateConfig;
|
||||
use dioxus_cli_config::Platform;
|
||||
use manganis_cli_support::{AssetManifest, AssetManifestExt};
|
||||
|
||||
pub fn asset_manifest(bin: Option<&str>, crate_config: &CrateConfig) -> AssetManifest {
|
||||
@@ -56,3 +62,98 @@ impl Drop for AssetConfigDropGuard {
|
||||
manganis_cli_support::Config::default().save();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_assets_dir(config: &CrateConfig, platform: Platform) -> anyhow::Result<()> {
|
||||
tracing::info!("Copying public assets to the output directory...");
|
||||
let out_dir = config.out_dir();
|
||||
let asset_dir = config.asset_dir();
|
||||
|
||||
if asset_dir.is_dir() {
|
||||
// Only pre-compress the assets from the web build. Desktop assets are not served, so they don't need to be pre_compressed
|
||||
let pre_compress = platform == Platform::Web && config.should_pre_compress_web_assets();
|
||||
|
||||
copy_dir_to(asset_dir, out_dir, pre_compress)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_dir_to(src_dir: PathBuf, dest_dir: PathBuf, pre_compress: bool) -> std::io::Result<()> {
|
||||
let entries = std::fs::read_dir(&src_dir)?;
|
||||
let mut children: Vec<std::thread::JoinHandle<std::io::Result<()>>> = Vec::new();
|
||||
|
||||
for entry in entries.flatten() {
|
||||
let entry_path = entry.path();
|
||||
let path_relative_to_src = entry_path.strip_prefix(&src_dir).unwrap();
|
||||
let output_file_location = dest_dir.join(path_relative_to_src);
|
||||
children.push(std::thread::spawn(move || {
|
||||
if entry.file_type()?.is_dir() {
|
||||
// If the file is a directory, recursively copy it into the output directory
|
||||
if let Err(err) =
|
||||
copy_dir_to(entry_path.clone(), output_file_location, pre_compress)
|
||||
{
|
||||
tracing::error!(
|
||||
"Failed to pre-compress directory {}: {}",
|
||||
entry_path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Make sure the directory exists
|
||||
std::fs::create_dir_all(output_file_location.parent().unwrap())?;
|
||||
// Copy the file to the output directory
|
||||
std::fs::copy(&entry_path, &output_file_location)?;
|
||||
|
||||
// Then pre-compress the file if needed
|
||||
if pre_compress {
|
||||
if let Err(err) = pre_compress_file(&entry_path.clone()) {
|
||||
tracing::error!(
|
||||
"Failed to pre-compress static assets {}: {}",
|
||||
entry_path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
for child in children {
|
||||
child.join().unwrap()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// pre-compress a file with brotli
|
||||
pub(crate) fn pre_compress_file(path: &Path) -> std::io::Result<()> {
|
||||
let new_extension = match path.extension() {
|
||||
Some(ext) => {
|
||||
if ext.to_string_lossy().to_lowercase().ends_with("br") {
|
||||
return Ok(());
|
||||
}
|
||||
let mut ext = ext.to_os_string();
|
||||
ext.push(".br");
|
||||
ext
|
||||
}
|
||||
None => OsString::from("br"),
|
||||
};
|
||||
let file = std::fs::File::open(path)?;
|
||||
let mut stream = std::io::BufReader::new(file);
|
||||
let output = path.with_extension(new_extension);
|
||||
let mut buffer = std::fs::File::create(output)?;
|
||||
let params = BrotliEncoderParams::default();
|
||||
brotli::BrotliCompress(&mut stream, &mut buffer, ¶ms)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// pre-compress all files in a folder
|
||||
pub(crate) fn pre_compress_folder(path: &Path) -> std::io::Result<()> {
|
||||
let walk_dir = WalkDir::new(path);
|
||||
for entry in walk_dir.into_iter().filter_map(|e| e.ok()) {
|
||||
let entry_path = entry.path();
|
||||
if entry_path.is_file() {
|
||||
pre_compress_file(entry_path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
+21
-76
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
assets::{asset_manifest, create_assets_head, process_assets, AssetConfigDropGuard},
|
||||
assets::{
|
||||
asset_manifest, copy_assets_dir, create_assets_head, pre_compress_folder, process_assets,
|
||||
AssetConfigDropGuard,
|
||||
},
|
||||
error::{Error, Result},
|
||||
tools::Tool,
|
||||
};
|
||||
@@ -85,13 +88,12 @@ pub fn build_web(
|
||||
..
|
||||
} = config;
|
||||
let out_dir = config.out_dir();
|
||||
let asset_dir = config.asset_dir();
|
||||
|
||||
let _guard = AssetConfigDropGuard::new();
|
||||
let _manganis_support = ManganisSupportGuard::default();
|
||||
|
||||
// start to build the assets
|
||||
let ignore_files = build_assets(config)?;
|
||||
build_assets(config)?;
|
||||
|
||||
let t_start = std::time::Instant::now();
|
||||
let _guard = dioxus_cli_config::__private::save_config(config);
|
||||
@@ -156,16 +158,16 @@ pub fn build_web(
|
||||
ExecutableType::Example(name) => cmd.arg("--example").arg(name),
|
||||
};
|
||||
|
||||
let warning_messages = prettier_build(cmd)?;
|
||||
let CargoBuildResult {
|
||||
warnings,
|
||||
output_location,
|
||||
} = prettier_build(cmd)?;
|
||||
let output_location = output_location.context("No output location found")?;
|
||||
|
||||
// [2] Establish the output directory structure
|
||||
let bindgen_outdir = out_dir.join("assets").join("dioxus");
|
||||
|
||||
let input_path = warning_messages
|
||||
.output_location
|
||||
.as_ref()
|
||||
.context("No output location found")?
|
||||
.with_extension("wasm");
|
||||
let input_path = output_location.with_extension("wasm");
|
||||
|
||||
tracing::info!("Running wasm-bindgen");
|
||||
let run_wasm_bindgen = || {
|
||||
@@ -234,6 +236,11 @@ pub fn build_web(
|
||||
tracing::info!("Skipping optimization with wasm-opt, binaryen tool not found.");
|
||||
}
|
||||
|
||||
// If pre-compressing is enabled, we can pre_compress the wasm-bindgen output
|
||||
if config.should_pre_compress_web_assets() {
|
||||
pre_compress_folder(&bindgen_outdir)?;
|
||||
}
|
||||
|
||||
// [5][OPTIONAL] If tailwind is enabled and installed we run it to generate the CSS
|
||||
if dioxus_tools.contains_key("tailwindcss") {
|
||||
let info = dioxus_tools.get("tailwindcss").unwrap();
|
||||
@@ -274,38 +281,7 @@ pub fn build_web(
|
||||
}
|
||||
|
||||
// this code will copy all public file to the output dir
|
||||
let copy_options = fs_extra::dir::CopyOptions {
|
||||
overwrite: true,
|
||||
skip_exist: false,
|
||||
buffer_size: 64000,
|
||||
copy_inside: false,
|
||||
content_only: false,
|
||||
depth: 0,
|
||||
};
|
||||
|
||||
tracing::info!("Copying public assets to the output directory...");
|
||||
if asset_dir.is_dir() {
|
||||
for entry in std::fs::read_dir(config.asset_dir())?.flatten() {
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
std::fs::copy(&path, out_dir.join(path.file_name().unwrap()))?;
|
||||
} else {
|
||||
match fs_extra::dir::copy(&path, &out_dir, ©_options) {
|
||||
Ok(_) => {}
|
||||
Err(_e) => {
|
||||
tracing::warn!("Error copying dir: {}", _e);
|
||||
}
|
||||
}
|
||||
for ignore in &ignore_files {
|
||||
let ignore = ignore.strip_prefix(&config.asset_dir()).unwrap();
|
||||
let ignore = out_dir.join(ignore);
|
||||
if ignore.is_file() {
|
||||
std::fs::remove_file(ignore)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
copy_assets_dir(config, dioxus_cli_config::Platform::Web)?;
|
||||
|
||||
let assets = if !skip_assets {
|
||||
tracing::info!("Processing assets");
|
||||
@@ -317,8 +293,8 @@ pub fn build_web(
|
||||
};
|
||||
|
||||
Ok(BuildResult {
|
||||
warnings: warning_messages.warnings,
|
||||
executable: warning_messages.output_location,
|
||||
warnings,
|
||||
executable: Some(output_location),
|
||||
elapsed_time: t_start.elapsed().as_millis(),
|
||||
assets,
|
||||
})
|
||||
@@ -366,7 +342,7 @@ pub fn build_desktop(
|
||||
tracing::info!("🚅 Running build [Desktop] command...");
|
||||
|
||||
let t_start = std::time::Instant::now();
|
||||
let ignore_files = build_assets(config)?;
|
||||
build_assets(config)?;
|
||||
let _guard = dioxus_cli_config::__private::save_config(config);
|
||||
let _manganis_support = ManganisSupportGuard::default();
|
||||
let _guard = AssetConfigDropGuard::new();
|
||||
@@ -427,38 +403,7 @@ pub fn build_desktop(
|
||||
copy(res_path, &output_path)?;
|
||||
}
|
||||
|
||||
// this code will copy all public file to the output dir
|
||||
if config.asset_dir().is_dir() {
|
||||
let copy_options = fs_extra::dir::CopyOptions {
|
||||
overwrite: true,
|
||||
skip_exist: false,
|
||||
buffer_size: 64000,
|
||||
copy_inside: false,
|
||||
content_only: false,
|
||||
depth: 0,
|
||||
};
|
||||
|
||||
for entry in std::fs::read_dir(config.asset_dir())?.flatten() {
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
std::fs::copy(&path, &config.out_dir().join(path.file_name().unwrap()))?;
|
||||
} else {
|
||||
match fs_extra::dir::copy(&path, &config.out_dir(), ©_options) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
tracing::warn!("Error copying dir: {}", e);
|
||||
}
|
||||
}
|
||||
for ignore in &ignore_files {
|
||||
let ignore = ignore.strip_prefix(&config.asset_dir()).unwrap();
|
||||
let ignore = config.out_dir().join(ignore);
|
||||
if ignore.is_file() {
|
||||
std::fs::remove_file(ignore)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
copy_assets_dir(config, dioxus_cli_config::Platform::Desktop)?;
|
||||
|
||||
let assets = if !skip_assets {
|
||||
tracing::info!("Processing assets");
|
||||
|
||||
@@ -8,10 +8,7 @@ use dioxus_html::HtmlCtx;
|
||||
use dioxus_rsx::hot_reload::*;
|
||||
use fs_extra::dir::CopyOptions;
|
||||
use notify::{RecommendedWatcher, Watcher};
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
use tokio::sync::broadcast::{self};
|
||||
|
||||
mod output;
|
||||
|
||||
@@ -12,7 +12,7 @@ use dioxus_cli_config::CrateConfig;
|
||||
use dioxus_rsx::hot_reload::*;
|
||||
use std::{
|
||||
net::{SocketAddr, UdpSocket},
|
||||
sync::{Arc, Mutex},
|
||||
sync::Arc,
|
||||
};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
|
||||
@@ -112,7 +112,6 @@ mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
use axum::Router;
|
||||
use axum_server::{Handle, Server};
|
||||
|
||||
async fn setup_servers(mut config: WebProxyConfig) -> String {
|
||||
|
||||
@@ -365,7 +365,6 @@ pub fn extract_zip(file: &Path, target: &Path) -> anyhow::Result<()> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user