capacitor icon indicating copy to clipboard operation
capacitor copied to clipboard

bug: log vue 3 warn cause error on iOS

Open bazuka5801 opened this issue 2 years ago • 6 comments

Bug Report

Continue #6545

Capacitor Version

5.02

Platform(s)

iOS

Current Behavior

No default value! Just watch my debugging video

https://github.com/ionic-team/capacitor/assets/11452353/1c642056-4c6b-438c-84b0-b08d3029aab9

Emulator: image

Expected Behavior

Just see original error from vue instead No default value, it's not a vue error. Capacitor must not skip my console.warn args, it's abuse!

Expected output (safari) image

Code Reproduction

https://github.com/bazuka5801/capacitor-error

Other Technical Details

npm --version output: latest

node --version output: latest

pod --version output (iOS issues only): latest

Additional Context

bazuka5801 avatar May 25 '23 22:05 bazuka5801

native-bridge.patch I fixed this problem my way, it works, without any No default value and infinite enumeration of vue objects (which causes infinite console spam).

I added hasSkipFlag method, which is not included in vue sources, if we don't check __v_skip flag, the code will try to serialize the vue object, which will cause infinite spam.

Diff in text

diff --git a/core/native-bridge.ts b/core/native-bridge.ts
index b910e08b..859d37f6 100644
--- a/core/native-bridge.ts
+++ b/core/native-bridge.ts
@@ -17,6 +17,43 @@ import { CapacitorException } from './src/util';
 // eslint-disable-next-line
 let dummy = {};
 
