Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"[javascript]": {
"editor.formatOnSave": false
},
"[html]": {
"editor.formatOnSave": false
},
"dioxus.formatOnSave": "disabled",
// "rust-analyzer.check.workspace": true,
// "rust-analyzer.check.workspace": false,
Expand All @@ -21,4 +24,4 @@
"rust-analyzer.cargo.extraArgs": [
"--tests"
],
}
}
1 change: 1 addition & 0 deletions packages/cli/assets/web/dev.index.html
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,6 @@ <h3 id="__dx-toast-text" class="dx-toast-header-text">Your app is being rebuilt.
</div>
</div>
<div id="main"></div>
<script type="module" async src="/{base_path}/{js_path}"></script>
</body>
</html>
2 changes: 2 additions & 0 deletions packages/cli/assets/web/prod.index.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!DOCTYPE html>
<html>
<head>
<title>{app_title}</title>
Expand All @@ -7,5 +8,6 @@
</head>
<body>
<div id="main"></div>
<script type="module" async src="/{base_path}/{js_path}"></script>
</body>
</html>
68 changes: 26 additions & 42 deletions packages/cli/src/build/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,6 @@ pub(crate) struct BuildRequest {
pub(crate) skip_assets: bool,
pub(crate) wasm_split: bool,
pub(crate) debug_symbols: bool,
pub(crate) inject_loading_scripts: bool,
pub(crate) custom_linker: Option<PathBuf>,
pub(crate) session_cache_dir: Arc<TempDir>,
pub(crate) link_args_file: Arc<NamedTempFile>,
Expand Down Expand Up @@ -761,7 +760,6 @@ impl BuildRequest {
base_path: args.base_path.clone(),
wasm_split: args.wasm_split,
debug_symbols: args.debug_symbols,
inject_loading_scripts: args.inject_loading_scripts,
})
}

Expand Down Expand Up @@ -3354,6 +3352,31 @@ impl BuildRequest {
format!("wasm/{}", asset.file_name().unwrap().to_str().unwrap())
};

// Load and initialize wasm without requiring a separate javascript file.
// This also allows using a strict Content-Security-Policy.
let mut js = std::fs::read(self.wasm_bindgen_js_output_file())?;
writeln!(
js,
r#"
window.__wasm_split_main_initSync = initSync;

// Actually perform the load
__wbg_init({{module_or_path: "/{}/{wasm_path}"}}).then((wasm) => {{
// assign this module to be accessible globally
window.__dx_mainWasm = wasm;
window.__dx_mainInit = __wbg_init;
window.__dx_mainInitSync = initSync;
window.__dx___wbg_get_imports = __wbg_get_imports;

if (wasm.__wbindgen_start == undefined) {{
wasm.main();
}}
}});
"#,
self.base_path_or_default(),
)?;
std::fs::write(self.wasm_bindgen_js_output_file(), js)?;

let js_path = if package_to_asset {
// Register the main.js with the asset system so it bundles in the snippets and optimizes
let name = assets.register_asset(
Expand Down Expand Up @@ -3843,9 +3866,6 @@ impl BuildRequest {
// Inject any resources from the config into the html
self.inject_resources(assets, wasm_path, &mut html)?;

// Inject loading scripts if they are not already present
self.inject_loading_scripts(&mut html);

// Replace any special placeholders in the HTML with resolved values
self.replace_template_placeholders(&mut html, wasm_path, js_path);

Expand Down Expand Up @@ -3936,49 +3956,13 @@ impl BuildRequest {

// Manually inject the wasm file for preloading. WASM currently doesn't support preloading in the manganis asset system
head_resources.push_str(&format!(
"<link rel=\"preload\" as=\"fetch\" type=\"application/wasm\" href=\"/{{base_path}}/assets/{wasm_path}\" crossorigin>"
"<link rel=\"preload\" as=\"fetch\" type=\"application/wasm\" href=\"/{{base_path}}/{wasm_path}\" crossorigin>"
));
Self::replace_or_insert_before("{style_include}", "</head", &head_resources, html);

Ok(())
}

/// Inject loading scripts if they are not already present
fn inject_loading_scripts(&self, html: &mut String) {
// If it looks like we are already loading wasm or the current build opted out of injecting loading scripts, don't inject anything
if !self.inject_loading_scripts || html.contains("__wbindgen_start") {
return;
}

// If not, insert the script
*html = html.replace(
"</body",
r#" <script>
// We can't use a module script here because we need to start the script immediately when streaming
import("/{base_path}/{js_path}").then(
({ default: init, initSync, __wbg_get_imports }) => {
// export initSync in case a split module needs to initialize
window.__wasm_split_main_initSync = initSync;

// Actually perform the load
init({module_or_path: "/{base_path}/{wasm_path}"}).then((wasm) => {
// assign this module to be accessible globally
window.__dx_mainWasm = wasm;
window.__dx_mainInit = init;
window.__dx_mainInitSync = initSync;
window.__dx___wbg_get_imports = __wbg_get_imports;

if (wasm.__wbindgen_start == undefined) {
wasm.main();
}
});
}
);
</script>
</body"#,
);
}

/// Replace any special placeholders in the HTML with resolved values
fn replace_template_placeholders(&self, html: &mut String, wasm_path: &str, js_path: &str) {
let base_path = self.base_path_or_default();
Expand Down
4 changes: 0 additions & 4 deletions packages/cli/src/cli/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ pub(crate) struct TargetArgs {
#[serde(default)]
pub(crate) skip_assets: bool,

/// Inject scripts to load the wasm and js files for your dioxus app if they are not already present [default: true]
#[clap(long, default_value_t = true)]
pub(crate) inject_loading_scripts: bool,

/// Experimental: Bundle split the wasm binary into multiple chunks based on `#[wasm_split]` annotations [default: false]
#[clap(long, default_value_t = false)]
pub(crate) wasm_split: bool,
Expand Down
1 change: 1 addition & 0 deletions packages/web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ features = [
"History",
"HtmlElement",
"HtmlFormElement",
"HtmlHeadElement",
"HtmlInputElement",
"HtmlSelectElement",
"HtmlTextAreaElement",
Expand Down
57 changes: 39 additions & 18 deletions packages/web/src/document.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use dioxus_core::prelude::queue_effect;
use dioxus_core::ScopeId;
use dioxus_document::{
create_element_in_head, Document, Eval, EvalError, Evaluator, LinkProps, MetaProps,
ScriptProps, StyleProps,
Document, Eval, EvalError, Evaluator, LinkProps, MetaProps, ScriptProps, StyleProps,
};
use dioxus_history::History;
use futures_util::FutureExt;
Expand Down Expand Up @@ -97,41 +96,63 @@ impl Document for WebDocument {

/// Create a new meta tag in the head
fn create_meta(&self, props: MetaProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head("meta", &props.attributes(), None));
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let head = document.head().expect("document should have a head");

let element = document.create_element("meta").unwrap();
for (name, value) in props.attributes() {
element.set_attribute(name, &value).unwrap();
}
head.append_child(&element).unwrap();
});
}

/// Create a new script tag in the head
fn create_script(&self, props: ScriptProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head(
"script",
&props.attributes(),
props.script_contents().ok(),
));
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let head = document.head().expect("document should have a head");

let element = document.create_element("script").unwrap();
for (name, value) in props.attributes() {
element.set_attribute(name, &value).unwrap();
}
element.set_text_content(props.script_contents().ok().as_deref());
head.append_child(&element).unwrap();
});
}

/// Create a new style tag in the head
fn create_style(&self, props: StyleProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head(
"style",
&props.attributes(),
props.style_contents().ok(),
));
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let head = document.head().expect("document should have a head");

let element = document.create_element("style").unwrap();
for (name, value) in props.attributes() {
element.set_attribute(name, &value).unwrap();
}
element.set_text_content(props.style_contents().ok().as_deref());
head.append_child(&element).unwrap();
});
}

/// Create a new link tag in the head
fn create_link(&self, props: LinkProps) {
let myself = self.clone();
queue_effect(move || {
myself.eval(create_element_in_head("link", &props.attributes(), None));
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let head = document.head().expect("document should have a head");

let element = document.create_element("link").unwrap();
for (name, value) in props.attributes() {
element.set_attribute(name, &value).unwrap();
}
head.append_child(&element).unwrap();
});
}
}
Expand Down
Loading