#![warn(clippy::pedantic)]
use vite_static_shared::Manifest;
#[allow(unused_imports)]
use vite_static_shared::ManifestChunk;
#[derive(Clone, Debug, Default)]
struct HtmlLinks {
stylesheets: Vec<&'static str>,
scripts: Vec<&'static str>,
preloads: Vec<&'static str>,
}
pub struct HtmlIntegration {
manifest: Box<dyn Manifest<'static>>,
links: HtmlLinks,
}
impl HtmlIntegration {
#[must_use]
pub fn new(manifest: Box<dyn Manifest<'static>>) -> Self {
Self {
manifest,
links: HtmlLinks::default(),
}
}
fn import_as(&mut self, chunk: &str, is_dependency: bool) {
let chunk = self
.manifest
.chunk_by_key(chunk)
.unwrap_or_else(|| panic!(r#"failed to find chunk "{chunk}""#));
for css in chunk.css {
if !self.links.stylesheets.contains(css) {
self.links.stylesheets.push(css);
}
}
for import in chunk.imports {
let import_file = self
.manifest
.resolve_output(import)
.unwrap_or_else(|| panic!(r#"failed to find imported chunk "{import}""#));
if !self.links.preloads.contains(&import_file) {
self.import_as(import, true);
}
}
if is_dependency {
self.links.preloads.push(chunk.file);
} else {
self.links.scripts.push(chunk.file);
}
}
#[must_use]
pub fn import(mut self, chunk: &str) -> Self {
self.import_as(chunk, false);
self
}
#[must_use]
pub fn build_lines(self) -> Vec<String> {
let links = self.links;
let mut html = Vec::new();
for style in links.stylesheets {
html.push(format!(r#"<link rel="stylesheet" href="/{style}" />"#));
}
for script in links.scripts {
html.push(format!(
r#"<script type="module" src="/{script}"></script>"#
));
}
for preload in links.preloads {
html.push(format!(r#"<link rel="modulepreload" href="/{preload}" />"#));
}
html
}
#[must_use]
pub fn build(self) -> String {
self.build_lines().join("\n")
}
}
impl Clone for HtmlIntegration {
fn clone(&self) -> Self {
Self {
manifest: self.manifest.boxed(),
links: self.links.clone(),
}
}
}