mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
dynamic/static embeds
This commit is contained in:
parent
e5c9aeb7fe
commit
cb56c80555
22 changed files with 9068 additions and 665 deletions
3994
build/derive/Cargo.lock
generated
Normal file
3994
build/derive/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
16
build/derive/Cargo.toml
Normal file
16
build/derive/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "demostf-build-derive"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "demostf_build_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "2.0.12"
|
||||
quote = "1.0.26"
|
||||
proc-macro2 = "1.0.54"
|
||||
structmeta = "0.2.0"
|
||||
merge = "0.1.0"
|
||||
demostf-build-bundlers = {version = "0.1", path = "../bundlers"}
|
||||
203
build/derive/src/asset.rs
Normal file
203
build/derive/src/asset.rs
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
use crate::{err, Derivable, DeriveParams};
|
||||
use demostf_build_bundlers::guess_mime;
|
||||
use merge::Merge;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use structmeta::StructMeta;
|
||||
use syn::parse::Parse;
|
||||
use syn::{Attribute, DeriveInput, LitStr, Result};
|
||||
|
||||
pub struct Asset;
|
||||
|
||||
impl Derivable for Asset {
|
||||
type Params = AssetParams;
|
||||
|
||||
fn derive(params: AssetParams) -> Result<TokenStream> {
|
||||
let struct_ident = params.name;
|
||||
let span = struct_ident.span();
|
||||
let input_path = params.source;
|
||||
|
||||
let asset = if params.debug {
|
||||
AssetContent::Runtime {
|
||||
url: input_path.clone(),
|
||||
ty: params.ty,
|
||||
}
|
||||
} else {
|
||||
let content = params.ty.bundle(&input_path);
|
||||
AssetContent::Compiled {
|
||||
route: params.url.clone(),
|
||||
content,
|
||||
}
|
||||
};
|
||||
let content = asset.content();
|
||||
let buster = asset.buster();
|
||||
let etag = asset.etag();
|
||||
let url = asset.url();
|
||||
let mime = guess_mime(&input_path);
|
||||
let mime = quote_spanned!(span => #mime);
|
||||
let route = params.url;
|
||||
let route = quote_spanned!(span => #route);
|
||||
|
||||
Ok(
|
||||
quote_spanned!(span => impl demostf_build::Asset for #struct_ident {
|
||||
fn mime() -> &'static str {
|
||||
#mime
|
||||
}
|
||||
fn etag() -> &'static str {
|
||||
#etag
|
||||
}
|
||||
fn cache_buster() -> std::borrow::Cow<'static, str> {
|
||||
#buster
|
||||
}
|
||||
fn content() -> std::borrow::Cow<'static, [u8]> {
|
||||
#content
|
||||
}
|
||||
fn route() -> &'static str {
|
||||
#route
|
||||
}
|
||||
fn url() -> std::borrow::Cow<'static, str> {
|
||||
#url
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AssetParams {
|
||||
name: Ident,
|
||||
debug: bool,
|
||||
source: String,
|
||||
url: String,
|
||||
ty: AssetType,
|
||||
}
|
||||
|
||||
enum AssetType {
|
||||
Js,
|
||||
Css,
|
||||
Raw,
|
||||
}
|
||||
|
||||
impl AssetType {
|
||||
fn from_url(url: &str) -> Self {
|
||||
if url.ends_with("css") {
|
||||
return AssetType::Css;
|
||||
} else if url.ends_with("js") {
|
||||
return AssetType::Js;
|
||||
}
|
||||
return AssetType::Raw;
|
||||
}
|
||||
|
||||
fn bundle_fn(&self) -> TokenStream {
|
||||
match self {
|
||||
AssetType::Css => quote!(bundle_style),
|
||||
AssetType::Js => quote!(bundle_script),
|
||||
AssetType::Raw => quote!(bundle_raw),
|
||||
}
|
||||
}
|
||||
|
||||
fn bundle(self, url: &str) -> Vec<u8> {
|
||||
match self {
|
||||
AssetType::Css => demostf_build_bundlers::bundle_style(url),
|
||||
AssetType::Js => demostf_build_bundlers::bundle_script(url),
|
||||
AssetType::Raw => demostf_build_bundlers::bundle_raw(url),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AssetContent {
|
||||
Runtime { url: String, ty: AssetType },
|
||||
Compiled { route: String, content: Vec<u8> },
|
||||
}
|
||||
|
||||
impl AssetContent {
|
||||
pub fn content(&self) -> TokenStream {
|
||||
match self {
|
||||
AssetContent::Runtime { url, ty } => {
|
||||
let bundle_fn = ty.bundle_fn();
|
||||
quote!(demostf_build::#bundle_fn(#url).into())
|
||||
}
|
||||
AssetContent::Compiled { content, .. } => {
|
||||
quote!(std::borrow::Cow::Borrowed(&[
|
||||
#(#content,)*
|
||||
]))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn buster(&self) -> TokenStream {
|
||||
match self {
|
||||
AssetContent::Runtime { .. } => {
|
||||
quote!(demostf_build::random_cache_buster().into())
|
||||
}
|
||||
AssetContent::Compiled { content, .. } => {
|
||||
let hash = demostf_build_bundlers::hash(&content);
|
||||
quote!(std::borrow::Cow::Borrowed(#hash))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn etag(&self) -> TokenStream {
|
||||
match self {
|
||||
AssetContent::Runtime { .. } => {
|
||||
quote!("")
|
||||
}
|
||||
AssetContent::Compiled { content, .. } => {
|
||||
let hash = demostf_build_bundlers::hash(&content);
|
||||
quote!(#hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn url(&self) -> TokenStream {
|
||||
match self {
|
||||
AssetContent::Runtime { .. } => {
|
||||
quote!(format!("{}?v={}", Self::route(), Self::cache_buster()).into())
|
||||
}
|
||||
AssetContent::Compiled { content, route } => {
|
||||
let hash = demostf_build_bundlers::hash(&content);
|
||||
let url = format!("{}?v={}", route, hash);
|
||||
quote!(std::borrow::Cow::Borrowed(#url))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeriveParams for AssetParams {
|
||||
fn parse(input: &DeriveInput) -> Result<AssetParams> {
|
||||
let attrs: AssetAttrs = parse_attrs(&input.attrs);
|
||||
#[cfg(debug_assertions)]
|
||||
let debug = true;
|
||||
#[cfg(not(debug_assertions))]
|
||||
let debug = false;
|
||||
let Some(source) = attrs.source else {
|
||||
return err("missing require attribute #[asset(source)]", input);
|
||||
};
|
||||
let source = source.value();
|
||||
let Some(url) = attrs.url else {
|
||||
return err("missing require attribute #[asset(url)]", input);
|
||||
};
|
||||
let url = url.value();
|
||||
let ty = AssetType::from_url(&url);
|
||||
|
||||
Ok(AssetParams {
|
||||
name: input.ident.clone(),
|
||||
debug,
|
||||
source,
|
||||
url,
|
||||
ty,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_attrs<T: Parse + Default + Merge>(attrs: &[Attribute]) -> T {
|
||||
let mut result = T::default();
|
||||
for attr in attrs {
|
||||
if let Ok(parsed) = attr.parse_args() {
|
||||
result.merge(parsed);
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[derive(Default, StructMeta, Merge)]
|
||||
struct AssetAttrs {
|
||||
source: Option<LitStr>,
|
||||
url: Option<LitStr>,
|
||||
}
|
||||
43
build/derive/src/lib.rs
Normal file
43
build/derive/src/lib.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//! Derive macros for tf-log-parser
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
mod asset;
|
||||
|
||||
use crate::asset::Asset;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use std::fmt::Display;
|
||||
use syn::{parse_macro_input, DeriveInput, Error, Result};
|
||||
|
||||
/// Derive the `Asset` trait for a struct
|
||||
#[proc_macro_derive(Asset, attributes(asset))]
|
||||
pub fn derive_asset(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let expanded = derive_trait::<Asset>(parse_macro_input!(input as DeriveInput));
|
||||
|
||||
proc_macro::TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Basic wrapper for error handling
|
||||
fn derive_trait<Trait: Derivable>(input: DeriveInput) -> TokenStream {
|
||||
derive_trait_inner::<Trait>(input).unwrap_or_else(|err| err.into_compile_error())
|
||||
}
|
||||
|
||||
fn derive_trait_inner<Trait: Derivable>(input: DeriveInput) -> Result<TokenStream> {
|
||||
let params = Trait::Params::parse(&input)?;
|
||||
Trait::derive(params)
|
||||
}
|
||||
|
||||
trait Derivable {
|
||||
type Params: DeriveParams;
|
||||
|
||||
fn derive(params: Self::Params) -> Result<TokenStream>;
|
||||
}
|
||||
|
||||
trait DeriveParams: Sized {
|
||||
fn parse(input: &DeriveInput) -> Result<Self>;
|
||||
}
|
||||
|
||||
fn err<R, T: ToTokens, U: Display>(msg: U, span: T) -> Result<R> {
|
||||
return Err(Error::new_spanned(&span, msg));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue