Repository: tauri-apps/tauri (language: rust)

Issue:
[bug] Unable to call `window.__TAURI_INTERNALS__.invoke` from within an `initialization_script`
Thanks for all your great work!

### Describe the bug

When attempting to call `window.__TAURI_INTERNALS__.invoke` from within an `initialization_script`, I get the following error:

`TypeError: undefined is not an object (evaluating 'window.__TAURI_INTERNALS__.invoke')`

### Reproduction

Here is a minimal reproduction: https://github.com/mattyg/bug-reproduction-tauri-initialization-script-invoke
(the relevant lines are here: https://github.com/mattyg/bug-reproduction-tauri-initialization-script-invoke/blob/f1bf03103b7ebc57b775f15f54a782ad85135f65/tauri-app/src-tauri/src/lib.rs#L10 )

You can see that calling `window.__TAURI_INTERNALS__.invoke` from within an `initialization_script` succeeds only after a short delay.

### Expected behavior

I can call `window.__TAURI_INTERNALS__.invoke` from within an `initialization_script`.

### Full `tauri info` output

```text
[✔] Environment
    - OS: Ubuntu 22.4.0 x86_64 (X64) (i3-gnome on x11)
    ✔ webkit2gtk-4.1: 2.46.5
    ✔ rsvg2: 2.52.5
    ✔ rustc: 1.85.0-nightly (d4025ee45 2024-12-12)
    ✔ cargo: 1.85.0-nightly (20a443231 2024-12-06)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: nightly-x86_64-unknown-linux-gnu (default)
    - node: 21.5.0
    - pnpm: 9.7.1
    - yarn: 1.22.21
    - npm: 10.2.4

[-] Packages
    - tauri 🦀: 2.2.2
    - tauri-build 🦀: 2.0.5
    - wry 🦀: 0.48.1
    - tao 🦀: 0.31.1
    - @tauri-apps/api : 2.2.0
    - @tauri-apps/cli : 2.2.4

[-] Plugins
    - tauri-plugin-opener 🦀: 2.2.4
    - @tauri-apps/plugin-opener : 2.2.4

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../build
    - devUrl: http://localhost:1420/
    - framework: Svelte
    - bundler: Vite
```


### Stack trace

_No response_

### Additional context

_No response_


Discussion / hints:
There's really nothing we can do here I think. The internals are also injected with the initialization script api (there's no way to inject something earlier).
idk, i think i'll close this in favor of https://github.com/tauri-apps/tauri/issues/12348
Okay thanks. I wasn't sure if the internals are injected after the user-defined initialization scripts, and it might be possible to just change the order. Or add an `initialization_script_after` fn to inject a script after the internals.
afaik we cannot influence the order on the webview api level

Fix patch:
diff --git a/.changes/initialization_scripts_order.md b/.changes/initialization_scripts_order.md
new file mode 100644
index 000000000000..5e3b36af58cc
--- /dev/null
+++ b/.changes/initialization_scripts_order.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'patch:bug'
+---
+
+Ensure that tauri's builtin initialization scripts and plugin initialization scripts are executed before any user-added initialization scripts in a webview.
diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs
index 8773600dca2e..99522442a4d7 100644
--- a/crates/tauri/src/manager/webview.rs
+++ b/crates/tauri/src/manager/webview.rs
@@ -150,9 +150,9 @@ impl<R: Runtime> WebviewManager<R> {
     }
     .render_default(&Default::default())?;
 
-    webview_attributes = webview_attributes
-      .initialization_script(
-        r"
+    let mut all_initialization_scripts: Vec<String> = vec![];
+    all_initialization_scripts.push(
+      r"
         Object.defineProperty(window, 'isTauri', {
           value: true,
         });
@@ -164,11 +164,12 @@ impl<R: Runtime> WebviewManager<R> {
             }
           })
         }
-      ",
-      )
-      .initialization_script(&self.invoke_initialization_script)
-      .initialization_script(&format!(
-        r#"
+      "
+      .to_string(),
+    );
+    all_initialization_scripts.push(self.invoke_initialization_script.to_string());
+    all_initialization_scripts.push(format!(
+      r#"
           Object.defineProperty(window.__TAURI_INTERNALS__, 'metadata', {{
             value: {{
               currentWindow: {{ label: {current_window_label} }},
@@ -176,39 +177,47 @@ impl<R: Runtime> WebviewManager<R> {
             }}
           }})
         "#,
-        current_window_label = serde_json::to_string(window_label)?,
-        current_webview_label = serde_json::to_string(&label)?,
-      ))
-      .initialization_script(&self.initialization_script(
-        app_manager,
-        &ipc_init.into_string(),
-        &pattern_init.into_string(),
-        is_init_global,
-        use_https_scheme,
-      )?);
+      current_window_label = serde_json::to_string(window_label)?,
+      current_webview_label = serde_json::to_string(&label)?,
+    ));
+    all_initialization_scripts.push(
+      self
+        .initialization_script(
+          app_manager,
+          &ipc_init.into_string(),
+          &pattern_init.into_string(),
+          is_init_global,
+          use_https_scheme,
+        )?
+        .to_string(),
+    );
 
     for plugin_init_script in plugin_init_scripts {
-      webview_attributes = webview_attributes.initialization_script(&plugin_init_script);
+      all_initialization_scripts.push(plugin_init_script.to_string());
     }
 
     #[cfg(feature = "isolation")]
     if let crate::Pattern::Isolation { schema, .. } = &*app_manager.pattern {
-      webview_attributes = webview_attributes.initialization_script(
-        &IsolationJavascript {
+      all_initialization_scripts.push(
+        IsolationJavascript {
           isolation_src: &crate::pattern::format_real_schema(schema, use_https_scheme),
           style: tauri_utils::pattern::isolation::IFRAME_STYLE,
         }
         .render_default(&Default::default())?
-        .into_string(),
+        .to_string(),
       );
     }
 
     if let Some(plugin_global_api_scripts) = &*app_manager.plugin_global_api_scripts {
       for script in plugin_global_api_scripts.iter() {
-        webview_attributes = webview_attributes.initialization_script(script);
+        all_initialization_scripts.push(script.to_string());
       }
     }
 
+    webview_attributes
+      .initialization_scripts
+      .splice(0..0, all_initialization_scripts);
+
     pending.webview_attributes = webview_attributes;
 
     let mut registered_scheme_protocols = Vec::new();


Test patch: