Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow to use different blur placeholder modes #49070

Merged
merged 2 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/next-swc/crates/next-core/src/app_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ use crate::{
context::{get_edge_compile_time_info, get_edge_resolve_options_context},
transition::NextEdgeTransition,
},
next_image::module::StructuredImageModuleType,
next_image::module::{BlurPlaceholderMode, StructuredImageModuleType},
next_route_matcher::NextParamsMatcherVc,
next_server::context::{
get_server_compile_time_info, get_server_module_options_context,
Expand Down Expand Up @@ -783,6 +783,7 @@ import {}, {{ chunks as {} }} from "COMPONENT_{}";
inner_module_id,
StructuredImageModuleType::create_module(
SourceAssetVc::new(*path).into(),
BlurPlaceholderMode::None,
state.context,
)
.into(),
Expand Down
36 changes: 31 additions & 5 deletions packages/next-swc/crates/next-core/src/next_image/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,43 @@ use turbo_binding::{

use super::source_asset::StructuredImageSourceAsset;

#[turbo_tasks::value(serialization = "auto_for_input")]
#[derive(Clone, Copy, Debug, PartialOrd, Ord, Hash)]
pub enum BlurPlaceholderMode {
/// Do not generate a blur placeholder at all.
None,
/// Generate a blur placeholder as data url and embed it directly into the
/// JavaScript code. This needs to compute the blur placeholder eagerly and
/// has a higher computation overhead.
DataUrl,
/// Avoid generating a blur placeholder eagerly and uses `/_next/image`
/// instead to compute one on demand. This changes the UX slightly (blur
/// placeholder is shown later than it should be) and should
/// only be used for development.
NextImageUrl,
}

/// Module type that analyzes images and offers some meta information like
/// width, height and blur placeholder as export from the module.
#[turbo_tasks::value]
pub struct StructuredImageModuleType {}
pub struct StructuredImageModuleType {
pub blur_placeholder_mode: BlurPlaceholderMode,
}

impl StructuredImageModuleType {
pub(crate) fn create_module(
source: AssetVc,
blur_placeholder_mode: BlurPlaceholderMode,
context: AssetContextVc,
) -> EcmascriptModuleAssetVc {
let static_asset = StaticModuleAssetVc::new(source, context);
EcmascriptModuleAssetVc::new_with_inner_assets(
StructuredImageSourceAsset { image: source }.cell().into(),
StructuredImageSourceAsset {
image: source,
blur_placeholder_mode,
}
.cell()
.into(),
context,
Value::new(EcmascriptModuleAssetType::Ecmascript),
EcmascriptInputTransformsVc::empty(),
Expand All @@ -49,8 +73,10 @@ impl StructuredImageModuleType {
#[turbo_tasks::value_impl]
impl StructuredImageModuleTypeVc {
#[turbo_tasks::function]
pub fn new() -> Self {
StructuredImageModuleTypeVc::cell(StructuredImageModuleType {})
pub fn new(blur_placeholder_mode: Value<BlurPlaceholderMode>) -> Self {
StructuredImageModuleTypeVc::cell(StructuredImageModuleType {
blur_placeholder_mode: blur_placeholder_mode.into_value(),
})
}
}

Expand All @@ -63,6 +89,6 @@ impl CustomModuleType for StructuredImageModuleType {
context: AssetContextVc,
_part: Option<ModulePartVc>,
) -> AssetVc {
StructuredImageModuleType::create_module(source, context).into()
StructuredImageModuleType::create_module(source, self.blur_placeholder_mode, context).into()
}
}
84 changes: 59 additions & 25 deletions packages/next-swc/crates/next-core/src/next_image/source_asset.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::io::Write;

use anyhow::{bail, Result};
use serde::Serialize;
use turbo_binding::{
turbo::{
tasks::primitives::StringVc,
Expand All @@ -17,6 +16,8 @@ use turbo_binding::{
},
};

use super::module::BlurPlaceholderMode;

fn modifier() -> StringVc {
StringVc::cell("structured image object".to_string())
}
Expand All @@ -30,22 +31,12 @@ fn blur_options() -> BlurPlaceholderOptionsVc {
.cell()
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ImageExport<'a> {
width: u32,
height: u32,
#[serde(rename = "blurDataURL")]
blur_data_url: Option<&'a str>,
blur_width: u32,
blur_height: u32,
}

/// An source asset that transforms an image into javascript code which exports
/// an object with meta information like width, height and a blur placeholder.
#[turbo_tasks::value(shared)]
pub struct StructuredImageSourceAsset {
pub image: AssetVc,
pub blur_placeholder_mode: BlurPlaceholderMode,
}

#[turbo_tasks::value_impl]
Expand All @@ -62,20 +53,63 @@ impl Asset for StructuredImageSourceAsset {
bail!("Input source is not a file and can't be transformed into image information");
};
let mut result = RopeBuilder::from("");
let info = get_meta_data(self.image.ident(), content, Some(blur_options())).await?;
let info = ImageExport {
width: info.width,
height: info.height,
blur_width: info.blur_placeholder.as_ref().map_or(0, |p| p.width),
blur_height: info.blur_placeholder.as_ref().map_or(0, |p| p.height),
blur_data_url: info.blur_placeholder.as_ref().map(|p| p.data_url.as_str()),
};
writeln!(result, "import src from \"IMAGE\";",)?;
writeln!(
result,
"export default {{ src, ...{} }}",
StringifyJs(&info)
)?;
let blur_options = blur_options();
match self.blur_placeholder_mode {
BlurPlaceholderMode::NextImageUrl => {
let info = get_meta_data(self.image.ident(), content, None).await?;
let width = info.width;
let height = info.height;
let blur_options = blur_options.await?;
let (blur_width, blur_height) = if width > height {
(
blur_options.size,
(blur_options.size as f32 * height as f32 / width as f32).ceil() as u32,
)
} else {
(
(blur_options.size as f32 * width as f32 / height as f32).ceil() as u32,
blur_options.size,
)
};
writeln!(
result,
"export default {{ src, width: {width}, height: {height}, blurDataURL: \
`/_next/image?w={blur_width}&q={quality}&url=${{encodeURIComponent(src)}}`, \
blurWidth: {blur_width}, blurHeight: {blur_height} }}",
width = StringifyJs(&info.width),
height = StringifyJs(&info.height),
quality = StringifyJs(&blur_options.quality),
blur_width = StringifyJs(&blur_width),
blur_height = StringifyJs(&blur_height),
)?;
}
BlurPlaceholderMode::DataUrl => {
let info = get_meta_data(self.image.ident(), content, Some(blur_options)).await?;
writeln!(
result,
"export default {{ src, width: {width}, height: {height}, blurDataURL: \
{blur_data_url}, blurWidth: {blur_width}, blurHeight: {blur_height} }}",
width = StringifyJs(&info.width),
height = StringifyJs(&info.height),
blur_data_url =
StringifyJs(&info.blur_placeholder.as_ref().map(|p| p.data_url.as_str())),
blur_width =
StringifyJs(&info.blur_placeholder.as_ref().map_or(0, |p| p.width)),
blur_height =
StringifyJs(&info.blur_placeholder.as_ref().map_or(0, |p| p.height),),
)?;
}
BlurPlaceholderMode::None => {
let info = get_meta_data(self.image.ident(), content, None).await?;
writeln!(
result,
"export default {{ src, width: {width}, height: {height} }}",
width = StringifyJs(&info.width),
height = StringifyJs(&info.height),
)?;
}
};
Ok(AssetContent::File(FileContent::Content(result.build().into()).cell()).cell())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ use turbo_binding::{
},
},
};
use turbo_tasks::trace::TraceRawVcs;
use turbo_tasks::{trace::TraceRawVcs, Value};

use crate::next_image::StructuredImageModuleTypeVc;
use crate::next_image::{module::BlurPlaceholderMode, StructuredImageModuleTypeVc};

/// Returns a rule which applies the Next.js page export stripping transform.
pub async fn get_next_pages_transforms_rule(
Expand Down Expand Up @@ -98,7 +98,7 @@ pub fn get_next_image_rule() -> ModuleRule {
ModuleRuleCondition::ResourcePathEndsWith(".svg".to_string()),
]),
vec![ModuleRuleEffect::ModuleType(ModuleType::Custom(
StructuredImageModuleTypeVc::new().into(),
StructuredImageModuleTypeVc::new(Value::new(BlurPlaceholderMode::DataUrl)).into(),
Copy link
Member Author

@sokra sokra May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it's possible to flip to the _next/image mode by changing this:

Suggested change
StructuredImageModuleTypeVc::new(Value::new(BlurPlaceholderMode::DataUrl)).into(),
StructuredImageModuleTypeVc::new(Value::new(BlurPlaceholderMode::NextImage)).into(),

see WEB-960

))],
)
}
Expand Down