+interface Target {
+  [ReactiveFlags.SKIP]?: boolean
+  [ReactiveFlags.IS_REACTIVE]?: boolean
+  [ReactiveFlags.IS_READONLY]?: boolean
+  [ReactiveFlags.IS_SHALLOW]?: boolean
+  [ReactiveFlags.RAW]?: any
+}
+const enum ReactiveFlags {
+  SKIP = '__v_skip',
+  IS_REACTIVE = '__v_isReactive',
+  IS_READONLY = '__v_isReadonly',
+  IS_SHALLOW = '__v_isShallow',
+  RAW = '__v_raw'
+}
+function isReactive(value: unknown): boolean {
+  if (isReadonly(value)) {
+    return isReactive((value as Target)[ReactiveFlags.RAW])
+  }
+  return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
+}
+function isReadonly(value: unknown): boolean {
+  return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
+}
+
+
+function hasSkipFlag(value: unknown): boolean {
+  return !!(value && (value as Target)[ReactiveFlags.SKIP])
+}
+
+function isProxy(value: unknown): boolean {
+  return isReactive(value) || isReadonly(value)
+}
+
+function isVueProxy(value: unknown) {
+  return hasSkipFlag(value) || isProxy(value)
+}
+
 const initBridge = (w: any): void => {
   const getPlatformId = (win: WindowCapacitor): 'android' | 'ios' | 'web' => {
     if (win?.androidBridge) {
@@ -277,6 +314,9 @@ const initBridge = (w: any): void => {
     };
 
     const serializeConsoleMessage = (msg: any): string => {
+      if (isVueProxy(msg)) {
+        return ''
+      }
       if (typeof msg === 'object') {
         try {
           msg = JSON.stringify(msg);
@@ -285,7 +325,13 @@ const initBridge = (w: any): void => {
         }
       }
 
-      return String(msg);
+      // https://github.com/ionic-team/capacitor/issues/6615
+      // String constructor may cause error (ex. msg is Proxy, created by Vue)
+      try {
+        return String(msg);
+      } catch (e) {
+        return '';
+      }
     };
 
     const platform = getPlatformId(win);

bazuka5801 avatar May 25 '23 23:05 bazuka5801

I can provide a minimal code version of fix

diff --git a/core/native-bridge.ts b/core/native-bridge.ts
index b910e08b..c6822aab 100644
--- a/core/native-bridge.ts
+++ b/core/native-bridge.ts
@@ -17,6 +17,11 @@ import { CapacitorException } from './src/util';
 // eslint-disable-next-line
 let dummy = {};
 
+const vueFlags = ['__v_skip', '__v_isReactive', '__v_isReadonly', '__v_isShallow', '__v_raw']
+function isVueProxy(value: unknown) {
+  return vueFlags.some(flag => !!value[flag])
+}
+
 const initBridge = (w: any): void => {
   const getPlatformId = (win: WindowCapacitor): 'android' | 'ios' | 'web' => {
     if (win?.androidBridge) {
@@ -277,6 +282,9 @@ const initBridge = (w: any): void => {
     };
 
     const serializeConsoleMessage = (msg: any): string => {
+      if (isVueProxy(msg)) {
+        return ''
+      }
       if (typeof msg === 'object') {
         try {
           msg = JSON.stringify(msg);
@@ -285,7 +293,13 @@ const initBridge = (w: any): void => {
         }
       }
 
-      return String(msg);
+      // https://github.com/ionic-team/capacitor/issues/6615
+      // String constructor may cause error (ex. msg is Proxy, created by Vue)
+      try {
+        return String(msg);
+      } catch (e) {
+        return '';
+      }
     };
 
     const platform = getPlatformId(win);

bazuka5801 avatar May 25 '23 23:05 bazuka5801

I have published an npm package for developers who have encountered this bug while the bug is not yet fixed. You can install it by replacing the line in your package.json

"@capacitor/ios": "npm:@bazuka5801/[email protected]",

And then install it using yarn command. P.s. I don't know how to do this with npm.

bazuka5801 avatar May 25 '23 23:05 bazuka5801

Up

bazuka5801 avatar Jun 06 '23 13:06 bazuka5801

Updated patch. fix: check value type before accessing object keys Also available npm package for cap-4: "@capacitor/ios": "npm:@bazuka5801/[email protected]",

diff --git a/core/native-bridge.ts b/core/native-bridge.ts
index 97ced31a..bcf5c0b0 100644
--- a/core/native-bridge.ts
+++ b/core/native-bridge.ts
@@ -17,6 +17,11 @@ import { CapacitorException } from './src/util';
 // eslint-disable-next-line
 let dummy = {};
 
+const vueFlags = ['__v_skip', '__v_isReactive', '__v_isReadonly', '__v_isShallow', '__v_raw']
+function isVueProxy(value: unknown) {
+  return typeof value === 'object' && value !== null && vueFlags.some(flag => !!value[flag])
+}
+
 const initBridge = (w: any): void => {
   const getPlatformId = (win: WindowCapacitor): 'android' | 'ios' | 'web' => {
     if (win?.androidBridge) {
@@ -277,6 +282,9 @@ const initBridge = (w: any): void => {
     };
 
     const serializeConsoleMessage = (msg: any): string => {
+      if (isVueProxy(msg)) {
+        return ''
+      }
       if (typeof msg === 'object') {
         try {
           msg = JSON.stringify(msg);
@@ -285,7 +293,13 @@ const initBridge = (w: any): void => {
         }
       }
 
-      return String(msg);
+      // https://github.com/ionic-team/capacitor/issues/6615
+      // String constructor may cause error (ex. msg is Proxy, created by Vue)
+      try {
+        return String(msg);
+      } catch (e) {
+        return '';
+      }
     };
 
     const platform = getPlatformId(win);

bazuka5801 avatar Jun 12 '23 16:06 bazuka5801

IMO considering current implementation already trying to ignore errors:

            const serializeConsoleMessage = (msg) => {
                if (typeof msg === 'object') {
                    try {
                        msg = JSON.stringify(msg);
                    }
                    catch (e) {
                        // ignore
                    }
                }
                return String(msg);
            };

the try catch should contain all the code including the return String(msg):

            const serializeConsoleMessage = (msg) => {
                try {
                    if (typeof msg === 'object') {
                        msg = JSON.stringify(msg);
                    }
                    return String(msg);
                }
                catch (e) {
                    // ignore
                }
            };

ciekawy avatar Oct 14 '23 15:10 ciekawy

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Capacitor, please create a new issue and ensure the template is fully filled out.

ionitron-bot[bot] avatar Apr 21 '24 09:04 ionitron-bot[bot]