vite_static_shared/lib.rs
1#![warn(clippy::pedantic)]
2
3use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7/// Type of `.vite/manifest.json`.
8pub type ViteManifest<S = String> = HashMap<S, ManifestChunk<S>>;
9
10/// Type alias for dynamic allocated [`ManifestChunk`].
11pub type DynamicManifestChunk = ManifestChunk<String, Vec<String>, Vec<u8>>;
12
13/// Type alias for static [`ManifestChunk`].
14pub type StaticManifestChunk = ManifestChunk<&'static str, &'static [&'static str], &'static [u8]>;
15
16/// Vite manifest chunk.
17///
18/// Where possible, use [`StaticManifestChunk`] and [`DynamicManifestChunk`] instead.
19///
20/// [See Vite documentation](https://vite.dev/guide/backend-integration)
21///
22/// # Generics
23///
24/// - Generic `S` can be used to change type of strings in struct.
25/// - Generic `Vs` can be used to change type of array of strings.
26/// - Generic `Vu8` can be used to change type of byte arrays (f.e. `Vec<u8>` or `&[u8]`).
27#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
28#[serde(rename_all = "camelCase")]
29pub struct ManifestChunk<S = String, Vs = Vec<S>, Vu8 = Vec<u8>> {
30 /// The key of this chunk in manifest.
31 ///
32 /// This field is added by `vite-static` and skipped during (de)serialization.
33 #[serde(skip)]
34 pub key: S,
35
36 /// The contents of manifest chunk.
37 ///
38 /// This field is added by `vite-static` and skipped during (de)serialization.
39 #[serde(skip)]
40 pub contents: Vu8,
41
42 /// Hash of this chunk. Derive macro uses [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) as hashing algorithm.
43 ///
44 /// This field is added by `vite-static` and skipped during (de)serialization.
45 #[serde(skip)]
46 pub hash: S,
47
48 /// Mime type of this chunk.
49 ///
50 /// This field is added by `vite-static` and skipped during (de)serialization.
51 #[serde(skip)]
52 pub mime_type: S,
53
54 /// The input file name of this chunk/asset if known.
55 pub src: Option<S>,
56
57 /// The output file name of this chunk/asset.
58 pub file: S,
59
60 /// The list of CSS files imported by this chunk.
61 #[serde(default)]
62 pub css: Vs,
63
64 /// The list of asset files imported by this chunk, excluding CSS files.
65 #[serde(default)]
66 pub assets: Vs,
67
68 /// Whether this chunk or asset is an entry point
69 #[serde(default)]
70 pub is_entry: bool,
71
72 /// The name of this chunk/asset if known.
73 pub name: Option<S>,
74
75 /// Whether this chunk is a dynamic entry point
76 ///
77 /// This field is only present in JS chunks.
78 #[serde(default)]
79 pub is_dynamic_entry: bool,
80
81 /// The list of statically imported chunks by this chunk
82 ///
83 /// The values are the keys of the manifest. This field is only present in JS chunks.
84 #[serde(default)]
85 pub imports: Vs,
86
87 /// The list of dynamically imported chunks by this chunk
88 ///
89 /// The values are the keys of the manifest. This field is only present in JS chunks.
90 #[serde(default)]
91 pub dynamic_imports: Vs,
92}
93
94/// Trait, that helps query chunks in Vite manifest.
95///
96/// See `Manifest` derive and [`ManifestChunk`].
97pub trait Manifest<'a> {
98 /// Get array of `(key, output_filename)` pairs.
99 ///
100 /// Array must be sorted by `key`
101 fn manifest_key_output_pairs(&self) -> &'a [(&'a str, &'a str)];
102
103 /// Get [`ManifestChunk`]s as `(output_filename, chunk)` pairs.
104 ///
105 /// Array must be sorted by `output_filename`
106 fn manifest_chunks(&self) -> &'a [(&'a str, &'a StaticManifestChunk)];
107
108 fn boxed(&self) -> Box<dyn Manifest<'a>>;
109
110 /// Get `output_filename` from manifest key.
111 fn resolve_output(&self, key: &str) -> Option<&'a str> {
112 let pairs = self.manifest_key_output_pairs();
113
114 match pairs.binary_search_by_key(&key, |&(this_key, _)| this_key) {
115 Ok(index) => Some(pairs[index].1),
116 Err(_) => None,
117 }
118 }
119
120 /// Get [`ManifestChunk`] from output filename.
121 fn chunk(&self, output: &str) -> Option<&'a StaticManifestChunk> {
122 let chunks = self.manifest_chunks();
123
124 match chunks.binary_search_by_key(&output, |&(this_output, _)| this_output) {
125 Ok(index) => Some(chunks[index].1),
126 Err(_) => None,
127 }
128 }
129
130 /// Get [`ManifestChunk`] from manifest key.
131 fn chunk_by_key(&self, output: &str) -> Option<&'a StaticManifestChunk> {
132 match self.resolve_output(output) {
133 Some(output) => self.chunk(output),
134 None => None,
135 }
136 }
137}