πŸš€ Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more β†’
Sign In

@d11/dota

Package Overview
Dependencies
Maintainers
6
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@d11/dota - npm Package Compare versions

Comparing version
1.1.0
to
1.2.0
+39
-15
android/codepush.gradle

@@ -61,2 +61,27 @@ // Adapted from https://raw.githubusercontent.com/facebook/react-native/d16ff3bd8b92fa84a9007bf5ebedd8153e4c089d/react.gradle

// Configure Hermes flags for base bytecode optimization
def baseBundlePath = project.hasProperty('dotaBaseBundlePath') ? project.dotaBaseBundlePath :
System.getenv('DOTA_BASE_BUNDLE_PATH') ?: null
if (baseBundlePath != null) {
def isBundleFileExists = file(baseBundlePath).exists()
if (isBundleFileExists) {
if (project.hasProperty('hermesEnabled') && project.hermesEnabled.toBoolean()) {
def currentFlags = config.hermesFlags ? new ArrayList(config.hermesFlags.get()) : new ArrayList([])
if (!currentFlags.any { it.contains("--base-bytecode") }) {
currentFlags.add("--base-bytecode")
currentFlags.add(baseBundlePath)
config.hermesFlags.set(currentFlags)
println "[DOTA] Added base bytecode flags to Hermes configuration"
} else {
println "[DOTA] Hermes bytecode optimization already enabled"
}
}
} else {
println "[DOTA] Skipping base bytecode optimization, base bundle file does not exist: ${baseBundlePath}"
}
} else {
println "[DOTA] Skipping base bytecode optimization, base bundle path is not set"
}
gradle.projectsEvaluated {

@@ -158,7 +183,4 @@ def debuggableVariants = config.debuggableVariants ? config.debuggableVariants.get() : ['debug']

println "Configuring copyCodePushBundle task for ${targetName}"
println "jsBundleDir: ${jsBundleDir}"
println "resourcesDir: ${resourcesDir}"
println "CprojectDir: ${projectDir}"
println "[DOTA] Configuring copyCodePushBundle task for ${targetName}"
println "[DOTA] Project directory: ${projectDir}"

@@ -175,3 +197,3 @@ from jsBundleDir

doLast {
println "Completed copyCodePushBundle task for ${targetName}"
println "[DOTA] Completed copyCodePushBundle task for ${targetName}"
}

@@ -188,11 +210,13 @@ }

// Ensure the copy task runs after the bundle and assets are created
copyCodePushBundle.dependsOn("createBundle${targetName}JsAndAssets")
// Run the copy task before any tasks that need the copied files
runBefore("processArmeabi-v7a${targetName}Resources", copyCodePushBundle)
runBefore("processX86${targetName}Resources", copyCodePushBundle)
runBefore("processUniversal${targetName}Resources", copyCodePushBundle)
runBefore("process${targetName}Resources", copyCodePushBundle)
def shouldCopyBundle = project.hasProperty('dotaCopyBundle') ? project.dotaCopyBundle.toBoolean() : true
if (shouldCopyBundle) {
copyCodePushBundle.dependsOn("createBundle${targetName}JsAndAssets")
runBefore("processArmeabi-v7a${targetName}Resources", copyCodePushBundle)
runBefore("processX86${targetName}Resources", copyCodePushBundle)
runBefore("processUniversal${targetName}Resources", copyCodePushBundle)
runBefore("process${targetName}Resources", copyCodePushBundle)
} else {
println "[DOTA] Skipping copyCodePushBundle task for ${targetName}, dotaCopyBundle is set to ${shouldCopyBundle}"
}
}
}
}

@@ -32,2 +32,17 @@ require 'xcodeproj'

# Source the .xcode.env file
ENV_PATH="$PODS_ROOT/../.xcode.env"
if [ -f "$ENV_PATH" ]; then
source "$ENV_PATH"
echo "Env variables sourced from $ENV_PATH"
else
echo "Env file $ENV_PATH not found. Ensure it exists."
fi
echo "Dota - DOTA_COPY_BUNDLE: $DOTA_COPY_BUNDLE"
if [[ "$DOTA_COPY_BUNDLE" == "false" ]]; then
echo "Dota - Skipping bundle copy as DOTA_COPY_BUNDLE is set to false."
exit 0
fi
BUNDLE_NAME="main"

@@ -34,0 +49,0 @@ DEST="$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH"

