bug: log vue 3 warn cause error on iOS
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:
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)
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
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);
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);
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.
Up
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);
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
}
};
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.