diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6a9073fb..836f9b1e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -74,7 +74,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ ubuntu-latest, macos-latest, windows-latest ] include: - os: ubuntu-latest binPath: target/debug/trunk @@ -119,13 +119,14 @@ jobs: fail-fast: false max-parallel: 32 matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ ubuntu-latest, macos-latest, windows-latest ] example: - cdylib - initializer - no-rust - proxy - seed + - target-path - vanilla - webworker - webworker-gloo diff --git a/examples/target-path/Cargo.lock b/examples/target-path/Cargo.lock new file mode 100644 index 00000000..bee0f64c --- /dev/null +++ b/examples/target-path/Cargo.lock @@ -0,0 +1,154 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "vanilla-example" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/examples/target-path/Cargo.toml b/examples/target-path/Cargo.toml new file mode 100644 index 00000000..70bd6d6a --- /dev/null +++ b/examples/target-path/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "vanilla-example" +version = "0.1.0" +authors = ["Jens Reimann "] +edition = "2021" + +[dependencies] +console_error_panic_hook = "0.1" +wasm-bindgen = "0.2" +web-sys = { version = "0.3", features = ["Window", "Document", "HtmlElement", "Node", "Text"] } diff --git a/examples/target-path/README.md b/examples/target-path/README.md new file mode 100644 index 00000000..131b8231 --- /dev/null +++ b/examples/target-path/README.md @@ -0,0 +1,7 @@ +Trunk | target-dirs +========================= +An example application demonstrating create a more complex target directory structure in the dist folder, based on +the vanilla example. + +Once you've installed Trunk, simply execute `trunk serve --open` from this example's directory, and you should see the +web application rendered in your browser. diff --git a/examples/target-path/Trunk.toml b/examples/target-path/Trunk.toml new file mode 100644 index 00000000..842cc2f7 --- /dev/null +++ b/examples/target-path/Trunk.toml @@ -0,0 +1,3 @@ +[build] +target = "index.html" +dist = "dist" diff --git a/examples/target-path/assets/rustacean-flat-happy.png b/examples/target-path/assets/rustacean-flat-happy.png new file mode 100644 index 00000000..ebce1a14 Binary files /dev/null and b/examples/target-path/assets/rustacean-flat-happy.png differ diff --git a/examples/target-path/index.html b/examples/target-path/index.html new file mode 100644 index 00000000..fe2ce304 --- /dev/null +++ b/examples/target-path/index.html @@ -0,0 +1,45 @@ + + + + + + Trunk | target-path + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestOutcomeExpected
copy-dirShould see PNG image
copy-fileShould see SVG image
+ + + + diff --git a/examples/target-path/more-assets/rustacean-flat-happy.svg b/examples/target-path/more-assets/rustacean-flat-happy.svg new file mode 100644 index 00000000..c7f240dd --- /dev/null +++ b/examples/target-path/more-assets/rustacean-flat-happy.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/target-path/src/app.css b/examples/target-path/src/app.css new file mode 100644 index 00000000..2d91681f --- /dev/null +++ b/examples/target-path/src/app.css @@ -0,0 +1 @@ +body {} \ No newline at end of file diff --git a/examples/target-path/src/index.scss b/examples/target-path/src/index.scss new file mode 100644 index 00000000..820afe56 --- /dev/null +++ b/examples/target-path/src/index.scss @@ -0,0 +1,9 @@ +@charset "utf-8"; + +html { + body { + font-size: 20pt; + color: #111; + font-family: sans-serif; + } +} diff --git a/examples/target-path/src/main.rs b/examples/target-path/src/main.rs new file mode 100644 index 00000000..dcfb8a2a --- /dev/null +++ b/examples/target-path/src/main.rs @@ -0,0 +1,26 @@ +#![recursion_limit = "1024"] + +use console_error_panic_hook::set_once as set_panic_hook; +use wasm_bindgen::prelude::*; +use web_sys::window; + +fn start_app() { + let document = window() + .and_then(|win| win.document()) + .expect("Could not access document"); + let body = document.body().expect("Could not access document.body"); + let text_node = document.create_text_node("Hello, world from Vanilla Rust!"); + body.append_child(text_node.as_ref()) + .expect("Failed to append text"); +} + +#[wasm_bindgen(inline_js = "export function snippetTest() { console.log('Hello from JS FFI!'); }")] +extern "C" { + fn snippetTest(); +} + +fn main() { + set_panic_hook(); + snippetTest(); + start_app(); +} diff --git a/examples/target-path/src/not_minified.css b/examples/target-path/src/not_minified.css new file mode 100644 index 00000000..a3122f19 --- /dev/null +++ b/examples/target-path/src/not_minified.css @@ -0,0 +1,4 @@ +.should_not_be_minified:checked:hover { + --empty-prop: ; + background-color: black; +} diff --git a/examples/target-path/src/script.js b/examples/target-path/src/script.js new file mode 100644 index 00000000..9c14e3a8 --- /dev/null +++ b/examples/target-path/src/script.js @@ -0,0 +1,3 @@ +function testFromJavaScript() { + console.log("Hello from JavaScript"); +} \ No newline at end of file diff --git a/examples/target-path/src/script.mjs b/examples/target-path/src/script.mjs new file mode 100644 index 00000000..31ffb3ca --- /dev/null +++ b/examples/target-path/src/script.mjs @@ -0,0 +1,5 @@ +function testFromJavaScriptModule() { + console.log("Hello from JavaScript Module"); +} + +testFromJavaScriptModule(); diff --git a/site/content/assets.md b/site/content/assets.md index d557336a..f40ed4b8 100644 --- a/site/content/assets.md +++ b/site/content/assets.md @@ -82,6 +82,8 @@ This will typically look like: ` anyhow::E _ => err, } } + +/// Create a target path from a base and an optional relative prefix. +/// +/// This is intended for cases where a subdirectory for a target base (like `dist`) is being +/// composed. The target directory will also be created. +pub async fn target_path( + base: &Path, + target_path: Option<&Path>, + default: Option<&OsStr>, +) -> Result { + if let Some(path) = target_path { + if path.is_absolute() || path.components().any(|c| matches!(c, Component::ParentDir)) { + bail!( + "Invalid data-target-path '{}'. Must be a relative path without '..'.", + path.display() + ); + } + let dir_out = base.join(path); + tokio::fs::create_dir_all(&dir_out).await?; + Ok(dir_out) + } else if let Some(default) = default { + Ok(base.join(default)) + } else { + Ok(base.to_owned()) + } +} diff --git a/src/pipelines/copy_dir.rs b/src/pipelines/copy_dir.rs index 2279381c..93e6105e 100644 --- a/src/pipelines/copy_dir.rs +++ b/src/pipelines/copy_dir.rs @@ -1,6 +1,6 @@ //! Copy-dir asset pipeline. -use std::path::{Component, PathBuf}; +use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; @@ -9,7 +9,7 @@ use tokio::fs; use tokio::task::JoinHandle; use super::{Attrs, TrunkAssetPipelineOutput, ATTR_HREF}; -use crate::common::copy_dir_recursive; +use crate::common::{copy_dir_recursive, target_path}; use crate::config::RtcBuild; /// A CopyDir asset pipeline. @@ -74,19 +74,12 @@ impl CopyDir { format!("could not get directory name of dir {:?}", &canonical_path) })?; - let dir_out = if let Some(path) = self.target_path { - if path.is_absolute() || path.components().any(|c| matches!(c, Component::ParentDir)) { - anyhow::bail!( - "Invalid data-target-path '{}'. Must be a relative path without '..'.", - path.display() - ); - } - let dir_out = self.cfg.staging_dist.join(&path); - tokio::fs::create_dir_all(&dir_out).await?; - dir_out - } else { - self.cfg.staging_dist.join(dir_name) - }; + let dir_out = target_path( + &self.cfg.staging_dist, + self.target_path.as_deref(), + Some(dir_name), + ) + .await?; copy_dir_recursive(canonical_path, dir_out).await?; tracing::debug!(path = ?rel_path, "finished copying directory"); diff --git a/src/pipelines/copy_file.rs b/src/pipelines/copy_file.rs index 50ffa41c..32a6b91e 100644 --- a/src/pipelines/copy_file.rs +++ b/src/pipelines/copy_file.rs @@ -1,10 +1,10 @@ //! Copy-file asset pipeline. -use std::path::PathBuf; -use std::sync::Arc; - +use crate::common::target_path; use anyhow::{Context, Result}; use nipper::Document; +use std::path::PathBuf; +use std::sync::Arc; use tokio::task::JoinHandle; use crate::config::RtcBuild; @@ -18,6 +18,8 @@ pub struct CopyFile { cfg: Arc, /// The asset file being processed. asset: AssetFile, + /// Optional target path inside the dist dir. + target_path: Option, } impl CopyFile { @@ -36,7 +38,18 @@ impl CopyFile { let mut path = PathBuf::new(); path.extend(href_attr.split('/')); let asset = AssetFile::new(&html_dir, path).await?; - Ok(Self { id, cfg, asset }) + + let target_path = attrs + .get("data-target-path") + .map(|val| val.parse()) + .transpose()?; + + Ok(Self { + id, + cfg, + asset, + target_path, + }) } /// Spawn the pipeline for this asset type. @@ -50,11 +63,16 @@ impl CopyFile { async fn run(self) -> Result { let rel_path = crate::common::strip_prefix(&self.asset.path); tracing::debug!(path = ?rel_path, "copying file"); + + let dir_out = + target_path(&self.cfg.staging_dist, self.target_path.as_deref(), None).await?; + let _ = self .asset - .copy(&self.cfg.staging_dist, false, false, AssetFileType::Other) + .copy(&dir_out, false, false, AssetFileType::Other) .await?; tracing::debug!(path = ?rel_path, "finished copying file"); + Ok(TrunkAssetPipelineOutput::CopyFile(CopyFileOutput(self.id))) } }