vite_static_shared/lib.rs
1#![warn(clippy::pedantic)]
2
3use std::{borrow::Cow, collections::HashMap};
4
5use serde::{Deserialize, Serialize};
6
7pub mod parsing;
8
9/// Type of `.vite/manifest.json`.
10pub type ViteManifest<'a> = HashMap<Cow<'a, str>, ManifestChunk<'a>>;
11
12/// Vite manifest chunk.
13///
14/// [See Vite documentation](https://vite.dev/guide/backend-integration)
15#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, Hash)]
16#[serde(rename_all = "camelCase")]
17pub struct ManifestChunk<'a> {
18 /// The key of this chunk in manifest.
19 ///
20 /// This field is added by `vite-static` and skipped during (de)serialization.
21 #[serde(skip)]
22 pub key: Cow<'a, str>,
23
24 /// The contents of manifest chunk.
25 ///
26 /// This field is added by `vite-static` and skipped during (de)serialization.
27 #[serde(skip)]
28 pub contents: Cow<'a, [u8]>,
29
30 /// Hash of this chunk. Derive macro uses [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) as hashing algorithm.
31 ///
32 /// This field is added by `vite-static` and skipped during (de)serialization.
33 #[serde(skip)]
34 pub hash: Cow<'a, str>,
35
36 /// Mime type of this chunk.
37 ///
38 /// This field is added by `vite-static` and skipped during (de)serialization.
39 #[serde(skip)]
40 pub mime_type: Cow<'a, str>,
41
42 /// The input file name of this chunk/asset if known.
43 pub src: Option<Cow<'a, str>>,
44
45 /// The output file name of this chunk/asset.
46 pub file: Cow<'a, str>,
47
48 /// The list of CSS files imported by this chunk.
49 #[serde(default)]
50 pub css: Cow<'a, [Cow<'a, str>]>,
51
52 /// The list of asset files imported by this chunk, excluding CSS files.
53 #[serde(default)]
54 pub assets: Cow<'a, [Cow<'a, str>]>,
55
56 /// Whether this chunk or asset is an entry point
57 #[serde(default)]
58 pub is_entry: bool,
59
60 /// The name of this chunk/asset if known.
61 pub name: Option<Cow<'a, str>>,
62
63 /// Whether this chunk is a dynamic entry point
64 ///
65 /// This field is only present in JS chunks.
66 #[serde(default)]
67 pub is_dynamic_entry: bool,
68
69 /// The list of statically imported chunks by this chunk
70 ///
71 /// The values are the keys of the manifest. This field is only present in JS chunks.
72 #[serde(default)]
73 pub imports: Cow<'a, [Cow<'a, str>]>,
74
75 /// The list of dynamically imported chunks by this chunk
76 ///
77 /// The values are the keys of the manifest. This field is only present in JS chunks.
78 #[serde(default)]
79 pub dynamic_imports: Cow<'a, [Cow<'a, str>]>,
80}
81
82/// Trait, that returns boxed [`Manifest`].
83///
84/// This trait is required for manifests and usually by integrations. **It is automatically implemented by derive macro**.
85///
86/// ```
87/// impl Boxed<'static> for MyViteManifest {
88/// fn boxed(&self) -> Box<dyn Manifest<'static>> {
89/// Box::new(MyViteManifest)
90/// }
91/// }
92///
93/// SomeCoolAndAwesomeIntegration::new(MyViteManifest.boxed()) // easy and simple!
94/// ```
95pub trait Boxed<'a> {
96 fn boxed(&self) -> Box<dyn Manifest<'a>>;
97}
98
99/// Trait for static/embedded manifests.
100///
101/// This trait is sort of internal, because it's suitable **only for embedded manifests**, so use [`Manifest`] instead!
102///
103/// This trait automatically implements [`Manifest`].
104pub trait StaticManifest: Boxed<'static> {
105 /// Get array of `(key, output_filename)` pairs.
106 ///
107 /// Array must be sorted by `key`
108 fn static_key_output_pairs(&self) -> &[(&'static str, &'static str)];
109
110 /// Get [`ManifestChunk`]s as `(output_filename, chunk)` pairs.
111 ///
112 /// Array must be sorted by `output_filename`
113 fn static_chunks(&self) -> &[(&'static str, &'static ManifestChunk<'static>)];
114}
115
116/// Trait, that helps query chunks in Vite manifest.
117///
118/// See `Manifest` derive and [`ManifestChunk`].
119pub trait Manifest<'a>: Boxed<'a> {
120 /// Get `output_filename` from manifest key.
121 ///
122 /// ```rust
123 /// MyViteManifest.resolve_output("src/main.tsx") // returns "main.HASH.js"
124 /// ```
125 fn resolve_output(&self, key: &str) -> Option<Cow<'a, str>>;
126
127 /// Iterator over manifest keys (input filenames, e.g. "src/main.tsx").
128 ///
129 /// ```rust
130 /// MyViteManifest.iter_keys()
131 /// // returns iterator over keys (e.g. "src/main.tsx", "src/component.tsx", ...)
132 /// ```
133 fn iter_keys(&self) -> Box<dyn Iterator<Item = &str> + '_>;
134
135 /// Iterator over manifest outputs (output filenames, e.g. "main.hashhh.js").
136 ///
137 /// ```rust
138 /// MyViteManifest.iter_outputs()
139 /// // returns iterator over output files (e.g. "main.HASH.js", "chunks/_shared.HASH.js", ...)
140 /// ```
141 fn iter_outputs(&self) -> Box<dyn Iterator<Item = &str> + '_>;
142
143 /// Get [`ManifestChunk`] from output filename.
144 ///
145 /// ```rust
146 /// dbg!(MyViteManifest.chunk("main.HASH.js"))
147 /// ```
148 fn chunk(&self, output: &str) -> Option<Cow<'a, ManifestChunk<'a>>>;
149
150 /// Get [`ManifestChunk`] from manifest key.
151 ///
152 /// ```rust
153 /// dbg!(MyViteManifest.chunk_by_key("src/main.tsx"))
154 /// ```
155 fn chunk_by_key(&self, key: &str) -> Option<Cow<'a, ManifestChunk<'a>>> {
156 match self.resolve_output(key) {
157 Some(output) => self.chunk(&output),
158 None => None,
159 }
160 }
161}
162
163impl<M: StaticManifest> Manifest<'static> for M {
164 fn resolve_output(&self, key: &str) -> Option<Cow<'static, str>> {
165 let pairs = self.static_key_output_pairs();
166
167 match pairs.binary_search_by_key(&key, |(this_key, _)| this_key) {
168 Ok(index) => Some(Cow::Borrowed(pairs[index].1)),
169 Err(_) => None,
170 }
171 }
172
173 fn iter_keys(&self) -> Box<dyn Iterator<Item = &str> + '_> {
174 Box::new(self.static_key_output_pairs().iter().map(|&(key, _)| key))
175 }
176
177 fn iter_outputs(&self) -> Box<dyn Iterator<Item = &str> + '_> {
178 Box::new(
179 self.static_key_output_pairs()
180 .iter()
181 .map(|&(_, output)| output),
182 )
183 }
184
185 fn chunk(&self, output: &str) -> Option<Cow<'static, ManifestChunk<'static>>> {
186 let chunks = self.static_chunks();
187
188 match chunks.binary_search_by_key(&output, |(this_output, _)| this_output) {
189 Ok(index) => Some(Cow::Borrowed(chunks[index].1)),
190 Err(_) => None,
191 }
192 }
193}