{
"name": "@d11/dota",
"version": "1.1.0",
"version": "1.2.0",
"description": "React Native plugin for the CodePush service",

@@ -5,0 +5,0 @@ "main": "CodePush.js",

+166
-70
# React Native Module for OTA Updates
Instantly deliver JS and asset updates to your React Native apps. Know more about [OTA Updates](docs/ota-updates.md)
<!-- React Native Catalog -->
Instantly deliver JS and asset updates to your React Native apps. Know more about [OTA Updates](docs/ota-updates.md).
* [Getting Started](#getting-started)
* [Usage](#usage)
* [Creating the JavaScript bundle](#creating-the-javascript-bundle-hermes)
* [Releasing Updates](#releasing-updates)
* [Debugging](#debugging)
* [Advanced Topics](#advanced-topics)
* [API Reference](#api-reference)
## πŸš€ Key Features
<!-- React Native Catalog -->
- **Full and Patch Bundle Updates**: Deliver both full updates and efficient patch updates by sending only the differences.
- **Brotli Compression Support**: Utilize [Brotli compression](https://github.com/ds-horizon/delivr-cli#release-management) to optimize both full and patch bundles for even smaller sizes compared to the default deflate algorithm.
- **Base Bytecode Optimization**: Reduce patch bundle sizes significantly using the [bytecode](#understanding-base-bytecode-optimization) structure of your base bundle.
- **Automated Bundle Handling**: Automatically manage bundles for both Android and iOS, ensuring seamless integration with the DOTA platform.
- **Flexible Configuration**: Leverage CLI capabilities for custom configuration needs. See [Delivr CLI](https://github.com/ds-horizon/delivr-cli) for more details.
- **Architecture Support**: Compatible with both old and new architecture setups.
## Getting Started
## πŸ”§ Getting Started with DOTA
You can add [DOTA](docs/ota-updates.md) to your React Native app by running the following command from within your app's root directory:
Integrate DOTA into your React Native app seamlessly:
* Yarn
### Installation
Run the following command from your app's root directory:
```shell
# Yarn
yarn add @d11/dota
```
* NPM
```shell
# NPM
npm install @d11/dota
```
As with all other React Native plugins, the integration experience is different for iOS and Android, so perform the following setup steps depending on which platform(s) you are targeting. Note, if you are targeting both platforms it is recommended to create separate DOTA applications for each platform through DOTA dashboard.
### Setup
Then continue with installing the native module
* [iOS Setup](docs/setup-ios.md)
* [Android Setup](docs/setup-android.md)
Wrap your root component with `codePush` to enable OTA updates:
## Usage
```javascript
import codePush from "@d11/dota";
The only thing left is to add the necessary code to your app to control the following policies:
function MyApp() {
// Your app code here
}
1. When (and how often) to check for an update? (for example app start, in response to clicking a button in a settings page, periodically at some fixed interval)
export default codePush(MyApp);
```
2. When an update is available, how to present it to the end user?
Additionally, complete the platform-specific setup to ensure full integration:
The simplest way to get started:
- [iOS Setup](docs/setup-ios.md)
- [Android Setup](docs/setup-android.md)
* Wrap your root component with the `codePush`:
### Default Behavior and Configuration
```javascript
import codePush from "@d11/dota";
By default, DOTA checks for updates every time the app starts. Updates download silently and apply on the next restart, ensuring a smooth experience. Mandatory updates install immediately to deliver critical updates promptly.
function MyApp () {
...
}
#### Customize Update Policies
export default codePush(MyApp);
```
- **Check Frequency**: Configure when to check for updates (e.g., on app start, button press).
- **User Notification**: Decide how users will be notified about updates.
By default, DOTA will check for updates on every app start. If an update is available, it will be silently downloaded, and installed the next time the app is restarted (either explicitly by the end user or by the OS), which ensures the least invasive experience for your end users. If an available update is mandatory, then it will be installed immediately, ensuring that the end user gets it as soon as possible.
For more advanced configurations, consult the [DOTA API reference](docs/api-js.md#dota).
If you would like your app to discover updates more quickly, you can refer to the [DOTA API reference](docs/api-js.md#dota)
## Creating the JavaScript bundle (Hermes)
There are two ways to generate the JavaScript bundle for DOTA:
### 1. Build-time Bundling (Recommended)
### 1. Automated Bundle Generation (Recommended)
This method effortlessly integrates DOTA and Hermes by automatically using the bundle generated during your app's build process.
This method automatically copies the bundle that is generated during your app's build process.
#### Android Setup
#### For Android:
Add to `android/app/build.gradle`. This ensures the bundle is copied to the `.dota/android` directory for processing.
Add this line to your `android/app/build.gradle`:
```gradle

@@ -77,28 +75,37 @@ apply from: "../../node_modules/@d11/dota/android/codepush.gradle"

#### For iOS:
To disable the default copying of the bundle, add the following in `gradle.properties`:
1. Add this line at the top of your `Podfile`:
```
dotaCopyBundle=false
```
#### iOS Setup
In your `Podfile`, add:
```ruby
# Import at the top
require_relative '../node_modules/@d11/dota/ios/scripts/dota_pod_helpers.rb'
```
Note: Make sure that it correctly points to node_modules path.
2. In the `post_install` block of your `Podfile`, add:
```ruby
# Include in the `post_install` block:
post_install do |installer|
# Add the Dota post install script
# Replace with your app's target name
dota_post_install(installer, <target>, File.expand_path(__dir__))
dota_post_install(installer, 'YourAppTarget', File.expand_path(__dir__))
end
```
3. Run pod install:
To disable the bundle copy process, set the environment variable in the `.xcode.env` file or directly in the CLI:
```bash
export DOTA_COPY_BUNDLE=false
```
Run:
```bash
cd ios && pod install
```
This will add a new build phase named "[Dota] Copy DOTA Bundle" that automatically handles bundle generation and copying. The bundles and assets will be generated in `.dota/<platform>` directory at your project root.
This ensures the bundle is copied to the `.dota/ios` directory for processing.
### 2. Manual Bundle Generation (Using CLI Tool)
### 2. Manual Bundle Generation

@@ -115,5 +122,5 @@ Use this method if you need more control over the bundle generation process or need to generate bundles outside of the build process.

#### Available Options
#### CLI Options
The CLI supports the following options:
Customize with available options:

@@ -123,8 +130,9 @@ ```bash

--platform <platform> Specify platform: android or ios (required)
--bundle-path <path> Directory to place the bundle in (default: ".dota")
--assets-path <path> Directory to place assets in (default: ".dota")
--sourcemap-path <path> Directory to place sourcemaps in (default: ".dota")
--bundle-path <path> Directory to place the bundle in, default is .dota/<platform> (default: ".dota")
--assets-path <path> Directory to place assets in, default is .dota/<platform> (default: ".dota")
--sourcemap-path <path> Directory to place sourcemaps in, default is .dota/<platform> (default: ".dota")
--make-sourcemap Generate sourcemap (default: false)
--entry-file <file> Entry file (default: "index.ts")
--dev <boolean> Development mode (default: "false")
--base-bundle-path <path> Path to base bundle for Hermes bytecode optimization
-h, --help Display help for command

@@ -136,15 +144,103 @@

#### Output Files
> **Note**: When generating a patch bundle using this script, ensure that the base bundle shipped with the APK is identical to the one generated here. Any discrepancy in flags, especially if additional flags are passed to React Native during bundle generation, may lead to patch application issues. If uncertain, follow the Automated Bundle Generation step to maintain consistency.
By default, the CLI will generate:
- For Android:
- `.dota/index.android.bundle` - The optimized Hermes bundle
- `.dota/` - Directory containing any assets
- `.dota/index.android.bundle.json` - Sourcemap file (if --make-sourcemap is enabled)
## ✨ Base Bytecode Optimization (New Feature)
- For iOS:
- `.dota/main.jsbundle` - The optimized Hermes bundle
- `.dota/` - Directory containing any assets
- `.dota/main.jsbundle.json` - Sourcemap file (if --make-sourcemap is enabled)
> Base bytecode optimization is available starting from version 1.2.0.
Significantly reduce patch bundle size using base bytecode optimization. There are two ways to set this up, depending on your bundle generation method. For more details, see [Understanding Base Bytecode Optimization](#understanding-base-bytecode-optimization) below.
### Automated Setup
Ensure your [automated bundle generation](#1-automated-bundle-generation-recommended) is configured, and set up your environment as follows:
- **Android**: Use any of the following methods to specify the base bundle path:
- Command line option:
```bash
./gradlew assembleRelease -PdotaBaseBundlePath=/path/to/base/bundle
```
- Environment variable:
```bash
export DOTA_BASE_BUNDLE_PATH=/path/to/base/bundle
./gradlew assembleRelease
```
- `gradle.properties` file:
```
dotaBaseBundlePath=/path/to/base/bundle
```
- **iOS**: To enable base bytecode optimization, you'll need to modify `node_modules/react-native/scripts/react-native-xcode.sh`. Since React Native doesn’t directly expose this feature, creating a patch is essential for implementing custom changes.
**Patch Package Setup** (Skip if already installed):
1. Install [patch-package](https://www.npmjs.com/package/patch-package):
```bash
yarn add patch-package postinstall-postinstall --dev
```
2. Add a postinstall script to ensure patches are applied:
```json
{
"scripts": {
"postinstall": "patch-package"
}
}
```
**Modify and Create Patch**: Locate `node_modules/react-native/scripts/react-native-xcode.sh` and add support for base bytecode. Insert the following code **before the Hermes CLI execution block**:
```bash
# Inside react-native-xcode.sh
BASE_BYTECODE_PATH=""
if [[ ! -z $DOTA_BASE_BUNDLE_PATH ]]; then
if [[ -f $DOTA_BASE_BUNDLE_PATH ]]; then
BASE_BYTECODE_PATH="--base-bytecode $DOTA_BASE_BUNDLE_PATH"
echo "Using --base-bytecode with path: $DOTA_BASE_BUNDLE_PATH"
else
echo "Not using --base-bytecode, path: $DOTA_BASE_BUNDLE_PATH, file not found"
BASE_BYTECODE_PATH=""
fi
fi
"$HERMES_CLI_PATH" -emit-binary -max-diagnostic-width=80 $EXTRA_COMPILER_ARGS -out "$DEST/$BUNDLE_NAME.jsbundle" "$BUNDLE_FILE" $BASE_BYTECODE_PATH
```
Create the patch using:
```bash
yarn patch-package react-native
```
**Environment Configuration**: Configure the base bundle path through an environment variable:
- In `.xcode.env`:
```bash
export DOTA_BASE_BUNDLE_PATH=/path/to/base.bundle
```
- Or directly within a terminal session:
```bash
export DOTA_BASE_BUNDLE_PATH=/path/to/base.bundle && yarn ios --mode=Release
```
### Manual Bundle Generation
When using [manual bundle generation](#2-manual-bundle-generation), configure the CLI with the `--base-bundle-path` option:
```bash
yarn dota bundle --platform android --base-bundle-path .dota/android/index.android.bundle
```
> **Note**: To opt-out of using the base bytecode optimization feature, ensure the DOTA_BASE_BUNDLE_PATH environment variable is not set. You can unset it by executing unset DOTA_BASE_BUNDLE_PATH. Alternatively, during manual bundle generation, simply omit the --base-bundle-path option.
### Understanding Base Bytecode Optimization
Base bytecode optimization enables smaller patch bundles by utilizing the bytecode structure of a previously created base bundle. When you generate updates, this previous bundle acts as a reference, ensuring only changes are transmitted. This method enhances performance, reducing data usage and ensuring faster updates.
## Releasing Updates

@@ -151,0 +247,0 @@

@@ -21,3 +21,3 @@ #!/bin/bash

if [[ -z "$1" || -z "$2" ]]; then
if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
echo "Failed to run bundle-to-binary.sh. No input file provided. Please refer to documentation in the script."

@@ -28,2 +28,4 @@ exit 1

HBC_BUNDLE_FILE="$2"
PLATFORM="$3"
MAKE_SOURCEMAP="$4"
fi

@@ -41,8 +43,32 @@

HBC_SOURCEMAP_FLAGS="-output-source-map"
HBC_SOURCEMAP_FLAGS=""
# create binary bundle from js bundle (-O=optmised, -w=no-warnings)
${HERMESC} -emit-binary -out ${HBC_BUNDLE_FILE} ${JS_BUNDLE_FILE} -O -w ${HBC_SOURCEMAP_FLAGS}
# For android we always pass the sourcemap flag, to match react native android bundle generation behaviour. Check:https://github.com/facebook/react-native/blob/f9754d34590fe4d988065a92de5d512883de3b33/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt#L127
if [[ "$PLATFORM" == "android" ]]; then
HBC_SOURCEMAP_FLAGS="-output-source-map"
fi
if [[ "$PLATFORM" == "ios" && ! -z "$MAKE_SOURCEMAP" ]]; then
HBC_SOURCEMAP_FLAGS="-output-source-map"
fi
EXTRA_FLAGS=""
if [[ ! -z "${BASE_BUNDLE_PATH}" ]]; then
if [[ -f "${BASE_BUNDLE_PATH}" ]]; then
echo "Using base bytecode flag: ${BASE_BUNDLE_PATH}"
EXTRA_FLAGS="--base-bytecode ${BASE_BUNDLE_PATH}"
else
echo "Warning: Base bytecode file not found: ${BASE_BUNDLE_PATH}"
fi
fi
# create binary bundle from js bundle (-O=optmised, -w=no-warnings)
${HERMESC} -emit-binary -out ${HBC_BUNDLE_FILE} ${JS_BUNDLE_FILE} -O -w ${HBC_SOURCEMAP_FLAGS} ${EXTRA_FLAGS}
# Cleanup source map, since it is not required if make sourcemap is not defined
HBC_SOURCEMAP_FILE="${JS_BUNDLE_FILE}.hbc.map"
if [[ "$PLATFORM" == "android" && -z "$MAKE_SOURCEMAP" ]]; then
rm ${HBC_SOURCEMAP_FILE}
fi
echo "Wrote HBC output to: ${HBC_BUNDLE_FILE}"

@@ -63,3 +63,3 @@ #!/bin/bash

./node_modules/@d11/dota/scripts/bundle/bundle-to-binary.sh ${JS_BUNDLE_FILE} ${HBC_TEMP_FILE}
./node_modules/@d11/dota/scripts/bundle/bundle-to-binary.sh ${JS_BUNDLE_FILE} ${HBC_TEMP_FILE} ${PLATFORM} ${MAKE_SOURCEMAP}

@@ -69,7 +69,2 @@ echo "Replacing JS bundle with HBC"

# Clean up sourcemap if not required
if [[ -z "${MAKE_SOURCEMAP}" ]]; then
rm ${HBC_SOURCEMAP_FILE}
fi
#####################################################################

@@ -76,0 +71,0 @@ # Compose sourcemaps if required

@@ -12,3 +12,3 @@ #!/usr/bin/env node

.name('dota')
.description('CLI tool for bundling React Native apps with CodePush')
.description('DOTA CLI tool for bundling React Native apps with CodePush')
.version('1.0.0');

@@ -18,10 +18,11 @@

.command('bundle')
.description('Generate a JS bundle and assets, compile to HBC and optionally emit sourcemap')
.description('Generate a Hermes bundle and assets, compile to HBC and optionally emit sourcemap')
.requiredOption('--platform <platform>', 'Specify platform: android or ios')
.option('--bundle-path <path>', 'Directory to place the bundle in', '.dota')
.option('--assets-path <path>', 'Directory to place assets in', '.dota')
.option('--sourcemap-path <path>', 'Directory to place sourcemaps in', '.dota')
.option('--bundle-path <path>', 'Directory to place the bundle in, default is .dota/<platform>', '.dota')
.option('--assets-path <path>', 'Directory to place assets in, default is .dota/<platform>', '.dota')
.option('--sourcemap-path <path>', 'Directory to place sourcemaps in, default is .dota/<platform>', '.dota')
.option('--make-sourcemap <boolean>', 'Generate sourcemap: true or false', 'false')
.option('--entry-file <file>', 'Entry file', 'index.ts')
.option('--dev <boolean>', 'Development mode', 'false')
.option('--base-bundle-path <path>', 'Path to base bundle', '')
.allowUnknownOption() // Allow additional options to be passed to react-native bundle

@@ -35,2 +36,6 @@ .action((options) => {

options.bundlePath = path.join(options.bundlePath, options.platform);
options.assetsPath = path.join(options.assetsPath, options.platform);
options.sourcemapPath = path.join(options.sourcemapPath, options.platform);
// Create necessary directories

@@ -53,3 +58,3 @@ [options.bundlePath, options.assetsPath, options.sourcemapPath].forEach(dir => {

process.env.ENTRY_FILE = options.entryFile;
process.env.BASE_BUNDLE_PATH = options.baseBundlePath || '';
// Build the bundle command using the existing script

@@ -56,0 +61,0 @@ const bundleCommand = [