|
1 | 1 | //! Source HTML pipelines.
|
2 | 2 |
|
3 |
| -use std::path::PathBuf; |
4 |
| -use std::sync::Arc; |
5 |
| - |
| 3 | +use crate::{ |
| 4 | + config::{RtcBuild, WsProtocol}, |
| 5 | + hooks::{spawn_hooks, wait_hooks}, |
| 6 | + pipelines::{ |
| 7 | + rust::RustApp, Attrs, PipelineStage, TrunkAsset, TrunkAssetPipelineOutput, |
| 8 | + TrunkAssetReference, TRUNK_ID, |
| 9 | + }, |
| 10 | + processing::minify::minify_html, |
| 11 | +}; |
6 | 12 | use anyhow::{ensure, Context, Result};
|
7 | 13 | use futures_util::stream::{FuturesUnordered, StreamExt};
|
8 | 14 | use nipper::Document;
|
| 15 | +use std::path::PathBuf; |
| 16 | +use std::sync::Arc; |
9 | 17 | use tokio::fs;
|
10 | 18 | use tokio::runtime::Handle;
|
11 | 19 | use tokio::sync::mpsc;
|
12 |
| -use tokio::task::JoinHandle; |
13 |
| - |
14 |
| -use crate::config::{RtcBuild, WsProtocol}; |
15 |
| -use crate::hooks::{spawn_hooks, wait_hooks}; |
16 |
| -use crate::pipelines::rust::RustApp; |
17 |
| -use crate::pipelines::{ |
18 |
| - Attrs, PipelineStage, TrunkAsset, TrunkAssetPipelineOutput, TrunkAssetReference, TRUNK_ID, |
19 |
| -}; |
20 |
| -use crate::processing::minify::minify_html; |
| 20 | +use tokio::task::{JoinError, JoinHandle}; |
21 | 21 |
|
22 | 22 | const PUBLIC_URL_MARKER_ATTR: &str = "data-trunk-public-url";
|
23 | 23 | const RELOAD_SCRIPT: &str = include_str!("../autoreload.js");
|
@@ -201,12 +201,45 @@ impl HtmlPipeline {
|
201 | 201 | target_html: &mut Document,
|
202 | 202 | mut pipelines: AssetPipelineHandles,
|
203 | 203 | ) -> Result<()> {
|
204 |
| - while let Some(asset_res) = pipelines.next().await { |
| 204 | + let mut errors = Vec::new(); |
| 205 | + |
| 206 | + /// finalize an asset pipeline with a single result |
| 207 | + async fn finalize( |
| 208 | + asset_res: std::result::Result<Result<TrunkAssetPipelineOutput>, JoinError>, |
| 209 | + target_html: &mut Document, |
| 210 | + ) -> Result<()> { |
205 | 211 | let asset = asset_res
|
206 |
| - .context("failed to await asset finalization")? |
| 212 | + .context("failed to await asset pipeline")? |
207 | 213 | .context("error from asset pipeline")?;
|
208 |
| - asset.finalize(target_html).await?; |
| 214 | + |
| 215 | + asset |
| 216 | + .finalize(target_html) |
| 217 | + .await |
| 218 | + .context("failed to finalize asset pipeline")?; |
| 219 | + |
| 220 | + Ok(()) |
| 221 | + } |
| 222 | + |
| 223 | + // pull all results and store their errors |
| 224 | + while let Some(asset_res) = pipelines.next().await { |
| 225 | + if let Err(err) = finalize(asset_res, target_html).await { |
| 226 | + // store the error, but don't return, so that we can still await all others |
| 227 | + errors.push(err); |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + // now check for errors |
| 232 | + if let Some(first) = errors.pop() { |
| 233 | + // if we have some, fail with the first |
| 234 | + return Err(first.context(format!( |
| 235 | + "HTML build pipeline failed ({} errors), showing first", |
| 236 | + errors.len() + 1 |
| 237 | + ))); |
209 | 238 | }
|
| 239 | + |
| 240 | + // return only once all pipeline steps have completed, so that we don't start a new build |
| 241 | + // while previous pipelines are still running |
| 242 | + |
210 | 243 | Ok(())
|
211 | 244 | }
|
212 | 245 |
|
|
0 commit comments