Selaa lähdekoodia

feature: import official webview rust binding (#846)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Ngo Iok Ui (Wu Yu Wei) 5 vuotta sitten
vanhempi
sitoutus
cd5b401707

+ 8 - 0
.changes/tauri-webview.md

@@ -0,0 +1,8 @@
+---
+"tauri": minor
+---
+
+Moving the webview implementation to [webview](https://github.com/webview/webview), with the [official Rust binding](https://github.com/webview/webview_rust).
+This is a breaking change.
+IE support has been dropped, so the `edge` object on `tauri.conf.json > tauri` no longer exists and you need to remove it.
+`webview.handle()` has been replaced with `webview.as_mut()`.

+ 3 - 3
cli/tauri.js/api-src/tauri.ts

@@ -1,6 +1,6 @@
 declare global {
-  interface External {
-    invoke: (command: string) => void
+  interface Window {
+    __TAURI_INVOKE_HANDLER__: (command: string) => void
   }
 }
 
@@ -21,7 +21,7 @@ function uid(): string {
  * @param args
  */
 function invoke(args: any): void {
-  window.external.invoke(typeof args === 'object' ? JSON.stringify(args) : args)
+  window.__TAURI_INVOKE_HANDLER__(args)
 }
 
 function transformCallback(callback?: (response: any) => void, once = false): string {

+ 0 - 4
cli/tauri.js/src/api/info.ts

@@ -192,10 +192,6 @@ async function printAppInfo(tauriDir: string): Promise<void> {
       key: '  CSP',
       value: config.tauri.security ? config.tauri.security.csp : 'unset'
     })
-    printInfo({
-      key: '  Windows',
-      value: config.tauri.edge?.active ? 'Edge' : 'MSHTML'
-    })
     printInfo({
       key: '  distDir',
       value: config.build

+ 0 - 3
cli/tauri.js/src/helpers/tauri-config.ts

@@ -54,9 +54,6 @@ const getTauriConfig = (cfg: Partial<TauriConfig>): TauriConfig => {
         security: {
           csp: "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
         },
-        edge: {
-          active: true
-        },
         inliner: {
           active: true
         }

+ 1 - 5
cli/tauri.js/src/runner.ts

@@ -117,7 +117,7 @@ class Runner {
             self.__parseHtml(cfg, indexDir, false)
               .then(({ html }) => {
                 const headers: { [key: string]: string } = {}
-                if(proxyRes.headers['content-type']) {
+                if (proxyRes.headers['content-type']) {
                   headers['content-type'] = proxyRes.headers['content-type']
                 } else {
                   const charsetMatch = /charset="(\S+)"/g.exec(bodyStr)
@@ -527,10 +527,6 @@ class Runner {
       tomlFeatures.push(...whitelist.map(toKebabCase))
     }
 
-    if (cfg.tauri.edge.active) {
-      tomlFeatures.push('edge')
-    }
-
     if (cfg.tauri.cli) {
       tomlFeatures.push('cli')
     }

+ 0 - 3
cli/tauri.js/src/template/defaultConfig.ts

@@ -45,9 +45,6 @@ export default {
     security: {
       csp: "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
     },
-    edge: {
-      active: true
-    },
     inliner: {
       active: true
     }

+ 0 - 12
cli/tauri.js/src/types/config.schema.json

@@ -391,17 +391,6 @@
           "$ref": "#/definitions/CliConfig",
           "description": "app's CLI definition"
         },
-        "edge": {
-          "additionalProperties": false,
-          "defaultProperties": [
-          ],
-          "properties": {
-            "active": {
-              "type": "boolean"
-            }
-          },
-          "type": "object"
-        },
         "embeddedServer": {
           "additionalProperties": false,
           "defaultProperties": [
@@ -496,7 +485,6 @@
       },
       "required": [
         "bundle",
-        "edge",
         "embeddedServer",
         "inliner",
         "security",

+ 0 - 3
cli/tauri.js/src/types/config.ts

@@ -285,9 +285,6 @@ export interface TauriConfig {
     security: {
       csp?: string
     }
-    edge: {
-      active?: boolean
-    }
     inliner: {
       active?: boolean
     }

+ 0 - 12
cli/tauri.js/src/types/config.validator.ts

@@ -401,17 +401,6 @@ export const TauriConfigSchema = {
           "$ref": "#/definitions/CliConfig",
           "description": "app's CLI definition"
         },
-        "edge": {
-          "additionalProperties": false,
-          "defaultProperties": [
-          ],
-          "properties": {
-            "active": {
-              "type": "boolean"
-            }
-          },
-          "type": "object"
-        },
         "embeddedServer": {
           "additionalProperties": false,
           "defaultProperties": [
@@ -506,7 +495,6 @@ export const TauriConfigSchema = {
       },
       "required": [
         "bundle",
-        "edge",
         "embeddedServer",
         "inliner",
         "security",

+ 24 - 42
cli/tauri.js/templates/tauri.js

@@ -6,31 +6,29 @@ if (!String.prototype.startsWith) {
   }
 }
 
-// makes the window.external.invoke API available after window.location.href changes
-switch (navigator.platform) {
-  case "Macintosh":
-  case "MacPPC":
-  case "MacIntel":
-  case "Mac68K":
-    window.external = this
-    invoke = function (x) {
-      webkit.messageHandlers.invoke.postMessage(x);
-    }
-    break;
-  case "Windows":
-  case "WinCE":
-  case "Win32":
-  case "Win64":
-    break;
-  default:
-    window.external = this
-    invoke = function (x) {
-      window.webkit.messageHandlers.external.postMessage(x);
+(function () {
+  function webviewBind (name) {
+    var RPC = window._rpc = (window._rpc || { nextSeq: 1 });
+    window[name] = function () {
+      var seq = RPC.nextSeq++;
+      var promise = new Promise(function (resolve, reject) {
+        RPC[seq] = {
+          resolve: resolve,
+          reject: reject,
+        };
+      });
+      window.external.invoke(JSON.stringify({
+        id: seq,
+        method: name,
+        params: Array.prototype.slice.call(arguments),
+      }));
+      return promise;
     }
-    break;
-}
+  }
+  if (!window.__TAURI_INVOKE_HANDLER__) {
+    webviewBind('__TAURI_INVOKE_HANDLER__')
+  }
 
-(function () {
   function s4() {
     return Math.floor((1 + Math.random()) * 0x10000)
       .toString(16)
@@ -89,9 +87,6 @@ switch (navigator.platform) {
   if (!window.__TAURI__) {
     window.__TAURI__ = {}
   }
-  window.__TAURI__.invoke = function invoke(args) {
-    window.external.invoke(JSON.stringify(args))
-  }
 
   window.__TAURI__.transformCallback = function transformCallback(callback) {
     var once = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false
@@ -109,10 +104,10 @@ switch (navigator.platform) {
   }
 
   window.__TAURI__.promisified = function promisified(args) {
-    var _this = this;
+    var _this = this
 
     return new Promise(function (resolve, reject) {
-      _this.invoke(_objectSpread({
+      window.__TAURI_INVOKE_HANDLER__(_objectSpread({
         callback: _this.transformCallback(resolve),
         error: _this.transformCallback(reject)
       }, args))
@@ -127,19 +122,6 @@ switch (navigator.platform) {
     })
   }
 
-  // init tauri API
-  try {
-    window.__TAURI__.invoke({
-      cmd: 'init'
-    })
-  } catch (e) {
-    window.addEventListener('DOMContentLoaded', function () {
-      window.__TAURI__.invoke({
-        cmd: 'init'
-      })
-    }, true)
-  }
-
   document.addEventListener('error', function (e) {
     var target = e.target
     while (target != null) {
@@ -161,7 +143,7 @@ switch (navigator.platform) {
       while (target != null) {
         if (target.matches ? target.matches('a') : target.msMatchesSelector('a')) {
           if (target.href && target.href.startsWith('http') && target.target === '_blank') {
-            window.__TAURI__.invoke({
+            window.__TAURI_INVOKE_HANDLER__({
               cmd: 'open',
               uri: target.href
             })

+ 3 - 4
tauri/Cargo.toml

@@ -20,8 +20,7 @@ features = [ "all-api" ]
 [dependencies]
 serde_json = "1.0"
 serde = { version = "1.0", features = [ "derive" ] }
-tauri-webview-sys = "0.5.0"
-tauri-web-view = "0.6.2"
+webview_rust = { version = "0.1", git = "https://github.com/webview/webview_rust.git", branch = "dev" }
 tauri_includedir = "0.6.0"
 phf = "0.8.0"
 base64 = "0.12.3"
@@ -35,6 +34,7 @@ thiserror = "1.0.20"
 envmnt = "0.8.3"
 once_cell = "1.4.0"
 tauri-api = { version = "0.7", path = "../tauri-api" }
+urlencoding = "1.1.1"
 
 [target."cfg(target_os = \"windows\")".dependencies]
 runas = "0.2"
@@ -46,12 +46,11 @@ cfg_aliases = "0.1.0"
 [dev-dependencies]
 proptest = "0.10.0"
 serde_json = "1.0"
-tauri = { path = ".", features = [ "all-api", "edge" ] }
+tauri = { path = ".", features = [ "all-api" ] }
 serde = { version = "1.0", features = [ "derive" ] }
 
 [features]
 cli = [ "tauri-api/cli" ]
-edge = [ "tauri-web-view/edge" ]
 embedded-server = [ "tiny_http" ]
 no-server = [ ]
 all-api = [ "tauri-api/notification" ]

+ 2 - 2
tauri/examples/communication/dist/communication.js

@@ -1,5 +1,5 @@
 document.getElementById('log').addEventListener('click', function () {
-  window.__TAURI__.invoke({
+  window.__TAURI__.tauri.invoke({
     cmd: 'logOperation',
     event: 'tauri-click',
     payload: 'this payload is optional because we used Option in Rust'
@@ -7,7 +7,7 @@ document.getElementById('log').addEventListener('click', function () {
 })
 
 document.getElementById('request').addEventListener('click', function () {
-  window.__TAURI__.promisified({
+  window.__TAURI__.tauri.promisified({
     cmd: 'performRequest',
     endpoint: 'dummy endpoint arg',
     body: {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
tauri/examples/communication/dist/index.tauri.html


+ 1 - 1
tauri/examples/communication/src-tauri/Cargo.toml

@@ -24,7 +24,7 @@ icon = [
 [dependencies]
 serde_json = "1.0"
 serde = { version = "1.0", features = [ "derive" ] }
-tauri = { path = "../../..", features = [ "all-api", "edge", "cli" ] }
+tauri = { path = "../../..", features = [ "all-api", "cli" ] }
 
 [target."cfg(windows)".build-dependencies]
 winres = "0.1"

+ 2 - 2
tauri/examples/communication/src-tauri/src/main.rs

@@ -15,14 +15,14 @@ struct Reply {
 fn main() {
   tauri::AppBuilder::new()
     .setup(|webview, _source| {
-      let handle = webview.handle();
+      let mut webview = webview.as_mut();
       tauri::event::listen(String::from("js-event"), move |msg| {
         println!("got js-event with message '{:?}'", msg);
         let reply = Reply {
           data: "something else".to_string(),
         };
 
-        tauri::event::emit(&handle, String::from("rust-event"), Some(reply))
+        tauri::event::emit(&mut webview, String::from("rust-event"), Some(reply))
           .expect("failed to emit");
       });
     })

+ 0 - 3
tauri/examples/communication/src-tauri/tauri.conf.json

@@ -55,9 +55,6 @@
     "security": {
       "csp": "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
     },
-    "edge": {
-      "active": true
-    },
     "inliner": {
       "active": true
     }

+ 7 - 7
tauri/src/app.rs

@@ -1,9 +1,9 @@
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 mod runner;
 
-type InvokeHandler = Box<dyn FnMut(&mut WebView<'_, ()>, &str) -> Result<(), String>>;
-type Setup = Box<dyn FnMut(&mut WebView<'_, ()>, String)>;
+type InvokeHandler = Box<dyn FnMut(&mut Webview, &str) -> Result<(), String>>;
+type Setup = Box<dyn FnMut(&mut Webview, String)>;
 
 /// The application runner.
 pub struct App {
@@ -26,7 +26,7 @@ impl App {
   /// The message is considered consumed if the handler exists and returns an Ok Result.
   pub(crate) fn run_invoke_handler(
     &mut self,
-    webview: &mut WebView<'_, ()>,
+    webview: &mut Webview,
     arg: &str,
   ) -> Result<bool, String> {
     if let Some(ref mut invoke_handler) = self.invoke_handler {
@@ -37,7 +37,7 @@ impl App {
   }
 
   /// Runs the setup callback if defined.
-  pub(crate) fn run_setup(&mut self, webview: &mut WebView<'_, ()>, source: String) {
+  pub(crate) fn run_setup(&mut self, webview: &mut Webview, source: String) {
     if let Some(ref mut setup) = self.setup {
       setup(webview, source);
     }
@@ -71,7 +71,7 @@ impl AppBuilder {
   }
 
   /// Defines the JS message handler callback.
-  pub fn invoke_handler<F: FnMut(&mut WebView<'_, ()>, &str) -> Result<(), String> + 'static>(
+  pub fn invoke_handler<F: FnMut(&mut Webview, &str) -> Result<(), String> + 'static>(
     mut self,
     invoke_handler: F,
   ) -> Self {
@@ -80,7 +80,7 @@ impl AppBuilder {
   }
 
   /// Defines the setup callback.
-  pub fn setup<F: FnMut(&mut WebView<'_, ()>, String) + 'static>(mut self, setup: F) -> Self {
+  pub fn setup<F: FnMut(&mut Webview, String) + 'static>(mut self, setup: F) -> Self {
     self.setup = Some(Box::new(setup));
     self
   }

+ 164 - 91
tauri/src/app/runner.rs

@@ -7,13 +7,19 @@ use std::{
   thread::spawn,
 };
 
-use web_view::{builder, Content, WebView};
+use webview_rust_sys::{SizeHint, Webview, WebviewBuilder};
 
 use super::App;
 #[cfg(embedded_server)]
 use crate::api::tcp::{get_available_port, port_is_available};
 use tauri_api::config::get;
 
+#[allow(dead_code)]
+enum Content<T> {
+  Html(T),
+  Url(T),
+}
+
 /// Main entry point for running the Webview
 pub(crate) fn run(application: &mut App) -> crate::Result<()> {
   // setup the content using the config struct depending on the compile target
@@ -56,7 +62,7 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
   spawn_updater()?;
 
   // run the webview
-  webview.run()?;
+  webview.run();
 
   Ok(())
 }
@@ -99,7 +105,10 @@ fn setup_content() -> crate::Result<Content<String>> {
         dev_dir
       );
     }
-    Ok(Content::Html(read_to_string(dev_path)?))
+    Ok(Content::Html(format!(
+      "data:text/html,{}",
+      urlencoding::encode(&read_to_string(dev_path)?)
+    )))
   }
 }
 
@@ -121,7 +130,10 @@ fn setup_content() -> crate::Result<Content<String>> {
 #[cfg(no_server)]
 fn setup_content() -> crate::Result<Content<String>> {
   let html = include_str!(concat!(env!("OUT_DIR"), "/index.tauri.html"));
-  Ok(Content::Html(html.to_string()))
+  Ok(Content::Html(format!(
+    "data:text/html,{}",
+    urlencoding::encode(html)
+  )))
 }
 
 // get the port for the embedded server
@@ -182,12 +194,49 @@ fn spawn_updater() -> crate::Result<()> {
   Ok(())
 }
 
+pub fn init() -> String {
+  #[cfg(not(event))]
+  return String::from("");
+  #[cfg(event)]
+  return format!(
+    "
+      window['{queue}'] = [];
+      window['{fn}'] = function (payload, salt, ignoreQueue) {{
+      const listeners = (window['{listeners}'] && window['{listeners}'][payload.type]) || []
+      if (!ignoreQueue && listeners.length === 0) {{
+        window['{queue}'].push({{
+          payload: payload,
+          salt: salt
+        }})
+      }}
+
+      if (listeners.length > 0) {{
+        window.__TAURI__.promisified({{
+          cmd: 'validateSalt',
+          salt: salt
+        }}).then(function () {{
+          for (let i = listeners.length - 1; i >= 0; i--) {{
+            const listener = listeners[i]
+            if (listener.once)
+              listeners.splice(i, 1)
+            listener.handler(payload)
+          }}
+        }})
+      }}
+    }}
+    ",
+    fn = crate::event::emit_function_name(),
+    queue = crate::event::event_queue_object_name(),
+    listeners = crate::event::event_listeners_object_name()
+  );
+}
+
 // build the webview struct
 fn build_webview(
   application: &mut App,
   content: Content<String>,
   splashscreen_content: Option<Content<String>>,
-) -> crate::Result<WebView<'_, ()>> {
+) -> crate::Result<Webview> {
   let config = get()?;
   let content_clone = match content {
     Content::Html(ref html) => Content::Html(html.clone()),
@@ -197,106 +246,122 @@ fn build_webview(
   // get properties from config struct
   let width = config.tauri.window.width;
   let height = config.tauri.window.height;
-  let resizable = config.tauri.window.resizable;
-  let fullscreen = config.tauri.window.fullscreen;
+  let resizable = if config.tauri.window.resizable {
+    SizeHint::NONE
+  } else {
+    SizeHint::FIXED
+  };
+  // let fullscreen = config.tauri.window.fullscreen;
   let title = config.tauri.window.title.clone().into_boxed_str();
 
   let has_splashscreen = splashscreen_content.is_some();
   let mut initialized_splashscreen = false;
+  let url = match splashscreen_content {
+    Some(Content::Html(s)) => s,
+    _ => match content {
+      Content::Html(s) => s,
+      Content::Url(s) => s,
+    },
+  };
 
-  let mut webview = builder()
+  let mut webview = WebviewBuilder::new()
+    .init(&format!(
+      r#"
+        {event_init}
+        if (window.__TAURI_INVOKE_HANDLER__) {{
+          window.__TAURI_INVOKE_HANDLER__({{ cmd: "__initialized" }})
+        }} else {{
+          window.addEventListener('DOMContentLoaded', function () {{
+            window.__TAURI_INVOKE_HANDLER__({{ cmd: "__initialized" }})
+          }})
+        }}
+      "#,
+      event_init = init()
+    ))
     .title(Box::leak(title))
-    .size(width, height)
-    .resizable(resizable)
+    .width(width as usize)
+    .height(height as usize)
+    .resize(resizable)
     .debug(debug)
-    .user_data(())
-    .invoke_handler(move |webview, arg| {
-      if arg == r#"{"cmd":"__initialized"}"# {
-        let source = if has_splashscreen && !initialized_splashscreen {
-          initialized_splashscreen = true;
-          "splashscreen"
-        } else {
-          "window-1"
-        };
-        application.run_setup(webview, source.to_string());
-        if source == "window-1" {
-          let handle = webview.handle();
-          handle
-            .dispatch(|webview| {
-              crate::plugin::ready(webview);
-              Ok(())
-            })
-            .expect("failed to invoke ready hook");
-        }
-      } else if arg == r#"{"cmd":"closeSplashscreen"}"# {
-        let content_href = match content_clone {
-          Content::Html(ref html) => html,
-          Content::Url(ref url) => url,
-        };
-        webview.eval(&format!(r#"window.location.href = "{}""#, content_href))?;
+    .url(&url)
+    .build();
+  // TODO waiting for webview window API
+  // webview.set_fullscreen(fullscreen);
+
+  if has_splashscreen {
+    let env_var = envmnt::get_or("TAURI_DIR", "../dist");
+    let path = Path::new(&env_var);
+    let contents = fs::read_to_string(path.join("/tauri.js"))?;
+    // inject the tauri.js entry point
+    webview.dispatch(move |_webview| _webview.eval(&contents));
+  }
+
+  let mut w = webview.clone();
+  webview.bind("__TAURI_INVOKE_HANDLER__", move |_, arg| {
+    // transform `[payload]` to `payload`
+    let arg = arg.chars().skip(1).take(arg.len() - 2).collect::<String>();
+    if arg == r#"{"cmd":"__initialized"}"# {
+      let source = if has_splashscreen && !initialized_splashscreen {
+        initialized_splashscreen = true;
+        "splashscreen"
       } else {
-        let endpoint_handle = crate::endpoints::handle(webview, arg)
-          .map_err(|tauri_handle_error| {
-            let tauri_handle_error_str = tauri_handle_error.to_string();
-            if tauri_handle_error_str.contains("unknown variant") {
-              match application.run_invoke_handler(webview, arg) {
-                Ok(handled) => {
-                  if handled {
-                    String::from("")
-                  } else {
-                    tauri_handle_error_str
-                  }
+        "window-1"
+      };
+      application.run_setup(&mut w, source.to_string());
+      if source == "window-1" {
+        w.dispatch(|w| {
+          crate::plugin::ready(w);
+        });
+      }
+    } else if arg == r#"{"cmd":"closeSplashscreen"}"# {
+      let content_href = match content_clone {
+        Content::Html(ref html) => html,
+        Content::Url(ref url) => url,
+      };
+      w.eval(&format!(r#"window.location.href = "{}""#, content_href));
+    } else {
+      let endpoint_handle = crate::endpoints::handle(&mut w, &arg)
+        .map_err(|tauri_handle_error| {
+          let tauri_handle_error_str = tauri_handle_error.to_string();
+          if tauri_handle_error_str.contains("unknown variant") {
+            match application.run_invoke_handler(&mut w, &arg) {
+              Ok(handled) => {
+                if handled {
+                  String::from("")
+                } else {
+                  tauri_handle_error_str
                 }
-                Err(e) => e,
               }
-            } else {
-              tauri_handle_error_str
+              Err(e) => e,
             }
-          })
-          .map_err(|app_handle_error| {
-            if app_handle_error.contains("unknown variant") {
-              match crate::plugin::extend_api(webview, arg) {
-                Ok(handled) => {
-                  if handled {
-                    String::from("")
-                  } else {
-                    app_handle_error
-                  }
+          } else {
+            tauri_handle_error_str
+          }
+        })
+        .map_err(|app_handle_error| {
+          if app_handle_error.contains("unknown variant") {
+            match crate::plugin::extend_api(&mut w, &arg) {
+              Ok(handled) => {
+                if handled {
+                  String::from("")
+                } else {
+                  app_handle_error
                 }
-                Err(e) => e,
               }
-            } else {
-              app_handle_error
+              Err(e) => e,
             }
-          })
-          .map_err(|e| e.replace("'", "\\'"));
-        if let Err(handler_error_message) = endpoint_handle {
-          if handler_error_message != "" {
-            webview.eval(&get_api_error_message(arg, handler_error_message))?;
+          } else {
+            app_handle_error
           }
+        })
+        .map_err(|e| e.replace("'", "\\'"));
+      if let Err(handler_error_message) = endpoint_handle {
+        if handler_error_message != "" {
+          w.eval(&get_api_error_message(&arg, handler_error_message));
         }
       }
-
-      Ok(())
-    })
-    .content(if splashscreen_content.is_some() {
-      splashscreen_content.expect("failed to get splashscreen content")
-    } else {
-      content
-    })
-    .build()?;
-
-  webview.set_fullscreen(fullscreen);
-
-  if has_splashscreen {
-    let env_var = envmnt::get_or("TAURI_DIR", "../dist");
-    let path = Path::new(&env_var);
-    let contents = fs::read_to_string(path.join("/tauri.js"))?;
-    // inject the tauri.js entry point
-    webview
-      .handle()
-      .dispatch(move |_webview| _webview.eval(&contents))?;
-  }
+    }
+  });
 
   Ok(webview)
 }
@@ -312,9 +377,9 @@ fn get_api_error_message(arg: &str, handler_error_message: String) -> String {
 
 #[cfg(test)]
 mod test {
+  use super::Content;
   use proptest::prelude::*;
   use std::env;
-  use web_view::Content;
 
   #[cfg(not(feature = "embedded-server"))]
   use std::{fs::read_to_string, path::Path};
@@ -351,7 +416,12 @@ mod test {
         };
         assert_eq!(
           s,
-          read_to_string(Path::new(&dist_dir).join("index.tauri.html")).unwrap()
+          format!(
+            "data:text/html,{}",
+            urlencoding::encode(
+              &read_to_string(Path::new(&dist_dir).join("index.tauri.html")).unwrap()
+            )
+          )
         );
       }
       _ => panic!("setup content failed"),
@@ -367,7 +437,10 @@ mod test {
           let dev_path = Path::new(dev_dir).join("index.tauri.html");
           assert_eq!(
             s,
-            read_to_string(dev_path).expect("failed to read dev path")
+            format!(
+              "data:text/html,{}",
+              urlencoding::encode(&read_to_string(dev_path).expect("failed to read dev path"))
+            )
           );
         }
         _ => panic!("setup content failed"),

+ 9 - 47
tauri/src/endpoints.rs

@@ -1,11 +1,8 @@
 mod cmd;
 #[allow(unused_imports)]
 mod file_system;
-mod init;
 mod salt;
 
-use init::init;
-
 #[cfg(assets)]
 mod asset;
 #[cfg(open)]
@@ -19,24 +16,15 @@ mod http;
 #[cfg(notification)]
 mod notification;
 
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 #[allow(unused_variables)]
-pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> crate::Result<()> {
+pub(crate) fn handle(webview: &mut Webview, arg: &str) -> crate::Result<()> {
   use cmd::Cmd::*;
   match serde_json::from_str(arg) {
     Err(e) => Err(e.into()),
     Ok(command) => {
       match command {
-        Init {} => {
-          let event_init = init()?;
-          webview.eval(&format!(
-            r#"{event_init}
-                window.external.invoke('{{"cmd":"__initialized"}}')
-              "#,
-            event_init = event_init
-          ))?;
-        }
         ReadTextFile {
           path,
           options,
@@ -153,7 +141,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
         }
         SetTitle { title } => {
           #[cfg(set_title)]
-          webview.set_title(&title)?;
+          webview.set_title(&title);
           #[cfg(not(set_title))]
           throw_whitelist_error(webview, "title");
         }
@@ -189,7 +177,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
           #[cfg(event)]
           {
             let js_string = event::listen_fn(event, handler, once)?;
-            webview.eval(&js_string)?;
+            webview.eval(&js_string);
           }
           #[cfg(not(event))]
           throw_whitelist_error(webview, "event");
@@ -286,19 +274,13 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
 }
 
 #[allow(dead_code)]
-fn api_error<T: 'static>(webview: &mut WebView<'_, T>, error_fn: String, message: &str) {
+fn api_error(webview: &mut Webview, error_fn: String, message: &str) {
   let reject_code = tauri_api::rpc::format_callback(error_fn, message);
-  webview
-    .eval(&reject_code)
-    .expect("failed to eval api error")
+  webview.eval(&reject_code)
 }
 
 #[allow(dead_code)]
-fn whitelist_error<T: 'static>(
-  webview: &mut WebView<'_, T>,
-  error_fn: String,
-  whitelist_key: &str,
-) {
+fn whitelist_error(webview: &mut Webview, error_fn: String, whitelist_key: &str) {
   api_error(
     webview,
     error_fn,
@@ -310,35 +292,15 @@ fn whitelist_error<T: 'static>(
 }
 
 #[allow(dead_code)]
-fn throw_whitelist_error<T: 'static>(webview: &mut WebView<'_, T>, whitelist_key: &str) {
+fn throw_whitelist_error(webview: &mut Webview, whitelist_key: &str) {
   let reject_code = format!(r#"throw new Error("'{}' not whitelisted")"#, whitelist_key);
-  webview
-    .eval(&reject_code)
-    .expect("failed to eval whitelist error")
+  webview.eval(&reject_code)
 }
 
 #[cfg(test)]
 mod test {
   use proptest::prelude::*;
 
-  #[test]
-  // test to see if check init produces a string or not.
-  fn check_init() {
-    if cfg!(not(event)) {
-      let res = super::init();
-      match res {
-        Ok(s) => assert_eq!(s, ""),
-        Err(e) => panic!("init Err {:?}", e.to_string()),
-      }
-    } else if cfg!(event) {
-      let res = super::init();
-      match res {
-        Ok(s) => assert!(s.contains("window.__TAURI__.promisified")),
-        Err(e) => panic!("init Err {:?}", e.to_string()),
-      }
-    }
-  }
-
   // check the listen_fn for various usecases.
   proptest! {
     #[cfg(event)]

+ 28 - 17
tauri/src/endpoints/asset.rs

@@ -1,14 +1,14 @@
 use std::path::PathBuf;
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
-pub fn load<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn load(
+  webview: &mut Webview,
   asset: String,
   asset_type: String,
   callback: String,
   error: String,
 ) {
-  let handle = webview.handle();
+  let mut webview_mut = webview.as_mut();
   crate::execute_promise(
     webview,
     move || {
@@ -58,19 +58,30 @@ pub fn load<T: 'static>(
           base64::encode(&read_asset.expect("Failed to read asset type").into_owned())
         ))
       } else {
-        handle
-          .dispatch(move |_webview| {
-            let asset_bytes = &read_asset.expect("Failed to read asset type").into_owned();
-            let asset_str =
-              &std::str::from_utf8(asset_bytes).expect("failed to convert asset bytes to u8 slice");
-            if asset_type == "stylesheet" {
-              _webview.inject_css(asset_str)
-            } else {
-              _webview.eval(asset_str)
-            }
-          })
-          .map_err(|err| err.into())
-          .map(|_| "Asset loaded successfully".to_string())
+        let asset_bytes = read_asset.expect("Failed to read asset type");
+        webview_mut.dispatch(move |webview_ref| {
+          let asset_str =
+            std::str::from_utf8(&asset_bytes).expect("failed to convert asset bytes to u8 slice");
+          if asset_type == "stylesheet" {
+            webview_ref.eval(&format!(
+              r#"
+                (function () {{
+                  var css = document.createElement('style')
+                  css.type = 'text/css'
+                  if (css.styleSheet)  
+                      css.styleSheet.cssText = {css}
+                  else  
+                      css.appendChild(document.createTextNode({css}))
+                  document.getElementsByTagName("head")[0].appendChild(css);
+                }})()
+              "#,
+              css = asset_str
+            ));
+          } else {
+            webview_ref.eval(asset_str);
+          }
+        })?;
+        Ok("Asset loaded successfully".to_string())
       }
     },
     callback,

+ 0 - 2
tauri/src/endpoints/cmd.rs

@@ -64,8 +64,6 @@ pub struct NotificationOptions {
 #[derive(Deserialize)]
 #[serde(tag = "cmd", rename_all = "camelCase")]
 pub enum Cmd {
-  /// The init command
-  Init {},
   /// The read text file API.
   ReadTextFile {
     path: PathBuf,

+ 5 - 5
tauri/src/endpoints/dialog.rs

@@ -1,7 +1,7 @@
 use super::cmd::{OpenDialogOptions, SaveDialogOptions};
 use crate::api::dialog::{pick_folder, save_file, select, select_multiple, Response};
 use serde_json::Value as JsonValue;
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 /// maps a dialog response to a JS value to eval
 fn map_response(response: Response) -> JsonValue {
@@ -14,8 +14,8 @@ fn map_response(response: Response) -> JsonValue {
 
 /// Shows an open dialog.
 #[cfg(open_dialog)]
-pub fn open<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn open(
+  webview: &mut Webview,
   options: OpenDialogOptions,
   callback: String,
   error: String,
@@ -40,8 +40,8 @@ pub fn open<T: 'static>(
 
 /// Shows a save dialog.
 #[cfg(save_dialog)]
-pub fn save<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn save(
+  webview: &mut Webview,
   options: SaveDialogOptions,
   callback: String,
   error: String,

+ 21 - 21
tauri/src/endpoints/file_system.rs

@@ -1,4 +1,4 @@
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 use tauri_api::dir;
 use tauri_api::file;
@@ -13,8 +13,8 @@ use super::cmd::{DirOperationOptions, FileOperationOptions};
 
 /// Reads a directory.
 #[cfg(read_dir)]
-pub fn read_dir<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn read_dir(
+  webview: &mut Webview,
   path: PathBuf,
   options: Option<DirOperationOptions>,
   callback: String,
@@ -37,8 +37,8 @@ pub fn read_dir<T: 'static>(
 
 /// Copies a file.
 #[cfg(copy_file)]
-pub fn copy_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn copy_file(
+  webview: &mut Webview,
   source: PathBuf,
   destination: PathBuf,
   options: Option<FileOperationOptions>,
@@ -64,8 +64,8 @@ pub fn copy_file<T: 'static>(
 
 /// Creates a directory.
 #[cfg(create_dir)]
-pub fn create_dir<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn create_dir(
+  webview: &mut Webview,
   path: PathBuf,
   options: Option<DirOperationOptions>,
   callback: String,
@@ -95,8 +95,8 @@ pub fn create_dir<T: 'static>(
 
 /// Removes a directory.
 #[cfg(remove_dir)]
-pub fn remove_dir<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn remove_dir(
+  webview: &mut Webview,
   path: PathBuf,
   options: Option<DirOperationOptions>,
   callback: String,
@@ -126,8 +126,8 @@ pub fn remove_dir<T: 'static>(
 
 /// Removes a file
 #[cfg(remove_file)]
-pub fn remove_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn remove_file(
+  webview: &mut Webview,
   path: PathBuf,
   options: Option<FileOperationOptions>,
   callback: String,
@@ -146,8 +146,8 @@ pub fn remove_file<T: 'static>(
 
 /// Renames a file.
 #[cfg(rename_file)]
-pub fn rename_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn rename_file(
+  webview: &mut Webview,
   old_path: PathBuf,
   new_path: PathBuf,
   options: Option<FileOperationOptions>,
@@ -173,8 +173,8 @@ pub fn rename_file<T: 'static>(
 
 /// Writes a text file.
 #[cfg(write_file)]
-pub fn write_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn write_file(
+  webview: &mut Webview,
   path: PathBuf,
   contents: String,
   options: Option<FileOperationOptions>,
@@ -195,8 +195,8 @@ pub fn write_file<T: 'static>(
 
 /// Writes a binary file.
 #[cfg(write_binary_file)]
-pub fn write_binary_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn write_binary_file(
+  webview: &mut Webview,
   path: PathBuf,
   contents: String,
   options: Option<FileOperationOptions>,
@@ -221,8 +221,8 @@ pub fn write_binary_file<T: 'static>(
 
 /// Reads a text file.
 #[cfg(read_text_file)]
-pub fn read_text_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn read_text_file(
+  webview: &mut Webview,
   path: PathBuf,
   options: Option<FileOperationOptions>,
   callback: String,
@@ -238,8 +238,8 @@ pub fn read_text_file<T: 'static>(
 
 /// Reads a binary file.
 #[cfg(read_binary_file)]
-pub fn read_binary_file<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn read_binary_file(
+  webview: &mut Webview,
   path: PathBuf,
   options: Option<FileOperationOptions>,
   callback: String,

+ 3 - 3
tauri/src/endpoints/http.rs

@@ -1,9 +1,9 @@
 use tauri_api::http::{make_request as request, HttpRequestOptions};
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 /// Makes an HTTP request and resolves the response to the webview
-pub fn make_request<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn make_request(
+  webview: &mut Webview,
   options: HttpRequestOptions,
   callback: String,
   error: String,

+ 0 - 36
tauri/src/endpoints/init.rs

@@ -1,36 +0,0 @@
-pub fn init() -> crate::Result<String> {
-  #[cfg(not(event))]
-  return Ok(String::from(""));
-  #[cfg(event)]
-  return Ok(format!(
-    "
-      window['{queue}'] = [];
-      window['{fn}'] = function (payload, salt, ignoreQueue) {{
-      const listeners = (window['{listeners}'] && window['{listeners}'][payload.type]) || []
-      if (!ignoreQueue && listeners.length === 0) {{
-        window['{queue}'].push({{
-          payload: payload,
-          salt: salt
-        }})
-      }}
-
-      if (listeners.length > 0) {{
-        window.__TAURI__.promisified({{
-          cmd: 'validateSalt',
-          salt: salt
-        }}).then(function () {{
-          for (let i = listeners.length - 1; i >= 0; i--) {{
-            const listener = listeners[i]
-            if (listener.once)
-              listeners.splice(i, 1)
-            listener.handler(payload)
-          }}
-        }})
-      }}
-    }}
-    ",
-    fn = crate::event::emit_function_name(),
-    queue = crate::event::event_queue_object_name(),
-    listeners = crate::event::event_listeners_object_name()
-  ));
-}

+ 5 - 14
tauri/src/endpoints/notification.rs

@@ -1,13 +1,8 @@
 use super::cmd::NotificationOptions;
 use serde_json::Value as JsonValue;
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
-pub fn send<T: 'static>(
-  webview: &mut WebView<'_, T>,
-  options: NotificationOptions,
-  callback: String,
-  error: String,
-) {
+pub fn send(webview: &mut Webview, options: NotificationOptions, callback: String, error: String) {
   crate::execute_promise(
     webview,
     move || {
@@ -26,11 +21,7 @@ pub fn send<T: 'static>(
   );
 }
 
-pub fn is_permission_granted<T: 'static>(
-  webview: &mut WebView<'_, T>,
-  callback: String,
-  error: String,
-) {
+pub fn is_permission_granted(webview: &mut Webview, callback: String, error: String) {
   crate::execute_promise(
     webview,
     move || {
@@ -46,8 +37,8 @@ pub fn is_permission_granted<T: 'static>(
   );
 }
 
-pub fn request_permission<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn request_permission(
+  webview: &mut Webview,
   callback: String,
   error: String,
 ) -> crate::Result<()> {

+ 4 - 4
tauri/src/endpoints/salt.rs

@@ -1,8 +1,8 @@
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 /// Validates a salt.
-pub fn validate<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn validate(
+  webview: &mut Webview,
   salt: String,
   callback: String,
   error: String,
@@ -13,6 +13,6 @@ pub fn validate<T: 'static>(
     Err("Invalid salt")
   };
   let callback_string = crate::api::rpc::format_callback_result(response, callback, error)?;
-  webview.eval(callback_string.as_str())?;
+  webview.eval(callback_string.as_str());
   Ok(())
 }

+ 12 - 14
tauri/src/event.rs

@@ -6,7 +6,7 @@ use lazy_static::lazy_static;
 use once_cell::sync::Lazy;
 use serde::Serialize;
 use serde_json::Value as JsonValue;
-use web_view::Handle;
+use webview_rust_sys::WebviewMut;
 
 /// An event handler.
 struct EventHandler {
@@ -57,8 +57,8 @@ pub fn listen<F: FnMut(Option<String>) + Send + 'static>(id: impl Into<String>,
 }
 
 /// Emits an event to JS.
-pub fn emit<T: 'static, S: Serialize>(
-  webview_handle: &Handle<T>,
+pub fn emit<S: Serialize>(
+  webview: &mut WebviewMut,
   event: impl AsRef<str> + Send + 'static,
   payload: Option<S>,
 ) -> crate::Result<()> {
@@ -70,17 +70,15 @@ pub fn emit<T: 'static, S: Serialize>(
     JsonValue::Null
   };
 
-  webview_handle
-    .dispatch(move |_webview| {
-      _webview.eval(&format!(
-        "window['{}']({{type: '{}', payload: {}}}, '{}')",
-        emit_function_name(),
-        event.as_ref(),
-        js_payload,
-        salt
-      ))
-    })
-    .expect("Failed to dispatch JS from emit");
+  webview.dispatch(move |webview_ref| {
+    webview_ref.eval(&format!(
+      "window['{}']({{type: '{}', payload: {}}}, '{}')",
+      emit_function_name(),
+      event.as_ref(),
+      js_payload,
+      salt
+    ))
+  })?;
 
   Ok(())
 }

+ 16 - 27
tauri/src/lib.rs

@@ -39,8 +39,7 @@ mod salt;
 pub use anyhow::Result;
 pub use app::*;
 pub use tauri_api as api;
-pub use web_view::Handle;
-pub use web_view::WebView;
+pub use webview_rust_sys::{Webview, WebviewMut};
 
 use std::process::Stdio;
 
@@ -61,20 +60,15 @@ pub fn spawn<F: FnOnce() -> () + Send + 'static>(task: F) {
 
 /// Synchronously executes the given task
 /// and evaluates its Result to the JS promise described by the `callback` and `error` function names.
-pub fn execute_promise_sync<
-  T: 'static,
-  R: Serialize,
-  F: FnOnce() -> crate::Result<R> + Send + 'static,
->(
-  webview: &mut WebView<'_, T>,
+pub fn execute_promise_sync<R: Serialize, F: FnOnce() -> crate::Result<R> + Send + 'static>(
+  webview: &mut Webview,
   task: F,
   callback: String,
   error: String,
 ) -> crate::Result<()> {
-  let handle = webview.handle();
   let callback_string =
     format_callback_result(task().map_err(|err| err.to_string()), callback, error)?;
-  handle.dispatch(move |_webview| _webview.eval(callback_string.as_str()))?;
+  webview.dispatch(move |w| w.eval(callback_string.as_str()));
   Ok(())
 }
 
@@ -83,17 +77,13 @@ pub fn execute_promise_sync<
 ///
 /// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value.
 /// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value.
-pub fn execute_promise<
-  T: 'static,
-  R: Serialize,
-  F: FnOnce() -> crate::Result<R> + Send + 'static,
->(
-  webview: &mut WebView<'_, T>,
+pub fn execute_promise<R: Serialize, F: FnOnce() -> crate::Result<R> + Send + 'static>(
+  webview: &mut Webview,
   task: F,
   success_callback: String,
   error_callback: String,
 ) {
-  let handle = webview.handle();
+  let mut webview = webview.as_mut();
   POOL.with(|thread| {
     thread.execute(move || {
       let callback_string = match format_callback_result(
@@ -104,16 +94,16 @@ pub fn execute_promise<
         Ok(callback_string) => callback_string,
         Err(e) => format_callback(error_callback, e.to_string()),
       };
-      handle
-        .dispatch(move |_webview| _webview.eval(callback_string.as_str()))
-        .expect("Failed to dispatch promise callback")
+      webview
+        .dispatch(move |webview_ref| webview_ref.eval(callback_string.as_str()))
+        .expect("Failed to dispatch promise callback");
     });
   });
 }
 
 /// Calls the given command and evaluates its output to the JS promise described by the `callback` and `error` function names.
-pub fn call<T: 'static>(
-  webview: &mut WebView<'_, T>,
+pub fn call(
+  webview: &mut Webview,
   command: String,
   args: Vec<String>,
   callback: String,
@@ -128,11 +118,10 @@ pub fn call<T: 'static>(
 }
 
 /// Closes the splashscreen.
-pub fn close_splashscreen<T: 'static>(webview_handle: &Handle<T>) -> crate::Result<()> {
-  webview_handle.dispatch(|webview| {
-    // send a signal to the runner so it knows that it should redirect to the main app content
-    webview.eval(r#"window.external.invoke(JSON.stringify({ cmd: "closeSplashscreen" }))"#)
-  })?;
+pub fn close_splashscreen(webview: &mut Webview) -> crate::Result<()> {
+  // send a signal to the runner so it knows that it should redirect to the main app content
+  webview.eval(r#"window.__TAURI_INVOKE_HANDLER__({ cmd: "closeSplashscreen" })"#);
+
   Ok(())
 }
 

+ 7 - 7
tauri/src/plugin.rs

@@ -1,19 +1,19 @@
 use std::sync::{Arc, Mutex};
-use web_view::WebView;
+use webview_rust_sys::Webview;
 
 /// The plugin interface.
 pub trait Plugin {
   /// Callback invoked when the webview is created.
   #[allow(unused_variables)]
-  fn created(&self, webview: &mut WebView<'_, ()>) {}
+  fn created(&self, webview: &mut Webview) {}
 
   /// Callback invoked when the webview is ready.
   #[allow(unused_variables)]
-  fn ready(&self, webview: &mut WebView<'_, ()>) {}
+  fn ready(&self, webview: &mut Webview) {}
 
   /// Add invoke_handler API extension commands.
   #[allow(unused_variables)]
-  fn extend_api(&self, webview: &mut WebView<'_, ()>, payload: &str) -> Result<bool, String> {
+  fn extend_api(&self, webview: &mut Webview, payload: &str) -> Result<bool, String> {
     Err("unknown variant".to_string())
   }
 }
@@ -37,19 +37,19 @@ fn run_plugin<T: FnMut(&Box<dyn Plugin>)>(mut callback: T) {
   });
 }
 
-pub(crate) fn created(webview: &mut WebView<'_, ()>) {
+pub(crate) fn created(webview: &mut Webview) {
   run_plugin(|ext| {
     ext.created(webview);
   });
 }
 
-pub(crate) fn ready(webview: &mut WebView<'_, ()>) {
+pub(crate) fn ready(webview: &mut Webview) {
   run_plugin(|ext| {
     ext.ready(webview);
   });
 }
 
-pub(crate) fn extend_api(webview: &mut WebView<'_, ()>, arg: &str) -> Result<bool, String> {
+pub(crate) fn extend_api(webview: &mut Webview, arg: &str) -> Result<bool, String> {
   PLUGINS.with(|plugins| {
     let exts = plugins.lock().unwrap();
     for ext in exts.iter() {

+ 4 - 2
tauri/test/fixture/src-tauri/tauri.conf.json

@@ -19,7 +19,9 @@
     },
     "security": {
       "csp": "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
+    },
+    "inliner": {
+      "active": true
     }
-  },
-  "edge": true
+  }
 }

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä