@react-native-quickjs/quickjs 1.0.0-alpha.0
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/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/NOTICE +31 -0
- package/README.md +217 -0
- package/ReactNativeQuickJS.podspec +197 -0
- package/android/CMakeLists.txt +134 -0
- package/android/build.gradle +214 -0
- package/android/quickjs.gradle +39 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/reactnativequickjs/quickjs/QuickJSInstance.kt +39 -0
- package/android/src/main/java/com/reactnativequickjs/quickjs/QuickJSPackage.kt +32 -0
- package/android/src/main/jni/JJSRuntimeFactory.h +37 -0
- package/android/src/main/jni/JQuickJSInstance.cpp +27 -0
- package/android/src/main/jni/JQuickJSInstance.h +46 -0
- package/android/src/main/jni/OnLoad.cpp +15 -0
- package/app.plugin.js +11 -0
- package/apple/RCTQuickJSInstanceFactory.h +32 -0
- package/apple/RCTQuickJSInstanceFactory.mm +16 -0
- package/bin/qjsc/darwin-arm64/qjsc +0 -0
- package/bin/qjsc/darwin-x64/qjsc +0 -0
- package/bin/qjsc/linux-arm64/qjsc +0 -0
- package/bin/qjsc/linux-x64/qjsc +0 -0
- package/bin/qjsc/manifest.json +11 -0
- package/bin/qjsc/win32-x64/qjsc.exe +0 -0
- package/bin/react-native-quickjs.js +28 -0
- package/cmake/jsi.cmake +24 -0
- package/cmake/quickjs.cmake +125 -0
- package/engine/quickjs-rel/LICENSE +24 -0
- package/engine/quickjs-rel/MANIFEST.json +55 -0
- package/engine/quickjs-rel/builtin-array-fromasync.h +120 -0
- package/engine/quickjs-rel/builtin-iterator-zip-keyed.h +332 -0
- package/engine/quickjs-rel/builtin-iterator-zip.h +337 -0
- package/engine/quickjs-rel/cutils.h +1998 -0
- package/engine/quickjs-rel/dtoa.c +1619 -0
- package/engine/quickjs-rel/dtoa.h +87 -0
- package/engine/quickjs-rel/libregexp-opcode.h +73 -0
- package/engine/quickjs-rel/libregexp.c +3478 -0
- package/engine/quickjs-rel/libregexp.h +101 -0
- package/engine/quickjs-rel/libunicode-table.h +5173 -0
- package/engine/quickjs-rel/libunicode.c +2069 -0
- package/engine/quickjs-rel/libunicode.h +172 -0
- package/engine/quickjs-rel/list.h +107 -0
- package/engine/quickjs-rel/quickjs-atom.h +280 -0
- package/engine/quickjs-rel/quickjs-c-atomics.h +54 -0
- package/engine/quickjs-rel/quickjs-opcode.h +385 -0
- package/engine/quickjs-rel/quickjs.c +64854 -0
- package/engine/quickjs-rel/quickjs.h +1577 -0
- package/modules/cdp/quickjs-cdp.c +1386 -0
- package/modules/cdp/quickjs-cdp.h +122 -0
- package/modules/cdp/react/QuickJSInspector.cpp +322 -0
- package/modules/cdp/react/QuickJSInspector.h +114 -0
- package/modules/hermes-compat/include/hermes/DebuggerAPI.h +20 -0
- package/modules/hermes-compat/include/hermes/Public/CrashManager.h +47 -0
- package/modules/hermes-compat/include/hermes/Public/CtorConfig.h +88 -0
- package/modules/hermes-compat/include/hermes/Public/GCConfig.h +83 -0
- package/modules/hermes-compat/include/hermes/Public/HermesExport.h +17 -0
- package/modules/hermes-compat/include/hermes/Public/RuntimeConfig.h +66 -0
- package/modules/hermes-compat/include/hermes/Public/SamplingProfiler.h +22 -0
- package/modules/hermes-compat/include/hermes/hermes.h +195 -0
- package/modules/hermes-compat/include/hermes/inspector/RuntimeAdapter.h +43 -0
- package/modules/hermes-compat/include/hermes/inspector-modern/chrome/Registration.h +31 -0
- package/modules/hermes-compat/include/hermes-compat/Diagnostics.h +35 -0
- package/modules/hermes-compat/src/HermesCompat.cpp +557 -0
- package/package.json +104 -0
- package/scripts/bytecode/compile.js +99 -0
- package/scripts/expo/plugin.js +231 -0
- package/scripts/postinstall.js +74 -0
- package/scripts/react_native_quickjs_pods.rb +237 -0
- package/scripts/setup/edits.js +311 -0
- package/scripts/setup/run.js +121 -0
- package/src/bytecode/QuickJSBytecode.cpp +50 -0
- package/src/bytecode/QuickJSBytecode.h +50 -0
- package/src/module/QuickJSCompat.cpp +92 -0
- package/src/module/QuickJSCompat.h +19 -0
- package/src/module/QuickJSModule.cpp +70 -0
- package/src/module/QuickJSModule.h +108 -0
- package/src/module/QuickJSModuleNative.h +93 -0
- package/src/runtime/QuickJSInstance.cpp +37 -0
- package/src/runtime/QuickJSInstance.h +74 -0
- package/src/runtime/QuickJSRuntime.cpp +1864 -0
- package/src/runtime/QuickJSRuntime.h +529 -0
- package/src/runtime/QuickJSRuntimeConfig.h +103 -0
- package/src/runtime/QuickJSRuntimeFactory.cpp +34 -0
- package/src/runtime/QuickJSRuntimeFactory.h +24 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.ReactNativeQuickJS = [
|
|
3
|
+
kotlinVersion: "2.0.21",
|
|
4
|
+
minSdkVersion: 24,
|
|
5
|
+
compileSdkVersion: 36
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
ext.getExtOrDefault = { prop ->
|
|
9
|
+
if (rootProject.ext.has(prop)) {
|
|
10
|
+
return rootProject.ext.get(prop)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return ReactNativeQuickJS[prop]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
repositories {
|
|
17
|
+
google()
|
|
18
|
+
mavenCentral()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dependencies {
|
|
22
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
23
|
+
// noinspection DifferentKotlinGradleVersion
|
|
24
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
apply plugin: "com.android.library"
|
|
29
|
+
apply plugin: "kotlin-android"
|
|
30
|
+
|
|
31
|
+
android {
|
|
32
|
+
namespace "com.reactnativequickjs.quickjs"
|
|
33
|
+
|
|
34
|
+
// Follow the app's NDK, or let the Android plugin choose. Pinning our own
|
|
35
|
+
// would compile this library with a different toolchain than the app.
|
|
36
|
+
if (rootProject.ext.has("ndkVersion")) {
|
|
37
|
+
ndkVersion rootProject.ext.get("ndkVersion")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
compileSdkVersion getExtOrDefault("compileSdkVersion")
|
|
41
|
+
|
|
42
|
+
defaultConfig {
|
|
43
|
+
minSdkVersion getExtOrDefault("minSdkVersion")
|
|
44
|
+
|
|
45
|
+
externalNativeBuild {
|
|
46
|
+
cmake {
|
|
47
|
+
// ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES gives the shared library 16 KB
|
|
48
|
+
// LOAD alignment. Without it we link at 4 KB while every prebuilt in
|
|
49
|
+
// the same APK -- libreactnative.so, libjsi.so, libfbjni.so,
|
|
50
|
+
// libc++_shared.so -- is already 16 KB, and on an Android 15 kernel
|
|
51
|
+
// the loader refuses ours outright:
|
|
52
|
+
//
|
|
53
|
+
// "...so" program alignment (4096) cannot be smaller than
|
|
54
|
+
// system page size (16384)
|
|
55
|
+
//
|
|
56
|
+
// The process is killed at System.loadLibrary, so there is no partial
|
|
57
|
+
// functionality to notice: the app does not start. NDK r27 leaves this
|
|
58
|
+
// off by default, r28 turns it on, and no host build can see it.
|
|
59
|
+
arguments "-DANDROID_STL=c++_shared",
|
|
60
|
+
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON",
|
|
61
|
+
"-DREACT_NATIVE_DIR=${reactNativeDir()}"
|
|
62
|
+
|
|
63
|
+
// Left unset, CMakeLists.txt takes the DevTools backend from the build
|
|
64
|
+
// type. -PrnqjsEnableCdp=true|false forces it either way.
|
|
65
|
+
if (project.hasProperty('rnqjsEnableCdp')) {
|
|
66
|
+
def on = project.property('rnqjsEnableCdp').toString() != 'false'
|
|
67
|
+
arguments "-DRNQJS_ENABLE_CDP=${on ? 'ON' : 'OFF'}"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Ships the Hermes compatibility shim as libhermesvm.so, so libraries
|
|
71
|
+
// that link against Hermes -- react-native-worklets, and so
|
|
72
|
+
// react-native-reanimated -- run on QuickJS unmodified.
|
|
73
|
+
arguments "-DRNQJS_HERMES_COMPAT=${hermesCompatEnabled() ? 'ON' : 'OFF'}"
|
|
74
|
+
|
|
75
|
+
abiFilters(*reactNativeArchitectures())
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
externalNativeBuild {
|
|
81
|
+
cmake {
|
|
82
|
+
path "CMakeLists.txt"
|
|
83
|
+
version "3.22.1"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
buildFeatures {
|
|
88
|
+
// Required to consume ReactAndroid::jsi and ReactAndroid::reactnative from
|
|
89
|
+
// the react-android AAR via find_package(ReactAndroid CONFIG).
|
|
90
|
+
prefab true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
packagingOptions {
|
|
94
|
+
// These ship with React Native itself; a second copy would conflict at
|
|
95
|
+
// load time.
|
|
96
|
+
excludes += [
|
|
97
|
+
"**/libc++_shared.so",
|
|
98
|
+
"**/libfbjni.so",
|
|
99
|
+
"**/libjsi.so",
|
|
100
|
+
"**/libreactnative.so",
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
compileOptions {
|
|
105
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
106
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Whether to build the Hermes compatibility shim.
|
|
111
|
+
//
|
|
112
|
+
// Autolinking puts this library into every app that has the package installed,
|
|
113
|
+
// including one still running Hermes and one part-way through switching over.
|
|
114
|
+
// The shim is named libhermesvm.so, because that is the name the libraries
|
|
115
|
+
// needing it look for, so building it in a Hermes app puts a second file of
|
|
116
|
+
// that name into the merge -- and a ~100 KB shim winning over the real engine
|
|
117
|
+
// leaves the app dead at startup with NoClassDefFoundError: HermesInstance.
|
|
118
|
+
//
|
|
119
|
+
// So it is built only once the app has actually left Hermes, which is what
|
|
120
|
+
// hermesEnabled=false in gradle.properties says. -PrnqjsHermesCompat decides
|
|
121
|
+
// it outright either way.
|
|
122
|
+
def hermesCompatEnabled() {
|
|
123
|
+
if (project.hasProperty('rnqjsHermesCompat')) {
|
|
124
|
+
return project.property('rnqjsHermesCompat').toString() != 'false'
|
|
125
|
+
}
|
|
126
|
+
return rootProject.findProperty('hermesEnabled')?.toString() == 'false'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Resolved through node so this works regardless of how the consuming app
|
|
130
|
+
// hoists its node_modules.
|
|
131
|
+
def reactNativeDir() {
|
|
132
|
+
def resolved = providers.exec {
|
|
133
|
+
workingDir(rootDir)
|
|
134
|
+
commandLine("node", "--print", "require.resolve('react-native/package.json')")
|
|
135
|
+
}.standardOutput.asText.get().trim()
|
|
136
|
+
|
|
137
|
+
return new File(resolved).getParentFile().getAbsolutePath()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
def reactNativeArchitectures() {
|
|
141
|
+
def value = rootProject.getProperties().get("reactNativeArchitectures")
|
|
142
|
+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
dependencies {
|
|
146
|
+
implementation "com.facebook.react:react-android"
|
|
147
|
+
implementation "com.facebook.fbjni:fbjni:0.7.0"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// The app template picks Hermes or JavaScriptCore in its own build.gradle, and
|
|
151
|
+
// an app on QuickJS wants neither -- but hermesEnabled=false lands it in the
|
|
152
|
+
// JavaScriptCore branch. Gradle gives a library no way to drop a dependency the
|
|
153
|
+
// app itself declared, so warn instead.
|
|
154
|
+
gradle.projectsEvaluated {
|
|
155
|
+
rootProject.subprojects.each { app ->
|
|
156
|
+
if (!app.plugins.hasPlugin("com.android.application")) return
|
|
157
|
+
|
|
158
|
+
def declared = app.configurations.findByName("implementation")
|
|
159
|
+
?.dependencies?.collect { it.name } ?: []
|
|
160
|
+
|
|
161
|
+
if (declared.contains("hermes-android")) {
|
|
162
|
+
app.logger.warn("[ReactNativeQuickJS] ${app.path} bundles Hermes. Set " +
|
|
163
|
+
"hermesEnabled=false in gradle.properties, or a release bundle is " +
|
|
164
|
+
"Hermes bytecode that QuickJS cannot execute.")
|
|
165
|
+
}
|
|
166
|
+
if (declared.any { it.startsWith("jsc-android") }) {
|
|
167
|
+
app.logger.warn("[ReactNativeQuickJS] ${app.path} bundles JavaScriptCore " +
|
|
168
|
+
"and never loads it. Remove the jscFlavor dependency to save about " +
|
|
169
|
+
"10 MB per architecture.")
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Compile the release bundle to QuickJS bytecode, after React Native has
|
|
175
|
+
// written it. Debug builds load JavaScript from Metro and never produce a
|
|
176
|
+
// bundle, so there is nothing to compile. -PrnqjsBytecode=false turns it off.
|
|
177
|
+
|
|
178
|
+
// ExecOperations is how a Gradle 9 build spawns a process; project.exec was
|
|
179
|
+
// removed. A plain ProcessBuilder also runs, but not identically: under a
|
|
180
|
+
// Volta-managed node it fails to resolve a version at all, in a build where
|
|
181
|
+
// React Native's own bundle task -- which goes through ExecOperations -- had
|
|
182
|
+
// just run the same binary.
|
|
183
|
+
interface ReactNativeQuickJSProcess {
|
|
184
|
+
@javax.inject.Inject
|
|
185
|
+
org.gradle.process.ExecOperations getExecOperations()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
gradle.projectsEvaluated {
|
|
189
|
+
if (project.findProperty('rnqjsBytecode')?.toString() == 'false') return
|
|
190
|
+
|
|
191
|
+
def compiler = file("${projectDir}/../scripts/bytecode/compile.js")
|
|
192
|
+
|
|
193
|
+
rootProject.subprojects.each { app ->
|
|
194
|
+
if (!app.plugins.hasPlugin("com.android.application")) return
|
|
195
|
+
|
|
196
|
+
def process = app.objects.newInstance(ReactNativeQuickJSProcess).execOperations
|
|
197
|
+
// The same node React Native bundles with, including an override of it.
|
|
198
|
+
def node = app.extensions.findByName('react')?.nodeExecutableAndArgs?.getOrNull() ?: ['node']
|
|
199
|
+
|
|
200
|
+
app.tasks.matching { it.name ==~ /createBundle.*JsAndAssets/ }.configureEach { bundleTask ->
|
|
201
|
+
bundleTask.doLast {
|
|
202
|
+
// Found by name rather than by reading the task's own properties,
|
|
203
|
+
// which are React Native Gradle plugin internals.
|
|
204
|
+
def assets = app.layout.buildDirectory.dir("generated/assets").get().asFile
|
|
205
|
+
app.fileTree(assets).matching { include '**/index.android.bundle' }.each { bundle ->
|
|
206
|
+
process.exec {
|
|
207
|
+
commandLine(*node, compiler.absolutePath, bundle.absolutePath)
|
|
208
|
+
workingDir app.rootDir
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) Ammar Ahmed.
|
|
2
|
+
//
|
|
3
|
+
// This source code is licensed under the MIT license found in the
|
|
4
|
+
// LICENSE file in the root directory of this source tree.
|
|
5
|
+
//
|
|
6
|
+
// Applied from the app's android/app/build.gradle:
|
|
7
|
+
//
|
|
8
|
+
// apply from: file("../../node_modules/@react-native-quickjs/quickjs/android/quickjs.gradle")
|
|
9
|
+
//
|
|
10
|
+
// React Native strips the JavaScript engine the app is not using. It knows two
|
|
11
|
+
// engines, so "not Hermes" means "delete **/libhermesvm.so" -- and that is the
|
|
12
|
+
// name the Hermes compatibility shim has to carry, because it is what
|
|
13
|
+
// react-native-worklets records as NEEDED. See useThirdPartyJSC in
|
|
14
|
+
// NdkConfiguratorUtils.kt.
|
|
15
|
+
//
|
|
16
|
+
// Turning that cleanup off would also stop JavaScriptCore and the Hermes
|
|
17
|
+
// tooling library being stripped, so it is replaced here rather than dropped:
|
|
18
|
+
// the same removals, minus the one file this engine needs.
|
|
19
|
+
|
|
20
|
+
react {
|
|
21
|
+
enableSoCleanup = false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
androidComponents {
|
|
25
|
+
onVariants(selector().all()) { variant ->
|
|
26
|
+
variant.packaging.jniLibs.excludes.addAll([
|
|
27
|
+
"**/libjsc.so",
|
|
28
|
+
"**/libjsctooling.so",
|
|
29
|
+
"**/libhermestooling.so",
|
|
30
|
+
])
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// A transitively pulled Hermes would put a second libhermesvm.so into the merge
|
|
35
|
+
// and the winner would be whichever the merger saw first -- a real engine,
|
|
36
|
+
// satisfying worklets and starting up silently. So it cannot enter the graph.
|
|
37
|
+
configurations.configureEach {
|
|
38
|
+
exclude group: "com.facebook.hermes", module: "hermes-android"
|
|
39
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
package com.reactnativequickjs.quickjs
|
|
9
|
+
|
|
10
|
+
import com.facebook.jni.HybridData
|
|
11
|
+
import com.facebook.jni.annotations.DoNotStrip
|
|
12
|
+
import com.facebook.react.runtime.JSRuntimeFactory
|
|
13
|
+
import com.facebook.soloader.SoLoader
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The QuickJS engine, as a drop-in replacement for
|
|
17
|
+
* `com.facebook.react.runtime.hermes.HermesInstance`.
|
|
18
|
+
*
|
|
19
|
+
* Pass it to `DefaultReactHost.getDefaultReactHost(...)` in your
|
|
20
|
+
* `MainApplication`:
|
|
21
|
+
* ```
|
|
22
|
+
* override val reactHost: ReactHost
|
|
23
|
+
* get() = getDefaultReactHost(
|
|
24
|
+
* applicationContext,
|
|
25
|
+
* reactNativeHost,
|
|
26
|
+
* jsRuntimeFactory = QuickJSInstance(),
|
|
27
|
+
* )
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
public class QuickJSInstance : JSRuntimeFactory(initHybrid()) {
|
|
31
|
+
|
|
32
|
+
public companion object {
|
|
33
|
+
@JvmStatic @DoNotStrip protected external fun initHybrid(): HybridData
|
|
34
|
+
|
|
35
|
+
init {
|
|
36
|
+
SoLoader.loadLibrary("quickjsinstancejni")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
package com.reactnativequickjs.quickjs
|
|
9
|
+
|
|
10
|
+
import com.facebook.react.ReactPackage
|
|
11
|
+
import com.facebook.react.bridge.NativeModule
|
|
12
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
13
|
+
import com.facebook.react.uimanager.ViewManager
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Deliberately empty.
|
|
17
|
+
*
|
|
18
|
+
* This package exports no modules and no view managers -- QuickJS is wired in
|
|
19
|
+
* through [QuickJSInstance], not through the module system. It exists only
|
|
20
|
+
* because React Native's autolinking skips any Android library that does not
|
|
21
|
+
* expose a ReactPackage (see cli-config-android dependencyConfig), and without
|
|
22
|
+
* autolinking the gradle project is never included in the app build.
|
|
23
|
+
*/
|
|
24
|
+
public class QuickJSPackage : ReactPackage {
|
|
25
|
+
override fun createNativeModules(
|
|
26
|
+
reactContext: ReactApplicationContext
|
|
27
|
+
): List<NativeModule> = emptyList()
|
|
28
|
+
|
|
29
|
+
override fun createViewManagers(
|
|
30
|
+
reactContext: ReactApplicationContext
|
|
31
|
+
): List<ViewManager<*, *>> = emptyList()
|
|
32
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* ---------------------------------------------------------------------------
|
|
8
|
+
* Verbatim copy of
|
|
9
|
+
* ReactAndroid/src/main/jni/react/runtime/jni/JJSRuntimeFactory.h
|
|
10
|
+
*
|
|
11
|
+
* React Native exports only ReactCommon/jsitooling through its prefab headers,
|
|
12
|
+
* so an out-of-tree engine has to carry its own copy of this one. It is a pure
|
|
13
|
+
* declaration -- it binds to the com.facebook.react.runtime.JSRuntimeFactory
|
|
14
|
+
* class that ships in the app -- so the copy duplicates no code, only a version
|
|
15
|
+
* coupling. Re-check it when raising the supported React Native version.
|
|
16
|
+
* ---------------------------------------------------------------------------
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#pragma once
|
|
20
|
+
|
|
21
|
+
#include <fbjni/fbjni.h>
|
|
22
|
+
#include <jni.h>
|
|
23
|
+
#include <react/runtime/JSRuntimeFactory.h>
|
|
24
|
+
|
|
25
|
+
namespace facebook::react {
|
|
26
|
+
|
|
27
|
+
class JJSRuntimeFactory : public jni::HybridClass<JJSRuntimeFactory>,
|
|
28
|
+
public JSRuntimeFactory {
|
|
29
|
+
public:
|
|
30
|
+
static auto constexpr kJavaDescriptor =
|
|
31
|
+
"Lcom/facebook/react/runtime/JSRuntimeFactory;";
|
|
32
|
+
|
|
33
|
+
private:
|
|
34
|
+
friend HybridBase;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "JQuickJSInstance.h"
|
|
9
|
+
|
|
10
|
+
namespace facebook::react {
|
|
11
|
+
|
|
12
|
+
jni::local_ref<JQuickJSInstance::jhybriddata> JQuickJSInstance::initHybrid(
|
|
13
|
+
jni::alias_ref<jclass>) {
|
|
14
|
+
return makeCxxInstance();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
std::unique_ptr<JSRuntime> JQuickJSInstance::createJSRuntime(
|
|
18
|
+
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
|
|
19
|
+
return instance_.createJSRuntime(std::move(msgQueueThread));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void JQuickJSInstance::registerNatives() {
|
|
23
|
+
registerHybrid(
|
|
24
|
+
{makeNativeMethod("initHybrid", JQuickJSInstance::initHybrid)});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <fbjni/fbjni.h>
|
|
11
|
+
#include <react/runtime/JSRuntimeFactory.h>
|
|
12
|
+
|
|
13
|
+
#include <memory>
|
|
14
|
+
|
|
15
|
+
#include "JJSRuntimeFactory.h"
|
|
16
|
+
#include "QuickJSInstance.h"
|
|
17
|
+
|
|
18
|
+
namespace facebook::react {
|
|
19
|
+
|
|
20
|
+
class MessageQueueThread;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The fbjni hybrid behind the Kotlin QuickJSInstance, mirroring React Native's
|
|
24
|
+
* own JHermesInstance: the Java-side object is a JSRuntimeFactory and the C++
|
|
25
|
+
* side answers createJSRuntime().
|
|
26
|
+
*/
|
|
27
|
+
class JQuickJSInstance
|
|
28
|
+
: public jni::HybridClass<JQuickJSInstance, JJSRuntimeFactory> {
|
|
29
|
+
public:
|
|
30
|
+
static constexpr auto kJavaDescriptor =
|
|
31
|
+
"Lcom/reactnativequickjs/quickjs/QuickJSInstance;";
|
|
32
|
+
|
|
33
|
+
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
|
|
34
|
+
|
|
35
|
+
static void registerNatives();
|
|
36
|
+
|
|
37
|
+
std::unique_ptr<JSRuntime> createJSRuntime(
|
|
38
|
+
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept;
|
|
39
|
+
|
|
40
|
+
private:
|
|
41
|
+
friend HybridBase;
|
|
42
|
+
|
|
43
|
+
QuickJSInstance instance_;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <fbjni/fbjni.h>
|
|
9
|
+
|
|
10
|
+
#include "JQuickJSInstance.h"
|
|
11
|
+
|
|
12
|
+
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/) {
|
|
13
|
+
return facebook::jni::initialize(
|
|
14
|
+
vm, [] { facebook::react::JQuickJSInstance::registerNatives(); });
|
|
15
|
+
}
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* Expo resolves a plugin referenced by package name to app.plugin.js at the
|
|
8
|
+
* package root.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
module.exports = require('./scripts/expo/plugin.js');
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import <react/runtime/JSRuntimeFactoryCAPI.h>
|
|
9
|
+
|
|
10
|
+
#ifdef __cplusplus
|
|
11
|
+
extern "C" {
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates the QuickJS engine factory, as a drop-in replacement for
|
|
16
|
+
* `jsrt_create_hermes_factory()`.
|
|
17
|
+
*
|
|
18
|
+
* Override `createJSRuntimeFactory` on your React Native factory delegate:
|
|
19
|
+
*
|
|
20
|
+
* - (JSRuntimeFactoryRef)createJSRuntimeFactory
|
|
21
|
+
* {
|
|
22
|
+
* return jsrt_create_quickjs_factory();
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* Ownership of the returned factory transfers to React Native, which releases
|
|
26
|
+
* it with `js_runtime_factory_destroy`.
|
|
27
|
+
*/
|
|
28
|
+
JSRuntimeFactoryRef jsrt_create_quickjs_factory(void);
|
|
29
|
+
|
|
30
|
+
#ifdef __cplusplus
|
|
31
|
+
}
|
|
32
|
+
#endif
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Ammar Ahmed.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import "RCTQuickJSInstanceFactory.h"
|
|
9
|
+
|
|
10
|
+
#import "QuickJSInstance.h"
|
|
11
|
+
|
|
12
|
+
using namespace facebook::react;
|
|
13
|
+
|
|
14
|
+
JSRuntimeFactoryRef jsrt_create_quickjs_factory(void) {
|
|
15
|
+
return reinterpret_cast<JSRuntimeFactoryRef>(new QuickJSInstance());
|
|
16
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Ammar Ahmed.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const run = require('../scripts/setup/run.js');
|
|
12
|
+
const [command, ...argv] = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
if (command in run) {
|
|
15
|
+
process.exit(run[command](argv));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(`
|
|
19
|
+
react-native-quickjs
|
|
20
|
+
|
|
21
|
+
install configure this app to run on QuickJS
|
|
22
|
+
revert configure it back to Hermes
|
|
23
|
+
doctor report which parts are configured
|
|
24
|
+
|
|
25
|
+
--project <path> act on this app instead of the current directory
|
|
26
|
+
--dry-run show what would change, write nothing
|
|
27
|
+
`);
|
|
28
|
+
process.exit(command === undefined || command === '--help' || command === '-h' ? 0 : 1);
|
package/cmake/jsi.cmake
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright (c) Ammar Ahmed.
|
|
2
|
+
#
|
|
3
|
+
# This source code is licensed under the MIT license found in the
|
|
4
|
+
# LICENSE file in the root directory of this source tree.
|
|
5
|
+
#
|
|
6
|
+
# Defines the `jsi` static library.
|
|
7
|
+
#
|
|
8
|
+
# It compiles React Native's own copy of JSI, not a vendored one. jsi::Runtime
|
|
9
|
+
# is abstract, so building against different headers than the app links is a
|
|
10
|
+
# vtable mismatch: it compiles, links, and crashes at the first virtual call.
|
|
11
|
+
|
|
12
|
+
set(REACT_NATIVE_DIR "${CMAKE_CURRENT_LIST_DIR}/../node_modules/react-native"
|
|
13
|
+
CACHE PATH "Path to the react-native package")
|
|
14
|
+
set(JSI_DIR "${REACT_NATIVE_DIR}/ReactCommon/jsi")
|
|
15
|
+
|
|
16
|
+
if(NOT EXISTS "${JSI_DIR}/jsi/jsi.cpp")
|
|
17
|
+
message(FATAL_ERROR
|
|
18
|
+
"Could not find JSI at ${JSI_DIR}.\n"
|
|
19
|
+
"Run `npm install` first, or pass -DREACT_NATIVE_DIR=/path/to/react-native")
|
|
20
|
+
endif()
|
|
21
|
+
|
|
22
|
+
add_library(jsi STATIC "${JSI_DIR}/jsi/jsi.cpp")
|
|
23
|
+
target_include_directories(jsi PUBLIC "${JSI_DIR}")
|
|
24
|
+
set_target_properties(jsi PROPERTIES POSITION_INDEPENDENT_CODE ON)
|