Skip to content

Commit dfa83aa

Browse files
committed
plugin: support prebuilt native modules and skip their compilation
1 parent 4c89c02 commit dfa83aa

File tree

3 files changed

+114
-13
lines changed

3 files changed

+114
-13
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,28 @@ echo "1" > nodejs-assets/BUILD_NATIVE_MODULES.txt
7777
react-native run-ios
7878
```
7979

80+
##### Prebuilds
81+
82+
The plugin also automatically detects the presence of prebuilt native modules, and **disables** compiling them on the fly. The prebuilds are detected as `.node` files in a specific path in the npm package:
83+
84+
```
85+
nodejs-assets/nodejs-project/node_modules/<MODULE_NAME>/prebuilds/<PLATFORM>-<ARCH>/<NAME>.node
86+
```
87+
88+
Notice `PLATFORM` and `ARCH`. The supported values are:
89+
90+
- PLATFORM = `android`
91+
- ARCH = `arm`
92+
- ARCH = `arm64`
93+
- ARCH = `x64`
94+
- PLATFORM = `ios`
95+
- ARCH = `arm64`
96+
- ARCH = `x64`
97+
98+
Compilation will then be forcefully disabled by hacking the `<MODULE_NAME>` folder to delete its `binding.gyp` and modify its `package.json` such that node-gyp will ignore this module for compilation.
99+
100+
If you are a maintainer of a native module and want to support prebuilds for nodejs-mobile, check out the CLI tool [prebuild-for-nodejs-mobile](https://github.com/staltz/prebuild-for-nodejs-mobile).
101+
80102
### `React-Native` application
81103

82104
To communicate with Node.js from your `react-native` application, first import `nodejs-mobile-react-native`.

android/build.gradle

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ if (shouldRebuildNativeModules==null) {
183183
}
184184

185185
if ("1".equals(shouldRebuildNativeModules)) {
186-
187186
String npmCommandName = 'npm';
188187
String nodeCommandName = 'node';
189188
if (OperatingSystem.current().isMacOsX()) {
@@ -366,8 +365,47 @@ if ("1".equals(shouldRebuildNativeModules)) {
366365
}
367366
}
368367

369-
task "BuildNpmModules${abi_name}" (type:Exec) {
368+
task "DeleteIncorrectPrebuilds${abi_name}" (type:Delete) {
370369
dependsOn "CopyNodeProjectAssets${abi_name}"
370+
description = "Delete all .node files except the prebuilt ones for ${abi_name}."
371+
372+
delete fileTree(dir: "${rootProject.buildDir}/nodejs-native-assets-temp-build/nodejs-native-assets-${abi_name}/nodejs-project/node_modules/").matching {
373+
include "**/*.node" // Look for all .node files
374+
exclude "**/prebuilds/android-${temp_arch}/*" // Don't touch the correct prebuilds
375+
}
376+
}
377+
378+
task "DetectCorrectPrebuilds${abi_name}" {
379+
dependsOn "DeleteIncorrectPrebuilds${abi_name}"
380+
description = "Handle npm packages that have a correct prebuild for ${abi_name}."
381+
inputs.file "${rootProject.buildDir}/nodejs-native-assets-temp-build/nodejs-native-assets-${abi_name}/copy.timestamp"
382+
outputs.dir "${rootProject.buildDir}/nodejs-native-assets-temp-build/nodejs-native-assets-${abi_name}/nodejs-project/"
383+
384+
doLast {
385+
def correctDotNodes = fileTree(dir: "${rootProject.buildDir}/nodejs-native-assets-temp-build/nodejs-native-assets-${abi_name}/nodejs-project/node_modules/").matching {
386+
include "**/prebuilds/android-${temp_arch}/*.node"
387+
}
388+
for (dotNode in correctDotNodes) {
389+
def moduleRoot = file("${dotNode.getAbsoluteFile()}/../../..")
390+
def moduleName = moduleRoot.getName()
391+
println "Preparing to use the prebuild in ${moduleName}"
392+
delete "${moduleRoot}/build"
393+
copy {
394+
from "${dotNode.getAbsoluteFile()}"
395+
into "${moduleRoot}/build/Release/"
396+
}
397+
exec {
398+
workingDir moduleRoot
399+
commandLine 'sed', '-i.bak', 's/"install"/"dontinstall"/g; s/"rebuild"/"dontrebuild"/g; s/"gypfile"/"dontgypfile"/g', 'package.json'
400+
}
401+
delete "${moduleRoot}/binding.gyp"
402+
delete "${moduleRoot}/prebuilds"
403+
}
404+
}
405+
}
406+
407+
task "BuildNpmModules${abi_name}" (type:Exec) {
408+
dependsOn "DetectCorrectPrebuilds${abi_name}"
371409
description = "Building native modules for ${abi_name}."
372410
def nodeVersionStdout = new ByteArrayOutputStream()
373411
def nodeVersionResult = exec {

scripts/ios-build-native-modules.sh

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ $(node -p 'process.versions.node')"
1717
exit 1
1818
fi
1919

20+
# This is our nodejs-project folder that was copied to the Xcode build folder
21+
NODEPROJ="$CODESIGNING_FOLDER_PATH/nodejs-project"
22+
2023
if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
2124
# If build native modules preference is not set, look for it in the project's
2225
#nodejs-assets/BUILD_NATIVE_MODULES.txt file.
@@ -30,7 +33,7 @@ fi
3033
if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
3134
# If build native modules preference is not set, try to find .gyp files
3235
#to turn it on.
33-
gypfiles=($(find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -type f -name "*.gyp"))
36+
gypfiles=($(find "$NODEPROJ" -type f -name "*.gyp"))
3437
if [ ${#gypfiles[@]} -gt 0 ]; then
3538
NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
3639
else
@@ -41,20 +44,58 @@ fi
4144
if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
4245

4346
# Delete object files that may already come from within the npm package.
44-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.o" -type f -delete
45-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.a" -type f -delete
46-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.node" -type f -delete
47+
find "$NODEPROJ" -name "*.o" -type f -delete
48+
find "$NODEPROJ" -name "*.a" -type f -delete
49+
50+
# Function to skip compilation of a prebuilt module
51+
preparePrebuiltModule()
52+
{
53+
local DOT_NODE_PATH="$1"
54+
local DOT_NODE_FULL="$(cd "$(dirname -- "$DOT_NODE_PATH")" >/dev/null; pwd -P)/$(basename -- "$DOT_NODE_PATH")"
55+
local MODULE_ROOT="$(cd $DOT_NODE_PATH && cd .. && cd .. && cd .. && pwd)"
56+
local MODULE_NAME="$(basename $MODULE_ROOT)"
57+
echo "Preparing to use the prebuild in $MODULE_NAME"
58+
# Move the prebuild to the correct folder:
59+
rm -rf $MODULE_ROOT/build
60+
mkdir -p $MODULE_ROOT/build/Release
61+
mv $DOT_NODE_FULL $MODULE_ROOT/build/Release/
62+
# Hack the npm package to forcefully disable compile-on-install:
63+
rm -rf $MODULE_ROOT/binding.gyp
64+
sed -i.bak 's/"install"/"dontinstall"/g; s/"rebuild"/"dontrebuild"/g; s/"gypfile"/"dontgypfile"/g' $MODULE_ROOT/package.json
65+
}
66+
67+
# Delete bundle contents that may be there from previous builds.
68+
# Handle the special case where the module has a prebuild that we want to use
69+
if [ "$PLATFORM_PREFERRED_ARCH" == "arm64" ]; then
70+
PREBUILD_ARCH="arm64"
71+
else
72+
PREBUILD_ARCH="x64"
73+
fi
74+
find -E "$NODEPROJ" \
75+
! -regex ".*/prebuilds/ios-$PREBUILD_ARCH" \
76+
-regex '.*/prebuilds/[^/]*$' -type d \
77+
-prune -exec rm -rf "{}" \;
78+
find -E "$NODEPROJ" \
79+
! -regex ".*/prebuilds/ios-$PREBUILD_ARCH/.*\.node$" \
80+
-name '*.node' -type f \
81+
-exec rm "{}" \;
82+
find "$NODEPROJ" \
83+
-name "*.framework" -type d \
84+
-prune -exec rm -rf "{}" \;
85+
PREBUILD_DOT_NODES=`find -E "$NODEPROJ" -regex ".*/prebuilds/ios-$PREBUILD_ARCH/.*\.node$"`
86+
for DOT_NODE in "$PREBUILD_DOT_NODES"
87+
do
88+
preparePrebuiltModule "$DOT_NODE"
89+
done
4790

4891
# Delete bundle contents that may be there from previous builds.
49-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.node/*" -delete
50-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.node" -type d -delete
51-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.framework/*" -delete
52-
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d -delete
92+
find "$NODEPROJ" -path "*/*.node/*" -delete
93+
find "$NODEPROJ" -name "*.node" -type d -delete
5394

5495
# Apply patches to the modules package.json
55-
if [ -d "$CODESIGNING_FOLDER_PATH"/nodejs-project/node_modules/ ]; then
96+
if [ -d "$NODEPROJ"/node_modules/ ]; then
5697
PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native/scripts/ && pwd )"
57-
NODEJS_PROJECT_MODULES_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd nodejs-project/node_modules/ && pwd )"
98+
NODEJS_PROJECT_MODULES_DIR="$( cd "$NODEPROJ" && cd node_modules && pwd )"
5899
node "$PATCH_SCRIPT_DIR"/patch-package.js $NODEJS_PROJECT_MODULES_DIR
59100
fi
60101

@@ -68,7 +109,7 @@ fi
68109

69110
# Rebuild modules with right environment
70111
NODEJS_HEADERS_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native/ios/libnode/ && pwd )"
71-
pushd $CODESIGNING_FOLDER_PATH/nodejs-project/
112+
pushd $NODEPROJ
72113
if [ "$PLATFORM_NAME" == "iphoneos" ]
73114
then
74115
GYP_DEFINES="OS=ios" \

0 commit comments

Comments
 (0)