diff --git a/crates/spa/src/vite.rs b/crates/spa/src/vite.rs index b2d7c0c2a..8a56b0097 100644 --- a/crates/spa/src/vite.rs +++ b/crates/spa/src/vite.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2023, 2024 The Matrix.org Foundation C.I.C. // @@ -30,7 +31,6 @@ pub struct ManifestEntry { #[expect(dead_code)] is_entry: Option, - #[expect(dead_code)] is_dynamic_entry: Option, imports: Option>, @@ -90,6 +90,7 @@ pub struct Asset<'a> { file_type: FileType, name: &'a Utf8Path, integrity: Option<&'a str>, + is_dynamic_entry: bool, } impl<'a> Asset<'a> { @@ -101,6 +102,7 @@ impl<'a> Asset<'a> { file_type, name, integrity, + is_dynamic_entry: entry.is_dynamic_entry.unwrap_or(false), }) } @@ -116,6 +118,13 @@ impl<'a> Asset<'a> { self.file_type } + /// Whether this asset is a chunk which is only reachable through a dynamic + /// `import()`, and therefore must not be evaluated eagerly + #[must_use] + pub fn is_dynamic_entry(&self) -> bool { + self.is_dynamic_entry + } + /// Get the integrity HTML tag attribute, with a leading space, if any #[must_use] pub fn integrity_attr(&self) -> String { diff --git a/crates/templates/src/functions.rs b/crates/templates/src/functions.rs index ea47be14d..16515572e 100644 --- a/crates/templates/src/functions.rs +++ b/crates/templates/src/functions.rs @@ -485,6 +485,20 @@ impl Object for IncludeAsset { // We'll accumulate the output in this string let mut output = String::new(); match main.file_type() { + mas_spa::FileType::Script if main.is_dynamic_entry() => { + // Chunks which are only reachable through a dynamic `import()` + // (like the translation files) must not be evaluated eagerly, + // we only hint the browser to fetch them + let integrity = main.integrity_attr(); + let src = main.src(assets_base); + if tracker.mark_preloaded(&src) { + writeln!( + output, + r#""# + ) + .unwrap(); + } + } mas_spa::FileType::Script => { let integrity = main.integrity_attr(); let src = main.src(assets_base); @@ -508,14 +522,6 @@ impl Object for IncludeAsset { } } - mas_spa::FileType::Json => { - // When a JSON is included at the top level (a translation), we preload it - let src = main.src(assets_base); - if tracker.mark_preloaded(&src) { - writeln!(output, r#""#).unwrap(); - } - } - file_type => { return Err(Error::new( ErrorKind::InvalidOperation, @@ -560,10 +566,8 @@ impl Object for IncludeAsset { } } mas_spa::FileType::Woff | mas_spa::FileType::Woff2 | mas_spa::FileType::Json => { - // Skip pre-loading fonts and JSON (translations) as it will - // lead to many wasted preloads. For translations, we only - // include them as preload if they are included on the - // top-level + // Skip pre-loading fonts and raw JSON assets, as it will + // lead to many wasted preloads } } }