Skip to main content

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}