Skip to content

feat(cli): add expo framework support to bundle command #73

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ Create a new release history for a specific binary app version.
**Example:**
- Create a new release history for the binary app version `1.0.0`.

```
```bash
npx code-push create-history --binary-version 1.0.0 --platform ios --identifier staging
```

Expand All @@ -342,7 +342,7 @@ Display the release history for a specific binary app version.
**Example:**
- Show the release history for the binary app version `1.0.0`.

```
```bash
npx code-push show-history --binary-version 1.0.0 --platform ios --identifier staging
```

Expand All @@ -354,11 +354,15 @@ Release a CodePush update for a specific binary app version.
**Example:**
- Release a CodePush update `1.0.1` targeting the binary app version `1.0.0`.

```
```bash
npx code-push release --binary-version 1.0.0 --app-version 1.0.1 \
--platform ios --identifier staging --entry-file index.js \
--mandatory true

# Expo project
npx code-push release --framework expo --binary-version 1.0.0 --app-version 1.0.1 --platform ios
```
- `--framework`(`-f`) : Framework type (expo)
- `--binary-version`: The version of the binary app that the CodePush update is targeting.
- `--app-version`: The version of the CodePush update itself.

Expand All @@ -375,7 +379,7 @@ Update the release history for a specific CodePush update.
**Example:**
- Rollback the CodePush update `1.0.1` (targeting the binary app version `1.0.0`).

```
```bash
npx code-push update-history --binary-version 1.0.0 --app-version 1.0.1 \
--platform ios --identifier staging \
--enable false
Expand All @@ -386,10 +390,17 @@ npx code-push update-history --binary-version 1.0.0 --app-version 1.0.1 \
Create a CodePush bundle file.

**Example:**
```
```bash
npx code-push bundle --platform android --entry-file index.js

# Expo project
npx code-push bundle --framework expo --platform android --entry-file index.js
```
- `--framework`(`-f`): Framework type (expo)

By default, the bundle file is created in the `/build/bundleOutput` directory.

> [!NOTE]
> For Expo projects, the CLI uses `expo export:embed` command for bundling instead of React Native's bundle command.

(The file name represents a hash value of the bundle content.)
28 changes: 21 additions & 7 deletions cli/commands/bundleCommand/bundleCodePush.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
const fs = require('fs');
const { prepareToBundleJS } = require('../../functions/prepareToBundleJS');
const { runReactNativeBundleCommand } = require('../../functions/runReactNativeBundleCommand');
const { runExpoBundleCommand } = require('../../functions/runExpoBundleCommand');
const { getReactTempDir } = require('../../functions/getReactTempDir');
const { runHermesEmitBinaryCommand } = require('../../functions/runHermesEmitBinaryCommand');
const { makeCodePushBundle } = require('../../functions/makeCodePushBundle');
const { ROOT_OUTPUT_DIR, ENTRY_FILE } = require('../../constant');

