@thelacanians/vue-native-cli 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +34 -17
- package/native/android/README.md +205 -0
- package/native/android/VueNativeCore/build.gradle.kts +100 -0
- package/native/android/VueNativeCore/consumer-rules.pro +12 -0
- package/native/android/VueNativeCore/proguard-rules.pro +33 -0
- package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +160 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
- package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
- package/native/android/app/build.gradle.kts +45 -0
- package/native/android/app/proguard-rules.pro +5 -0
- package/native/android/app/src/main/AndroidManifest.xml +25 -0
- package/native/android/app/src/main/assets/.gitkeep +0 -0
- package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
- package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
- package/native/android/app/src/main/res/values/strings.xml +3 -0
- package/native/android/app/src/main/res/values/themes.xml +9 -0
- package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
- package/native/android/build.gradle.kts +6 -0
- package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/native/android/gradle.properties +4 -0
- package/native/android/gradlew +87 -0
- package/native/android/gradlew.bat +48 -0
- package/native/android/settings.gradle.kts +20 -0
- package/native/ios/VueNativeCore/Package.resolved +23 -0
- package/native/ios/VueNativeCore/Package.swift +32 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +132 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +92 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +891 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +91 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +150 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +112 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +246 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +172 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +291 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +65 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +366 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +387 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +161 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +318 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +138 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +49 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +240 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
- package/package.json +3 -2
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import JavaScriptCore
|
|
3
|
+
import Foundation
|
|
4
|
+
|
|
5
|
+
// MARK: - Bundle Source
|
|
6
|
+
|
|
7
|
+
/// Describes where to load the JS application bundle from.
|
|
8
|
+
public enum BundleSource {
|
|
9
|
+
/// Load from an embedded resource in the app bundle.
|
|
10
|
+
case embedded(name: String)
|
|
11
|
+
/// Load from a development server URL (for live reload).
|
|
12
|
+
case devServer(url: URL)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// MARK: - JSRuntime
|
|
16
|
+
|
|
17
|
+
/// Core JavaScript runtime manager. Wraps JSContext on a dedicated serial DispatchQueue.
|
|
18
|
+
/// All JS operations are guaranteed to execute on the JS queue. UIKit operations
|
|
19
|
+
/// are never performed on this queue.
|
|
20
|
+
///
|
|
21
|
+
/// Thread safety contract:
|
|
22
|
+
/// - All JSContext access happens exclusively on `jsQueue`
|
|
23
|
+
/// - Never pass JSValue across threads — extract primitives first
|
|
24
|
+
/// - All closures registered with JSContext use [weak self]
|
|
25
|
+
public final class JSRuntime: @unchecked Sendable {
|
|
26
|
+
|
|
27
|
+
// MARK: - Singleton
|
|
28
|
+
|
|
29
|
+
public static let shared = JSRuntime()
|
|
30
|
+
|
|
31
|
+
// MARK: - Properties
|
|
32
|
+
|
|
33
|
+
/// Dedicated serial queue for all JavaScript execution.
|
|
34
|
+
/// QoS is userInteractive because JS drives the UI pipeline.
|
|
35
|
+
public let jsQueue = DispatchQueue(label: "com.vuenative.js", qos: .userInteractive)
|
|
36
|
+
|
|
37
|
+
/// The underlying JavaScriptCore context. Only access on jsQueue.
|
|
38
|
+
public private(set) var context: JSContext!
|
|
39
|
+
|
|
40
|
+
/// Whether the runtime has been initialized.
|
|
41
|
+
public private(set) var isInitialized = false
|
|
42
|
+
|
|
43
|
+
/// Startup time reference for performance.now()
|
|
44
|
+
public let startTime: CFAbsoluteTime = CFAbsoluteTimeGetCurrent()
|
|
45
|
+
|
|
46
|
+
// MARK: - Initialization
|
|
47
|
+
|
|
48
|
+
private init() {}
|
|
49
|
+
|
|
50
|
+
/// Initialize the JS runtime. Creates the JSContext on the JS queue,
|
|
51
|
+
/// configures exception handling, and registers polyfills.
|
|
52
|
+
/// Must be called before any other method.
|
|
53
|
+
public func initialize(completion: (() -> Void)? = nil) {
|
|
54
|
+
jsQueue.async { [weak self] in
|
|
55
|
+
guard let self = self else { return }
|
|
56
|
+
guard !self.isInitialized else {
|
|
57
|
+
completion?()
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Create the JSContext
|
|
62
|
+
self.context = JSContext()
|
|
63
|
+
|
|
64
|
+
// Configure exception handler
|
|
65
|
+
self.context.exceptionHandler = { [weak self] context, exception in
|
|
66
|
+
guard let exception = exception else { return }
|
|
67
|
+
let message = exception.toString() ?? "Unknown JS error"
|
|
68
|
+
let line = exception.objectForKeyedSubscript("line")?.toInt32() ?? 0
|
|
69
|
+
let column = exception.objectForKeyedSubscript("column")?.toInt32() ?? 0
|
|
70
|
+
let stack = exception.objectForKeyedSubscript("stack")?.toString() ?? ""
|
|
71
|
+
NSLog("[VueNative JS Error] \(message) at line \(line):\(column)")
|
|
72
|
+
if !stack.isEmpty {
|
|
73
|
+
NSLog("[VueNative JS Stack] \(stack)")
|
|
74
|
+
}
|
|
75
|
+
#if DEBUG
|
|
76
|
+
let fullMessage = stack.isEmpty ? message : "\(message)\n\n\(stack)"
|
|
77
|
+
ErrorOverlayView.show(error: fullMessage)
|
|
78
|
+
#endif
|
|
79
|
+
_ = self // prevent unused warning
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Set globalThis = global object
|
|
83
|
+
self.context.evaluateScript("var globalThis = this;")
|
|
84
|
+
|
|
85
|
+
// Register polyfills
|
|
86
|
+
JSPolyfills.register(in: self)
|
|
87
|
+
|
|
88
|
+
self.isInitialized = true
|
|
89
|
+
completion?()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// MARK: - Script Evaluation
|
|
94
|
+
|
|
95
|
+
/// Evaluate a JavaScript string on the JS queue.
|
|
96
|
+
/// The completion handler is called on the JS queue with the result.
|
|
97
|
+
public func evaluateScript(_ script: String, sourceURL: String? = nil, completion: ((JSValue?) -> Void)? = nil) {
|
|
98
|
+
jsQueue.async { [weak self] in
|
|
99
|
+
guard let self = self, let context = self.context else {
|
|
100
|
+
completion?(nil)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let result: JSValue?
|
|
105
|
+
if let sourceURL = sourceURL, let url = URL(string: sourceURL) {
|
|
106
|
+
result = context.evaluateScript(script, withSourceURL: url)
|
|
107
|
+
} else {
|
|
108
|
+
result = context.evaluateScript(script)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Force microtask drain after evaluation.
|
|
112
|
+
// JSC may not automatically drain microtasks after evaluateScript returns.
|
|
113
|
+
// This ensures Vue's Promise-based scheduler flushes.
|
|
114
|
+
context.evaluateScript("void 0;")
|
|
115
|
+
|
|
116
|
+
completion?(result)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// Evaluate a script synchronously. MUST only be called from the JS queue.
|
|
121
|
+
/// Returns the JSValue result directly.
|
|
122
|
+
@discardableResult
|
|
123
|
+
public func evaluateScriptSync(_ script: String, sourceURL: String? = nil) -> JSValue? {
|
|
124
|
+
dispatchPrecondition(condition: .onQueue(jsQueue))
|
|
125
|
+
guard let context = context else { return nil }
|
|
126
|
+
|
|
127
|
+
let result: JSValue?
|
|
128
|
+
if let sourceURL = sourceURL, let url = URL(string: sourceURL) {
|
|
129
|
+
result = context.evaluateScript(script, withSourceURL: url)
|
|
130
|
+
} else {
|
|
131
|
+
result = context.evaluateScript(script)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Force microtask drain
|
|
135
|
+
context.evaluateScript("void 0;")
|
|
136
|
+
return result
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MARK: - Function Calls
|
|
140
|
+
|
|
141
|
+
/// Call a global JS function by name with arguments. Runs on the JS queue.
|
|
142
|
+
/// Uses objectForKeyedSubscript().call() for performance (avoids re-parsing).
|
|
143
|
+
public func callFunction(_ name: String, withArguments args: [Any], completion: ((JSValue?) -> Void)? = nil) {
|
|
144
|
+
jsQueue.async { [weak self] in
|
|
145
|
+
guard let self = self, let context = self.context else {
|
|
146
|
+
completion?(nil)
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let function = context.objectForKeyedSubscript(name)
|
|
151
|
+
guard let fn = function, !fn.isUndefined else {
|
|
152
|
+
NSLog("[VueNative] Warning: JS function '\(name)' not found")
|
|
153
|
+
completion?(nil)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let result = fn.call(withArguments: args)
|
|
158
|
+
|
|
159
|
+
// Force microtask drain
|
|
160
|
+
context.evaluateScript("void 0;")
|
|
161
|
+
|
|
162
|
+
completion?(result)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Call a global JS function synchronously. MUST only be called from the JS queue.
|
|
167
|
+
@discardableResult
|
|
168
|
+
public func callFunctionSync(_ name: String, withArguments args: [Any]) -> JSValue? {
|
|
169
|
+
dispatchPrecondition(condition: .onQueue(jsQueue))
|
|
170
|
+
guard let context = context else { return nil }
|
|
171
|
+
|
|
172
|
+
let function = context.objectForKeyedSubscript(name)
|
|
173
|
+
guard let fn = function, !fn.isUndefined else {
|
|
174
|
+
NSLog("[VueNative] Warning: JS function '\(name)' not found")
|
|
175
|
+
return nil
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let result = fn.call(withArguments: args)
|
|
179
|
+
|
|
180
|
+
// Force microtask drain
|
|
181
|
+
context.evaluateScript("void 0;")
|
|
182
|
+
return result
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// MARK: - Function Registration
|
|
186
|
+
|
|
187
|
+
/// Register a Swift function as a global JS function.
|
|
188
|
+
/// The block receives a single JSValue argument (use .toArray() etc. to extract args).
|
|
189
|
+
/// IMPORTANT: The block executes on the JS queue.
|
|
190
|
+
public func registerFunction(_ name: String, block: @escaping @convention(block) (JSValue) -> Void) {
|
|
191
|
+
jsQueue.async { [weak self] in
|
|
192
|
+
guard let self = self, let context = self.context else { return }
|
|
193
|
+
let wrappedBlock: @convention(block) (JSValue) -> Void = { [weak self] value in
|
|
194
|
+
_ = self // prevent retain cycle through closure capture
|
|
195
|
+
block(value)
|
|
196
|
+
}
|
|
197
|
+
context.setObject(wrappedBlock, forKeyedSubscript: name as NSString)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// Register a Swift function with multiple arguments.
|
|
202
|
+
public func registerFunctionMultiArg(_ name: String, argCount: Int, block: @escaping ([JSValue]) -> Void) {
|
|
203
|
+
jsQueue.async { [weak self] in
|
|
204
|
+
guard let self = self, let context = self.context else { return }
|
|
205
|
+
|
|
206
|
+
switch argCount {
|
|
207
|
+
case 0:
|
|
208
|
+
let wrapped: @convention(block) () -> Void = { [weak self] in
|
|
209
|
+
_ = self
|
|
210
|
+
block([])
|
|
211
|
+
}
|
|
212
|
+
context.setObject(wrapped, forKeyedSubscript: name as NSString)
|
|
213
|
+
case 1:
|
|
214
|
+
let wrapped: @convention(block) (JSValue) -> Void = { [weak self] a in
|
|
215
|
+
_ = self
|
|
216
|
+
block([a])
|
|
217
|
+
}
|
|
218
|
+
context.setObject(wrapped, forKeyedSubscript: name as NSString)
|
|
219
|
+
case 2:
|
|
220
|
+
let wrapped: @convention(block) (JSValue, JSValue) -> Void = { [weak self] a, b in
|
|
221
|
+
_ = self
|
|
222
|
+
block([a, b])
|
|
223
|
+
}
|
|
224
|
+
context.setObject(wrapped, forKeyedSubscript: name as NSString)
|
|
225
|
+
case 3:
|
|
226
|
+
let wrapped: @convention(block) (JSValue, JSValue, JSValue) -> Void = { [weak self] a, b, c in
|
|
227
|
+
_ = self
|
|
228
|
+
block([a, b, c])
|
|
229
|
+
}
|
|
230
|
+
context.setObject(wrapped, forKeyedSubscript: name as NSString)
|
|
231
|
+
default:
|
|
232
|
+
// For 4+ args, use the single-arg version and extract from JSValue
|
|
233
|
+
let wrapped: @convention(block) (JSValue) -> Void = { [weak self] value in
|
|
234
|
+
_ = self
|
|
235
|
+
block([value])
|
|
236
|
+
}
|
|
237
|
+
context.setObject(wrapped, forKeyedSubscript: name as NSString)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// MARK: - Bundle Loading
|
|
243
|
+
|
|
244
|
+
/// Load a JS application bundle from the given source.
|
|
245
|
+
/// Polyfills are already registered during initialize().
|
|
246
|
+
public func loadBundle(source: BundleSource, completion: ((Bool) -> Void)? = nil) {
|
|
247
|
+
jsQueue.async { [weak self] in
|
|
248
|
+
guard let self = self, self.context != nil else {
|
|
249
|
+
completion?(false)
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
switch source {
|
|
254
|
+
case .embedded(let name):
|
|
255
|
+
self.loadEmbeddedBundle(name: name, completion: completion)
|
|
256
|
+
|
|
257
|
+
case .devServer(let url):
|
|
258
|
+
self.loadDevServerBundle(url: url, completion: completion)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// MARK: - Private: Bundle Loading
|
|
264
|
+
|
|
265
|
+
private func loadEmbeddedBundle(name: String, completion: ((Bool) -> Void)?) {
|
|
266
|
+
// Try to find the bundle in the main app bundle
|
|
267
|
+
let bundleName: String
|
|
268
|
+
let bundleExtension: String
|
|
269
|
+
|
|
270
|
+
if name.contains(".") {
|
|
271
|
+
let parts = name.split(separator: ".", maxSplits: 1)
|
|
272
|
+
bundleName = String(parts[0])
|
|
273
|
+
bundleExtension = String(parts[1])
|
|
274
|
+
} else {
|
|
275
|
+
bundleName = name
|
|
276
|
+
bundleExtension = "js"
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Search in main bundle and SPM resource bundle
|
|
280
|
+
var scriptURL: URL?
|
|
281
|
+
|
|
282
|
+
if let url = Bundle.main.url(forResource: bundleName, withExtension: bundleExtension) {
|
|
283
|
+
scriptURL = url
|
|
284
|
+
} else {
|
|
285
|
+
// Try the module bundle (SPM resources)
|
|
286
|
+
#if SWIFT_PACKAGE
|
|
287
|
+
if let url = Bundle.module.url(forResource: bundleName, withExtension: bundleExtension) {
|
|
288
|
+
scriptURL = url
|
|
289
|
+
}
|
|
290
|
+
#endif
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
guard let url = scriptURL else {
|
|
294
|
+
NSLog("[VueNative] Error: Bundle '\(name)' not found in app resources")
|
|
295
|
+
completion?(false)
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
do {
|
|
300
|
+
let script = try String(contentsOf: url, encoding: .utf8)
|
|
301
|
+
NSLog("[VueNative] Loading bundle: \(name) (\(script.count) bytes)")
|
|
302
|
+
self.context.evaluateScript(script, withSourceURL: url)
|
|
303
|
+
// Force microtask drain after bundle load
|
|
304
|
+
self.context.evaluateScript("void 0;")
|
|
305
|
+
NSLog("[VueNative] Bundle loaded successfully")
|
|
306
|
+
completion?(true)
|
|
307
|
+
} catch {
|
|
308
|
+
NSLog("[VueNative] Error loading bundle '\(name)': \(error.localizedDescription)")
|
|
309
|
+
completion?(false)
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private func loadDevServerBundle(url: URL, completion: ((Bool) -> Void)?) {
|
|
314
|
+
// Fetch from dev server on a background queue, then evaluate on JS queue
|
|
315
|
+
let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
|
|
316
|
+
guard let self = self else {
|
|
317
|
+
completion?(false)
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
self.jsQueue.async { [weak self] in
|
|
322
|
+
guard let self = self, self.context != nil else {
|
|
323
|
+
completion?(false)
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if let error = error {
|
|
328
|
+
NSLog("[VueNative] Dev server error: \(error.localizedDescription)")
|
|
329
|
+
completion?(false)
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
guard let data = data, let script = String(data: data, encoding: .utf8) else {
|
|
334
|
+
NSLog("[VueNative] Dev server returned invalid data")
|
|
335
|
+
completion?(false)
|
|
336
|
+
return
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
NSLog("[VueNative] Loading dev bundle from \(url) (\(script.count) bytes)")
|
|
340
|
+
self.context.evaluateScript(script, withSourceURL: url)
|
|
341
|
+
// Force microtask drain
|
|
342
|
+
self.context.evaluateScript("void 0;")
|
|
343
|
+
NSLog("[VueNative] Dev bundle loaded successfully")
|
|
344
|
+
completion?(true)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
task.resume()
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// MARK: - Hot Reload
|
|
351
|
+
|
|
352
|
+
/// Reload the runtime with a new JavaScript bundle string.
|
|
353
|
+
/// Creates a fresh JSContext, re-registers polyfills, and evaluates the bundle.
|
|
354
|
+
/// Calls completion on the JS queue with success/failure.
|
|
355
|
+
public func reload(bundle: String, completion: ((Bool) -> Void)? = nil) {
|
|
356
|
+
jsQueue.async { [weak self] in
|
|
357
|
+
guard let self = self else {
|
|
358
|
+
completion?(false)
|
|
359
|
+
return
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
NSLog("[VueNative] Hot reload: tearing down old context...")
|
|
363
|
+
|
|
364
|
+
// Tear down old Vue app gracefully
|
|
365
|
+
if let teardown = self.context?.objectForKeyedSubscript("__VN_teardown"),
|
|
366
|
+
!teardown.isUndefined {
|
|
367
|
+
teardown.call(withArguments: [])
|
|
368
|
+
self.context?.evaluateScript("void 0;")
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Reset polyfill state (timers, RAF, display link) before creating new context
|
|
372
|
+
JSPolyfills.reset()
|
|
373
|
+
|
|
374
|
+
// Create fresh context
|
|
375
|
+
self.context = JSContext()
|
|
376
|
+
self.context.exceptionHandler = { [weak self] _, exception in
|
|
377
|
+
guard let exception = exception else { return }
|
|
378
|
+
let message = exception.toString() ?? "Unknown JS error"
|
|
379
|
+
let line = exception.objectForKeyedSubscript("line")?.toInt32() ?? 0
|
|
380
|
+
let stack = exception.objectForKeyedSubscript("stack")?.toString() ?? ""
|
|
381
|
+
NSLog("[VueNative JS Error] \(message) at line \(line)")
|
|
382
|
+
#if DEBUG
|
|
383
|
+
let fullMessage = stack.isEmpty ? message : "\(message)\n\n\(stack)"
|
|
384
|
+
ErrorOverlayView.show(error: fullMessage)
|
|
385
|
+
#endif
|
|
386
|
+
_ = self
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Re-register globalThis and polyfills
|
|
390
|
+
self.context.evaluateScript("var globalThis = this;")
|
|
391
|
+
JSPolyfills.register(in: self)
|
|
392
|
+
|
|
393
|
+
NSLog("[VueNative] Hot reload: evaluating new bundle (\(bundle.count) bytes)...")
|
|
394
|
+
self.context.evaluateScript(bundle)
|
|
395
|
+
if let exception = self.context.exception {
|
|
396
|
+
NSLog("[VueNative] Hot reload bundle error: %@", exception.toString() ?? "unknown")
|
|
397
|
+
self.context.exception = nil
|
|
398
|
+
completion?(false)
|
|
399
|
+
return
|
|
400
|
+
}
|
|
401
|
+
self.context.evaluateScript("void 0;")
|
|
402
|
+
NSLog("[VueNative] Hot reload: complete")
|
|
403
|
+
|
|
404
|
+
completion?(true)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// MARK: - Teardown
|
|
409
|
+
|
|
410
|
+
/// Invalidate the runtime and release resources.
|
|
411
|
+
/// After calling this, the runtime cannot be used again.
|
|
412
|
+
public func invalidate() {
|
|
413
|
+
jsQueue.async { [weak self] in
|
|
414
|
+
guard let self = self else { return }
|
|
415
|
+
self.context = nil
|
|
416
|
+
self.isInitialized = false
|
|
417
|
+
NSLog("[VueNative] JS runtime invalidated")
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
#endif
|