Skip to content

Commit

Permalink
Add data-type attribute to rust links
Browse files Browse the repository at this point in the history
This allows web workers to be included in `index.html`. Since this makes the
rust-worker attribute unnecessary it has been removed.
  • Loading branch information
kristoff3r committed Dec 14, 2021
1 parent ecea495 commit 0ff1842
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 83 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe
### added
- Added the `--address` option for `trunk serve`.
- Open autoreload websocket using wss when assets are served over a secure connection.
- Added the `data-type` attribute to Rust assets. Can be set to either `main` (previous behaviour and default) or `worker`, which builds the asset and includes it as a web worker.

### changed
- Bump notify to 5.0.0-pre.13, which fixes [notify-rs/notify#356](https://github.com/notify-rs/notify/issues/356)
Expand Down
10 changes: 3 additions & 7 deletions site/content/assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ This will typically look like: `<link data-trunk rel="{type}" href="{path}" ..ot

# Asset Types
## rust
`rel="rust"`: Trunk will compile the specified Cargo project as the main WASM application. This is optional. If not specified, Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file.
`rel="rust"`: Trunk will compile the specified Cargo project as WASM and load it. This is optional. If not specified, Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file.
- `href`: (optional) the path to the `Cargo.toml` of the Rust project. If a directory is specified, then Trunk will look for the `Cargo.toml` in the given directory. If no value is specified, then Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file.
- `data-bin`: (optional) the name of the binary to compile and use as the main WASM application. If the Cargo project has multiple binaries, this value will be required for proper functionality.
- `data-bin`: (optional) the name of the binary to compile and load. If the Cargo project has multiple binaries, this value will be required for proper functionality.
- `data-type`: (optional) specifies how the binary should be loaded into the project. Can be set to `main` or `worker`. `main` is the default. There can only be one `main` link. For workers a javascript wrapper is created named after the binary name (if provided) or project name, which can be used to load it.
- `data-cargo-features`: (optional) Space or comma separated list of cargo features to activate.
- `data-wasm-opt`: (optional) run wasm-opt with the set optimization level. The possible values are `0`, `1`, `2`, `3`, `4`, `s`, `z` or an _empty value_ for wasm-opt's default. Set this option to `0` to disable wasm-opt explicitly. The values `1-4` are increasingly stronger optimization levels for speed. `s` and `z` (z means more optimization) optimize for binary size instead. Only used in `--release` mode.
- `data-keep-debug`: (optional) instruct `wasm-bindgen` to preserve debug info in the final WASM output, even for `--release` mode. This may conflict with the use of wasm-opt, so to be sure, it is recommended to set `data-wasm-opt="0"` when using this option.
Expand Down Expand Up @@ -43,11 +44,6 @@ This will typically look like: `<link data-trunk rel="{type}" href="{path}" ..ot
## copy-dir
`rel="copy-dir"`: Trunk will recursively copy the directory specified in the `href` attribute to the `dist` dir. This content is copied exactly, no hashing is performed.

## rust-worker
`rel="rust-worker"`: (in-progress) Trunk will compile the specified Rust project as a WASM web worker. The following attributes are required:
- `href`: (optional) the path to the `Cargo.toml` of the Rust project. If a directory is specified, then Trunk will look for the `Cargo.toml` in the given directory. If no value is specified, then Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file.
- `data-bin`: (optional) the name of the binary to compile and use as the web worker. If the Cargo project has multiple binaries, this value will be required for proper functionality.

Trunk is still a young project, and new asset types will be added as we move forward. Keep an eye on [trunk#3](https://github.com/thedodd/trunk/issues/3) for more information on planned asset types, implementation status, and please contribute to the discussion if you think something is missing.

# JS Snippets
Expand Down
11 changes: 8 additions & 3 deletions src/pipelines/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use tokio::task::JoinHandle;

use crate::config::RtcBuild;
use crate::hooks::{spawn_hooks, wait_hooks};
use crate::pipelines::rust_app::RustApp;
use crate::pipelines::rust::RustApp;
use crate::pipelines::{LinkAttrs, PipelineStage, TrunkLink, TrunkLinkPipelineOutput, TRUNK_ID};

const PUBLIC_URL_MARKER_ATTR: &str = "data-trunk-public-url";
Expand Down Expand Up @@ -96,8 +96,13 @@ impl HtmlPipeline {
}

// Ensure we have a Rust app pipeline to spawn.
let rust_app_nodes = target_html.select(r#"link[data-trunk][rel="rust"]"#).length();
ensure!(rust_app_nodes <= 1, r#"only one <link data-trunk rel="rust" .../> may be specified"#);
let rust_app_nodes = target_html
.select(r#"link[data-trunk][rel="rust"][data-type="main"], link[data-trunk][rel="rust"]:not([data-type])"#)
.length();
ensure!(
rust_app_nodes <= 1,
r#"only one <link data-trunk rel="rust" data-type="main" .../> may be specified"#
);
if rust_app_nodes == 0 {
let app = RustApp::new_default(self.cfg.clone(), self.target_html_dir.clone(), self.ignore_chan.clone()).await?;
assets.push(TrunkLink::RustApp(app));
Expand Down
12 changes: 2 additions & 10 deletions src/pipelines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ mod css;
mod html;
mod icon;
mod inline;
mod rust_app;
mod rust_worker;
mod rust;
mod sass;

use std::collections::HashMap;
Expand All @@ -27,8 +26,7 @@ use crate::pipelines::copy_file::{CopyFile, CopyFileOutput};
use crate::pipelines::css::{Css, CssOutput};
use crate::pipelines::icon::{Icon, IconOutput};
use crate::pipelines::inline::{Inline, InlineOutput};
use crate::pipelines::rust_app::{RustApp, RustAppOutput};
use crate::pipelines::rust_worker::{RustWorker, RustWorkerOutput};
use crate::pipelines::rust::{RustApp, RustAppOutput};
use crate::pipelines::sass::{Sass, SassOutput};

pub use html::HtmlPipeline;
Expand Down Expand Up @@ -58,7 +56,6 @@ pub enum TrunkLink {
CopyFile(CopyFile),
CopyDir(CopyDir),
RustApp(RustApp),
RustWorker(RustWorker),
}

impl TrunkLink {
Expand All @@ -77,7 +74,6 @@ impl TrunkLink {
CopyFile::TYPE_COPY_FILE => Self::CopyFile(CopyFile::new(cfg, html_dir, attrs, id).await?),
CopyDir::TYPE_COPY_DIR => Self::CopyDir(CopyDir::new(cfg, html_dir, attrs, id).await?),
RustApp::TYPE_RUST_APP => Self::RustApp(RustApp::new(cfg, html_dir, ignore_chan, attrs, id).await?),
RustWorker::TYPE_RUST_WORKER => Self::RustWorker(RustWorker::new(cfg, html_dir, ignore_chan, attrs, id).await?),
_ => bail!(
r#"unknown <link data-trunk .../> attr value `rel="{}"`; please ensure the value is lowercase and is a supported asset type"#,
rel
Expand All @@ -95,7 +91,6 @@ impl TrunkLink {
TrunkLink::CopyFile(inner) => inner.spawn(),
TrunkLink::CopyDir(inner) => inner.spawn(),
TrunkLink::RustApp(inner) => inner.spawn(),
TrunkLink::RustWorker(inner) => inner.spawn(),
}
}
}
Expand All @@ -109,8 +104,6 @@ pub enum TrunkLinkPipelineOutput {
CopyFile(CopyFileOutput),
CopyDir(CopyDirOutput),
RustApp(RustAppOutput),
#[allow(dead_code)] // TODO: remove this when this pipeline type is implemented.
RustWorker(RustWorkerOutput),
}

impl TrunkLinkPipelineOutput {
Expand All @@ -123,7 +116,6 @@ impl TrunkLinkPipelineOutput {
TrunkLinkPipelineOutput::CopyFile(out) => out.finalize(dom).await,
TrunkLinkPipelineOutput::CopyDir(out) => out.finalize(dom).await,
TrunkLinkPipelineOutput::RustApp(out) => out.finalize(dom).await,
TrunkLinkPipelineOutput::RustWorker(out) => out.finalize(dom).await,
}
}
}
Expand Down
73 changes: 69 additions & 4 deletions src/pipelines/rust_app.rs → src/pipelines/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub struct RustApp {
id: Option<usize>,
/// Runtime config.
cfg: Arc<RtcBuild>,
/// Is this module main or a worker.
type_: RustAppType,
/// Space or comma separated list of cargo features to activate.
cargo_features: Option<String>,
/// All metadata associated with the target Cargo project.
Expand All @@ -44,6 +46,32 @@ pub struct RustApp {
/// An optional optimization setting that enables wasm-opt. Can be nothing, `0` (default), `1`,
/// `2`, `3`, `4`, `s or `z`. Using `0` disables wasm-opt completely.
wasm_opt: WasmOptLevel,
/// Name for the module. Is binary name if given, otherwise it is the name of the cargo project.
name: String,
}

/// Describes how the rust application is used.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RustAppType {
/// Used as the main application.
Main,
/// Used as a web worker.
Worker,
}

impl FromStr for RustAppType {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"main" => Ok(RustAppType::Main),
"worker" => Ok(RustAppType::Worker),
_ => bail!(
r#"unknown `data-type="{}"` value for <link data-trunk rel="rust" .../> attr; please ensure the value is lowercase and is a supported type"#,
s
),
}
}
}

impl RustApp {
Expand Down Expand Up @@ -71,13 +99,18 @@ impl RustApp {
let cargo_features = attrs.get("data-cargo-features").map(|val| val.to_string());
let keep_debug = attrs.contains_key("data-keep-debug");
let no_demangle = attrs.contains_key("data-no-demangle");
let type_ = attrs
.get("data-type")
.and_then(|s| RustAppType::from_str(s).ok())
.unwrap_or(RustAppType::Main);
let wasm_opt = attrs
.get("data-wasm-opt")
.map(|val| val.parse())
.transpose()?
.unwrap_or_else(|| if cfg.release { Default::default() } else { WasmOptLevel::Off });
let manifest = CargoMetadata::new(&manifest_href).await?;
let id = Some(id);
let name = bin.clone().unwrap_or_else(|| manifest.package.name.clone());

Ok(Self {
id,
Expand All @@ -89,12 +122,16 @@ impl RustApp {
keep_debug,
no_demangle,
wasm_opt,
type_,
name,
})
}

pub async fn new_default(cfg: Arc<RtcBuild>, html_dir: Arc<PathBuf>, ignore_chan: Option<mpsc::Sender<PathBuf>>) -> Result<Self> {
let path = html_dir.join("Cargo.toml");
let manifest = CargoMetadata::new(&path).await?;
let name = manifest.package.name.clone();

Ok(Self {
id: None,
cfg,
Expand All @@ -105,6 +142,8 @@ impl RustApp {
keep_debug: false,
no_demangle: false,
wasm_opt: WasmOptLevel::Off,
type_: RustAppType::Main,
name,
})
}

Expand Down Expand Up @@ -195,11 +234,11 @@ impl RustApp {
.context("could not find WASM output after cargo build")?;

// Hash the built wasm app, then use that as the out-name param.
tracing::info!("processing WASM");
tracing::info!("processing WASM for {}", self.name);
let wasm_bytes = fs::read(&wasm)
.await
.context("error reading wasm file for hash generation")?;
let hashed_name = format!("index-{:x}", seahash::hash(&wasm_bytes));
let hashed_name = format!("{}-{:x}", self.name, seahash::hash(&wasm_bytes));
Ok((wasm, hashed_name))
}

Expand All @@ -225,7 +264,11 @@ impl RustApp {
let arg_out_path = format!("--out-dir={}", bindgen_out.display());
let arg_out_name = format!("--out-name={}", &hashed_name);
let target_wasm = wasm.to_string_lossy().to_string();
let mut args = vec!["--target=web", &arg_out_path, &arg_out_name, "--no-typescript", &target_wasm];
let target_type = match self.type_ {
RustAppType::Main => "--target=web",
RustAppType::Worker => "--target=no-modules",
};
let mut args = vec![target_type, &arg_out_path, &arg_out_name, "--no-typescript", &target_wasm];
if self.keep_debug {
args.push("--keep-debug");
}
Expand All @@ -234,7 +277,7 @@ impl RustApp {
}

// Invoke wasm-bindgen.
tracing::info!("calling wasm-bindgen");
tracing::info!("calling wasm-bindgen for {}", self.name);
common::run_command(wasm_bindgen_name, &wasm_bindgen, &args)
.await
.map_err(|err| check_target_not_found_err(err, wasm_bindgen_name))?;
Expand All @@ -243,6 +286,18 @@ impl RustApp {
tracing::info!("copying generated wasm-bindgen artifacts");
let hashed_js_name = format!("{}.js", &hashed_name);
let hashed_wasm_name = format!("{}_bg.wasm", &hashed_name);
if self.type_ == RustAppType::Worker {
let worker_wrapper_path = self.cfg.staging_dist.join(format!("{}.js", self.name));
let worker_wrapper = format!(
"importScripts('{base}{js}');wasm_bindgen('{base}{wasm}');",
base = self.cfg.public_url,
js = hashed_js_name,
wasm = hashed_wasm_name
);
fs::write(worker_wrapper_path, worker_wrapper)
.await
.context("error writing worker wrapper")?;
}
let js_loader_path = bindgen_out.join(&hashed_js_name);
let js_loader_path_dist = self.cfg.staging_dist.join(&hashed_js_name);
let wasm_path = bindgen_out.join(&hashed_wasm_name);
Expand All @@ -267,6 +322,7 @@ impl RustApp {
cfg: self.cfg.clone(),
js_output: hashed_js_name,
wasm_output: hashed_wasm_name,
type_: self.type_,
})
}

Expand Down Expand Up @@ -366,6 +422,8 @@ pub struct RustAppOutput {
pub js_output: String,
/// The filename of the generated WASM file written to the dist dir.
pub wasm_output: String,
/// Is this module main or a worker.
pub type_: RustAppType,
}

pub fn pattern_evaluate(template: &str, params: &HashMap<String, String>) -> String {
Expand All @@ -385,6 +443,13 @@ pub fn pattern_evaluate(template: &str, params: &HashMap<String, String>) -> Str

impl RustAppOutput {
pub async fn finalize(self, dom: &mut Document) -> Result<()> {
if self.type_ == RustAppType::Worker {
if let Some(id) = self.id {
dom.select(&super::trunk_id_selector(id)).remove();
}
return Ok(());
}

let (base, js, wasm, head, body) = (&self.cfg.public_url, &self.js_output, &self.wasm_output, "html head", "html body");
let (pattern_script, pattern_preload) = (&self.cfg.pattern_script, &self.cfg.pattern_preload);
let mut params: HashMap<String, String> = match &self.cfg.pattern_params {
Expand Down
59 changes: 0 additions & 59 deletions src/pipelines/rust_worker.rs

This file was deleted.

0 comments on commit 0ff1842

Please sign in to comment.