Skip to content

Commit 09dd5e6

Browse files
committed
Stub out the vite manifest when stabilising template renders
1 parent 4a06f72 commit 09dd5e6

File tree

8 files changed

+95
-31
lines changed

8 files changed

+95
-31
lines changed

crates/cli/src/commands/server.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ impl Options {
166166
&url_builder,
167167
// Don't use strict mode in production yet
168168
false,
169+
// Don't stabilise in production
170+
false,
169171
)
170172
.await?;
171173
shutdown.register_reloadable(&templates);

crates/cli/src/commands/templates.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,10 @@ impl Options {
9090
let templates = templates_from_config(
9191
&template_config,
9292
&site_config,
93-
&url_builder, // Use strict mode in template checks
93+
&url_builder,
94+
// Use strict mode in template checks
9495
true,
96+
stabilise,
9597
)
9698
.await?;
9799
let all_renders = templates.check_render(now, &rng)?;

crates/cli/src/commands/worker.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ impl Options {
5858
&url_builder,
5959
// Don't use strict mode on task workers for now
6060
false,
61+
// Don't stabilise in production
62+
false,
6163
)
6264
.await?;
6365

crates/cli/src/util.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,12 @@ pub async fn templates_from_config(
233233
site_config: &SiteConfig,
234234
url_builder: &UrlBuilder,
235235
strict: bool,
236+
stabilise: bool,
236237
) -> Result<Templates, anyhow::Error> {
237238
Templates::load(
238239
config.path.clone(),
239240
url_builder.clone(),
240-
config.assets_manifest.clone(),
241+
(!stabilise).then(|| config.assets_manifest.clone()),
241242
config.translations_path.clone(),
242243
site_config.templates_branding(),
243244
site_config.templates_features(),

crates/handlers/src/test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ impl TestState {
172172
let templates = Templates::load(
173173
workspace_root.join("templates"),
174174
url_builder.clone(),
175-
workspace_root.join("frontend/dist/manifest.json"),
175+
Some(workspace_root.join("frontend/dist/manifest.json")),
176176
workspace_root.join("translations"),
177177
site_config.templates_branding(),
178178
site_config.templates_features(),

crates/spa/src/vite.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,48 @@ pub struct Manifest {
4747
inner: HashMap<Utf8PathBuf, ManifestEntry>,
4848
}
4949

50+
impl Manifest {
51+
/// Produce a sample manifest for use in reproducible sample renders.
52+
#[must_use]
53+
#[allow(clippy::missing_panics_doc)]
54+
pub fn sample() -> Self {
55+
let mut inner = HashMap::new();
56+
57+
for name in &[
58+
"src/shared.css",
59+
"src/templates.css",
60+
"src/main.tsx",
61+
"src/swagger.ts",
62+
] {
63+
inner.insert(
64+
name.parse().unwrap(),
65+
ManifestEntry {
66+
name: None,
67+
names: None,
68+
src: None,
69+
// Construct a fake but slightly plausible dummy asset name.
70+
file: name
71+
.replace('/', "__")
72+
.replace('.', "-XXXXX.")
73+
.replace(".tsx", ".js")
74+
.replace(".ts", ".js")
75+
.parse()
76+
.unwrap(),
77+
css: None,
78+
assets: None,
79+
is_entry: None,
80+
is_dynamic_entry: None,
81+
imports: None,
82+
dynamic_imports: None,
83+
integrity: None,
84+
},
85+
);
86+
}
87+
88+
Manifest { inner }
89+
}
90+
}
91+
5092
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
5193
enum FileType {
5294
Script,

crates/templates/src/functions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,10 @@ impl Object for IncludeAsset {
434434

435435
let path: &Utf8Path = path.into();
436436

437-
let (main, imported) = self.vite_manifest.find_assets(path).map_err(|_e| {
437+
let (main, imported) = self.vite_manifest.find_assets(path).map_err(|e| {
438438
Error::new(
439439
ErrorKind::InvalidOperation,
440-
"Invalid assets manifest while calling function `include_asset`",
440+
format!("Invalid assets manifest while calling function `include_asset` with path = {path:?}: {e}"),
441441
)
442442
})?;
443443

crates/templates/src/lib.rs

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub struct Templates {
7272
url_builder: UrlBuilder,
7373
branding: SiteBranding,
7474
features: SiteFeatures,
75-
vite_manifest_path: Utf8PathBuf,
75+
vite_manifest_path: Option<Utf8PathBuf>,
7676
translations_path: Utf8PathBuf,
7777
path: Utf8PathBuf,
7878
/// Whether template rendering is in strict mode (for testing,
@@ -143,6 +143,11 @@ fn is_hidden(entry: &DirEntry) -> bool {
143143
impl Templates {
144144
/// Load the templates from the given config
145145
///
146+
/// # Parameters
147+
///
148+
/// - `vite_manifest_path`: None if we are rendering resources for
149+
/// reproducibility, in which case a dummy Vite manifest will be used.
150+
///
146151
/// # Errors
147152
///
148153
/// Returns an error if the templates could not be loaded from disk.
@@ -154,7 +159,7 @@ impl Templates {
154159
pub async fn load(
155160
path: Utf8PathBuf,
156161
url_builder: UrlBuilder,
157-
vite_manifest_path: Utf8PathBuf,
162+
vite_manifest_path: Option<Utf8PathBuf>,
158163
translations_path: Utf8PathBuf,
159164
branding: SiteBranding,
160165
features: SiteFeatures,
@@ -163,7 +168,7 @@ impl Templates {
163168
let (translator, environment) = Self::load_(
164169
&path,
165170
url_builder.clone(),
166-
&vite_manifest_path,
171+
vite_manifest_path.as_deref(),
167172
&translations_path,
168173
branding.clone(),
169174
features,
@@ -186,7 +191,7 @@ impl Templates {
186191
async fn load_(
187192
path: &Utf8Path,
188193
url_builder: UrlBuilder,
189-
vite_manifest_path: &Utf8Path,
194+
vite_manifest_path: Option<&Utf8Path>,
190195
translations_path: &Utf8Path,
191196
branding: SiteBranding,
192197
features: SiteFeatures,
@@ -196,13 +201,18 @@ impl Templates {
196201
let span = tracing::Span::current();
197202

198203
// Read the assets manifest from disk
199-
let vite_manifest = tokio::fs::read(vite_manifest_path)
200-
.await
201-
.map_err(TemplateLoadingError::ViteManifestIO)?;
204+
let vite_manifest = if let Some(vite_manifest_path) = vite_manifest_path {
205+
let raw_vite_manifest = tokio::fs::read(vite_manifest_path)
206+
.await
207+
.map_err(TemplateLoadingError::ViteManifestIO)?;
208+
209+
serde_json::from_slice::<ViteManifest>(&raw_vite_manifest)
210+
.map_err(TemplateLoadingError::ViteManifest)?
211+
} else {
212+
ViteManifest::sample()
213+
};
202214

203215
// Parse it
204-
let vite_manifest: ViteManifest =
205-
serde_json::from_slice(&vite_manifest).map_err(TemplateLoadingError::ViteManifest)?;
206216

207217
let translations_path = translations_path.to_owned();
208218
let translator =
@@ -291,7 +301,7 @@ impl Templates {
291301
let (translator, environment) = Self::load_(
292302
&self.path,
293303
self.url_builder.clone(),
294-
&self.vite_manifest_path,
304+
self.vite_manifest_path.as_deref(),
295305
&self.translations_path,
296306
self.branding.clone(),
297307
self.features,
@@ -506,23 +516,28 @@ mod tests {
506516
Utf8Path::new(env!("CARGO_MANIFEST_DIR")).join("../../frontend/dist/manifest.json");
507517
let translations_path =
508518
Utf8Path::new(env!("CARGO_MANIFEST_DIR")).join("../../translations");
509-
let templates = Templates::load(
510-
path,
511-
url_builder,
512-
vite_manifest_path,
513-
translations_path,
514-
branding,
515-
features,
516-
// Use strict mode in tests
517-
true,
518-
)
519-
.await
520-
.unwrap();
521519

522-
// Check the renders are deterministic, when given the same rng
523-
let render1 = templates.check_render(now, &rng).unwrap();
524-
let render2 = templates.check_render(now, &rng).unwrap();
520+
for use_real_vite_manifest in [true, false] {
521+
let templates = Templates::load(
522+
path.clone(),
523+
url_builder.clone(),
524+
// Check both renders against the real vite manifest and the 'dummy' vite manifest
525+
// used for reproducible renders.
526+
use_real_vite_manifest.then_some(vite_manifest_path.clone()),
527+
translations_path.clone(),
528+
branding.clone(),
529+
features,
530+
// Use strict mode in tests
531+
true,
532+
)
533+
.await
534+
.unwrap();
535+
536+
// Check the renders are deterministic, when given the same rng
537+
let render1 = templates.check_render(now, &rng).unwrap();
538+
let render2 = templates.check_render(now, &rng).unwrap();
525539

526-
assert_eq!(render1, render2);
540+
assert_eq!(render1, render2);
541+
}
527542
}
528543
}

0 commit comments

Comments
 (0)