/**
* @param framework {string|undefined} 'expo'
* @param platform {string} 'ios' | 'android'
* @param outputRootPath {string}
* @param entryFile {string}
Expand All @@ -15,6 +17,7 @@ const { ROOT_OUTPUT_DIR, ENTRY_FILE } = require('../../constant');
* @return {Promise<string>} CodePush bundle file name (equals to packageHash)
*/
async function bundleCodePush(
framework,
platform = 'ios',
outputRootPath = ROOT_OUTPUT_DIR,
entryFile = ENTRY_FILE,
Expand All @@ -32,13 +35,24 @@ async function bundleCodePush(

prepareToBundleJS({ deleteDirs: [outputRootPath, getReactTempDir()], makeDir: OUTPUT_CONTENT_PATH });

runReactNativeBundleCommand(
_jsBundleName,
OUTPUT_CONTENT_PATH,
platform,
SOURCEMAP_OUTPUT,
entryFile,
);
if (framework === 'expo') {
runExpoBundleCommand(
_jsBundleName,
OUTPUT_CONTENT_PATH,
platform,
SOURCEMAP_OUTPUT,
entryFile,
);
} else {
runReactNativeBundleCommand(
_jsBundleName,
OUTPUT_CONTENT_PATH,
platform,
SOURCEMAP_OUTPUT,
entryFile,
);
}

console.log('log: JS bundling complete');

await runHermesEmitBinaryCommand(
Expand Down
3 changes: 3 additions & 0 deletions cli/commands/bundleCommand/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ const { OUTPUT_BUNDLE_DIR, ROOT_OUTPUT_DIR, ENTRY_FILE } = require('../../consta

program.command('bundle')
.description('Creates a CodePush bundle file (assumes Hermes is enabled).')
.addOption(new Option('-f, --framework <type>', 'framework type (expo)').choices(['expo']))
.addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
.option('-o, --output-path <string>', 'path to output root directory', ROOT_OUTPUT_DIR)
.option('-e, --entry-file <string>', 'path to JS/TS entry file', ENTRY_FILE)
.option('-b, --bundle-name <string>', 'bundle file name (default-ios: "main.jsbundle" / default-android: "index.android.bundle")')
.option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
/**
* @param {Object} options
* @param {string} options.framework
* @param {string} options.platform
* @param {string} options.outputPath
* @param {string} options.entryFile
Expand All @@ -20,6 +22,7 @@ program.command('bundle')
*/
.action((options) => {
bundleCodePush(
options.framework,
options.platform,
options.outputPath,
options.entryFile,
Expand Down
3 changes: 3 additions & 0 deletions cli/commands/releaseCommand/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ program.command('release')
.description('Deploys a new CodePush update for a target binary app.\nAfter creating the CodePush bundle, it uploads the file and updates the ReleaseHistory information.\n`bundleUploader`, `getReleaseHistory`, and `setReleaseHistory` functions should be implemented in the config file.')
.requiredOption('-b, --binary-version <string>', '(Required) The target binary version')
.requiredOption('-v, --app-version <string>', '(Required) The app version to be released. It must be greater than the binary version.')
.addOption(new Option('-f, --framework <type>', 'framework type (expo)').choices(['expo']))
.addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
.option('-i, --identifier <string>', 'reserved characters to distinguish the release.')
.option('-c, --config <path>', 'set config file name (JS/TS)', CONFIG_FILE_NAME)
Expand All @@ -22,6 +23,7 @@ program.command('release')
* @param {Object} options
* @param {string} options.binaryVersion
* @param {string} options.appVersion
* @param {string} options.framework
* @param {string} options.platform
* @param {string} options.identifier
* @param {string} options.config
Expand All @@ -44,6 +46,7 @@ program.command('release')
config.setReleaseHistory,
options.binaryVersion,
options.appVersion,
options.framework,
options.platform,
options.identifier,
options.outputPath,
Expand Down
4 changes: 3 additions & 1 deletion cli/commands/releaseCommand/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const { addToReleaseHistory } = require("./addToReleaseHistory");
* ): Promise<void>}
* @param binaryVersion {string}
* @param appVersion {string}
* @param framework {string|undefined} 'expo'
* @param platform {"ios" | "android"}
* @param identifier {string?}
* @param outputPath {string}
Expand All @@ -43,6 +44,7 @@ async function release(
setReleaseHistory,
binaryVersion,
appVersion,
framework,
platform,
identifier,
outputPath,
Expand All @@ -56,7 +58,7 @@ async function release(
) {
const bundleFileName = skipBundle
? readBundleFileNameFrom(bundleDirectory)
: await bundleCodePush(platform, outputPath, entryFile, jsBundleName, bundleDirectory);
: await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory);
const bundleFilePath = `${bundleDirectory}/${bundleFileName}`;

const downloadUrl = await (async () => {
Expand Down
53 changes: 53 additions & 0 deletions cli/functions/runExpoBundleCommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const path = require('path');
const shell = require('shelljs');

/**
* Run `expo bundle` CLI command
*
* @param bundleName {string} JS bundle file name
* @param entryFile {string} App code entry file name (default: index.ts)
* @param outputPath {string} Path to output JS bundle file and assets
* @param platform {string} Platform (ios | android)
* @param sourcemapOutput {string} Path to output sourcemap file (Warning: if sourcemapOutput points to the outputPath, the sourcemap will be included in the CodePush bundle and increase the deployment size)
* @return {void}
*/
function runExpoBundleCommand(
bundleName,
outputPath,
platform,
sourcemapOutput,
entryFile,
) {
/**
* @return {string}
*/
function getCliPath() {
return path.join('node_modules', '.bin', 'expo');
}

/**
* @type {string[]}
*/
const expoBundleArgs = [
'export:embed',
'--assets-dest',
outputPath,
'--bundle-output',
path.join(outputPath, bundleName),
'--dev',
'false',
'--entry-file',
entryFile,
'--platform',
platform,
'--sourcemap-output',
sourcemapOutput,
'--reset-cache',
];

console.log('Running "expo export:embed" command:\n');

shell.exec(`${getCliPath()} ${expoBundleArgs.join(' ')}`);
}

module.exports = { runExpoBundleCommand };