Skip to main content

apace/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3//! Apace is a modular, embeddable web engine with a native Rust API.
4//!
5//! It powers the [`dioxus-native`] UI framework.
6//!
7//! This crate exists to collect the most important functionality for users together in one place.
8//! It does not bring any unique functionality, but rather, it re-exports the relevant crates as modules.
9//! The exported crate corresponding to each module is also available in a stand-alone manner, i.e. [`apace-dom`] as [`apace::dom`](crate::dom).
10//!
11//! [`dioxus-native`]: https://docs.rs/dioxus-native
12//! [`apace-dom`]: https://docs.rs/apace-dom
13
14use std::sync::Arc;
15
16use anyrender_vello::VelloWindowRenderer as WindowRenderer;
17use apace_dom::{DocumentConfig, UserAgentStylesheet};
18use apace_html::HtmlDocument;
19use apace_shell::{
20    ApaceApplication, ApaceShellProxy, Config, EventLoop, WindowConfig, create_default_event_loop,
21};
22use apace_traits::net::NetProvider;
23
24#[doc(inline)]
25/// Re-export of [`apace_dom`].
26pub use apace_dom as dom;
27#[doc(inline)]
28/// Re-export of [`apace_html`]. HTML parsing on top of apace-dom
29pub use apace_html as html;
30#[cfg(feature = "net")]
31#[doc(inline)]
32/// Re-export of [`apace_net`].
33pub use apace_net as net;
34#[doc(inline)]
35/// Re-export of [`apace_paint`].
36pub use apace_paint as paint;
37#[doc(inline)]
38/// Re-export of [`apace_shell`].
39pub use apace_shell as shell;
40#[doc(inline)]
41/// Re-export of [`apace_traits`](https://docs.rs/apace-traits). Base types and traits for interoperability between modules
42pub use apace_traits as traits;
43
44#[cfg(feature = "net")]
45#[cfg(not(target_arch = "wasm32"))]
46pub fn launch_url(url: &str) {
47    // Assert that url is valid
48    #[cfg(feature = "tracing")]
49    tracing::info!("Launching {url}");
50    let url = url.to_owned();
51    let url = url::Url::parse(&url).expect("Invalid url");
52
53    // Turn on the runtime and enter it
54    let rt = tokio::runtime::Builder::new_multi_thread()
55        .enable_all()
56        .build()
57        .unwrap();
58    let _guard = rt.enter();
59
60    let event_loop = create_default_event_loop();
61    let (proxy, reciever) = ApaceShellProxy::new(event_loop.create_proxy());
62    let net_provider = create_net_provider(proxy.clone());
63    let application = ApaceApplication::new(proxy, reciever);
64
65    let (url, bytes) = rt
66        .block_on(net_provider.fetch_async(apace_traits::net::Request::get(url)))
67        .unwrap();
68    let html = std::str::from_utf8(bytes.as_ref()).unwrap();
69
70    launch_internal(
71        html,
72        Config {
73            stylesheets: Vec::new(),
74            base_url: Some(url),
75        },
76        event_loop,
77        application,
78        net_provider,
79    )
80}
81
82pub fn launch_static_html(html: &str) {
83    launch_static_html_cfg(html, Config::default())
84}
85
86pub fn launch_static_html_cfg(html: &str, cfg: Config) {
87    // Turn on the runtime and enter it
88    #[cfg(feature = "net")]
89    #[cfg(not(target_arch = "wasm32"))]
90    let rt = tokio::runtime::Builder::new_multi_thread()
91        .enable_all()
92        .build()
93        .unwrap();
94    #[cfg(feature = "net")]
95    #[cfg(not(target_arch = "wasm32"))]
96    let _guard = rt.enter();
97
98    let event_loop = create_default_event_loop();
99    let (proxy, reciever) = ApaceShellProxy::new(event_loop.create_proxy());
100    let net_provider = create_net_provider(proxy.clone());
101    let application = ApaceApplication::new(proxy, reciever);
102
103    launch_internal(html, cfg, event_loop, application, net_provider)
104}
105
106fn launch_internal(
107    html: &str,
108    cfg: Config,
109    event_loop: EventLoop,
110    mut application: ApaceApplication<WindowRenderer>,
111    net_provider: Arc<dyn NetProvider>,
112) {
113    let doc = HtmlDocument::from_html(
114        html,
115        DocumentConfig {
116            base_url: cfg.base_url,
117            ua_stylesheets: std::iter::once(UserAgentStylesheet::default_sheet())
118                .chain(
119                    cfg.stylesheets
120                        .iter()
121                        .map(|css| UserAgentStylesheet::parse(css)),
122                )
123                .collect(),
124            net_provider: Some(net_provider),
125            ..Default::default()
126        },
127    );
128    let renderer = WindowRenderer::new();
129    let window = WindowConfig::new(Box::new(doc) as _, renderer);
130
131    // Create application
132
133    application.add_window(window);
134
135    // Run event loop
136    event_loop.run_app(application).unwrap()
137}
138
139#[cfg(feature = "net")]
140type EnabledNetProvider = apace_net::Provider;
141#[cfg(not(feature = "net"))]
142type EnabledNetProvider = apace_traits::net::DummyNetProvider;
143
144fn create_net_provider(proxy: ApaceShellProxy) -> Arc<EnabledNetProvider> {
145    #[cfg(feature = "net")]
146    let net_provider = Arc::new(apace_net::Provider::new(Some(Arc::new(proxy))));
147    #[cfg(not(feature = "net"))]
148    let net_provider = {
149        use apace_traits::net::DummyNetProvider;
150
151        // This isn't used without the net feature, so ignore it here to not
152        // get unnused warnings.
153        let _ = event_loop;
154        Arc::new(DummyNetProvider::default())
155    };
156
157    net_provider
158}