Skip to content

Commit

Permalink
improve error handling (#4779)
Browse files Browse the repository at this point in the history
### Description

[return fallback metadata when image processing
fails](31c1557)
[improve error reporting for ecmascript parsing
errors](813852a)

### Testing Instructions

see vercel/next.js#49093

---------

Co-authored-by: Alex Kirszenberg <alex.kirszenberg@vercel.com>
  • Loading branch information
sokra and alexkirsz committed May 2, 2023
1 parent d8ae01e commit ac765e7
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 8 deletions.
83 changes: 80 additions & 3 deletions crates/turbopack-ecmascript/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use turbo_tasks_fs::{FileContent, FileSystemPath, FileSystemPathVc};
use turbo_tasks_hash::hash_xxh3_hash64;
use turbopack_core::{
asset::{Asset, AssetContent, AssetVc},
error::PrettyPrintError,
issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc},
source_map::{GenerateSourceMap, GenerateSourceMapVc, OptionSourceMapVc},
SOURCE_MAP_ROOT_NAME,
};
Expand Down Expand Up @@ -140,14 +142,41 @@ pub async fn parse(
source: AssetVc,
ty: Value<EcmascriptModuleAssetType>,
transforms: EcmascriptInputTransformsVc,
) -> Result<ParseResultVc> {
match parse_internal(source, ty, transforms).await {
Ok(result) => Ok(result),
Err(error) => Err(error.context(format!(
"failed to parse {}",
source.ident().to_string().await?
))),
}
}

async fn parse_internal(
source: AssetVc,
ty: Value<EcmascriptModuleAssetType>,
transforms: EcmascriptInputTransformsVc,
) -> Result<ParseResultVc> {
let content = source.content();
let fs_path_vc = source.ident().path();
let fs_path = &*fs_path_vc.await?;
let ident = &*source.ident().to_string().await?;
let file_path_hash = *hash_ident(source.ident().to_string()).await? as u128;
let ty = ty.into_value();
Ok(match &*content.await? {
let content = match content.await {
Ok(content) => content,
Err(error) => {
ReadSourceIssue {
source,
error: PrettyPrintError(&error).to_string(),
}
.cell()
.as_issue()
.emit();
return Ok(ParseResult::Unparseable.cell());
}
};
Ok(match &*content {
AssetContent::File(file) => match &*file.await? {
FileContent::NotFound => ParseResult::NotFound.cell(),
FileContent::Content(file) => match file.content().to_str() {
Expand All @@ -174,8 +203,16 @@ pub async fn parse(
}
}
}
// FIXME: report error
Err(_) => ParseResult::Unparseable.cell(),
Err(error) => {
ReadSourceIssue {
source,
error: PrettyPrintError(&error).to_string(),
}
.cell()
.as_issue()
.emit();
ParseResult::Unparseable.cell()
}
},
},
AssetContent::Redirect { .. } => ParseResult::Unparseable.cell(),
Expand Down Expand Up @@ -339,3 +376,43 @@ async fn hash_ident(ident: StringVc) -> Result<U64Vc> {
let ident = &*ident.await?;
Ok(U64Vc::cell(hash_xxh3_hash64(ident)))
}

#[turbo_tasks::value]
struct ReadSourceIssue {
source: AssetVc,
error: String,
}

#[turbo_tasks::value_impl]
impl Issue for ReadSourceIssue {
#[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc {
self.source.ident().path()
}

#[turbo_tasks::function]
fn title(&self) -> StringVc {
StringVc::cell("Reading source code for parsing failed".to_string())
}

#[turbo_tasks::function]
fn description(&self) -> StringVc {
StringVc::cell(
format!(
"An unexpected error happened while trying to read the source code to parse: {}",
self.error
)
.into(),
)
}

#[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc {
IssueSeverity::Error.cell()
}

#[turbo_tasks::function]
fn category(&self) -> StringVc {
StringVc::cell("parse".to_string())
}
}
45 changes: 40 additions & 5 deletions crates/turbopack-image/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ pub struct BlurPlaceholder {
pub height: u32,
}

impl BlurPlaceholder {
pub fn fallback() -> Self {
BlurPlaceholder {
data_url: "data:image/gif;base64,R0lGODlhAQABAIAAAP///\
wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
.to_string(),
width: 1,
height: 1,
}
}
}

/// Gathered meta information about an image.
#[serde_as]
#[turbo_tasks::value]
Expand All @@ -47,6 +59,18 @@ pub struct ImageMetaData {
placeholder_for_future_extensions: (),
}

impl ImageMetaData {
pub fn fallback_value(mime_type: Option<Mime>) -> Self {
ImageMetaData {
width: 100,
height: 100,
mime_type,
blur_placeholder: Some(BlurPlaceholder::fallback()),
placeholder_for_future_extensions: (),
}
}
}

/// Options for generating a blur placeholder.
#[turbo_tasks::value(shared)]
pub struct BlurPlaceholderOptions {
Expand Down Expand Up @@ -138,7 +162,7 @@ fn compute_blur_data(
.cell()
.as_issue()
.emit();
None
Some(BlurPlaceholder::fallback())
}
}
}
Expand Down Expand Up @@ -253,9 +277,20 @@ pub async fn get_meta_data(
let path = ident.path().await?;
let extension = path.extension();
if extension == Some("svg") {
let content = std::str::from_utf8(&bytes).context("Input image is not valid utf-8")?;
let (width, height) =
calculate(content).context("Failed to parse svg source code for image dimensions")?;
let content = result_to_issue(
ident,
std::str::from_utf8(&bytes).context("Input image is not valid utf-8"),
);
let Some(content) = content else {
return Ok(ImageMetaData::fallback_value(Some(mime::IMAGE_SVG)).cell());
};
let info = result_to_issue(
ident,
calculate(content).context("Failed to parse svg source code for image dimensions"),
);
let Some((width, height)) = info else {
return Ok(ImageMetaData::fallback_value(Some(mime::IMAGE_SVG)).cell());
};
return Ok(ImageMetaData {
width,
height,
Expand All @@ -266,7 +301,7 @@ pub async fn get_meta_data(
.cell());
}
let Some((image, format)) = load_image(ident, &bytes, extension) else {
return Ok(ImageMetaData::default().cell());
return Ok(ImageMetaData::fallback_value(None).cell());
};
let (width, height) = image.dimensions();
let blur_placeholder = if let Some(blur_placeholder) = blur_placeholder {
Expand Down

0 comments on commit ac765e7

Please sign in to comment.