1
0
mirror of https://gitcode.com/github-mirrors/react-native-update-cli.git synced 2025-11-23 00:36:11 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

Compare commits

...

12 Commits

Author SHA1 Message Date
sunnylqm
cf679715a5 Remove unused copiesv2 variable from diffFromPPK and diffFromPackage functions in bundle.ts to streamline JSON output. 2025-11-22 01:16:18 +08:00
sunnylqm
ebd6d36b30 Update version to 2.4.1 in package.json and streamline file and keyword declarations; import fetch in http-helper.ts for enhanced HTTP functionality. 2025-11-19 13:41:41 +08:00
sunnylqm
818907f811 Refactor rollout configuration handling in bindVersionToPackages; replace rollout logic with direct package binding and update API call to use POST method. 2025-11-04 21:52:25 +08:00
sunnylqm
6751daf8e0 Update version to 2.3.2 in package.json and enhance search paths for @expo/cli in runReactNativeBundleCommand to include expo package directory. 2025-10-31 16:07:02 +08:00
sunnylqm
b973ace443 Update version to 2.3.1 in package.json and add support for harmony platform in runReactNativeBundleCommand to handle asset copying and file movement. 2025-10-26 18:05:18 +08:00
sunnylqm
e81744b52a Refactor bundle file handling by introducing isPPKBundleFileName utility; streamline diff logic for bundle files in bundle.ts. 2025-10-25 16:07:41 +08:00
sunnylqm
89da1e5238 fix typo 2025-10-25 15:52:53 +08:00
sunnylqm
603e2adf47 add install command 2025-10-25 15:49:35 +08:00
sunnylqm
317975cdba Update version to 2.3.0 in package.json 2025-10-25 12:19:18 +08:00
sunnylqm
f8edbb8083 Refactor Hermes option handling in CLI and bundle commands; rename 'disableHermes' to 'hermes' for clarity and update related logic in bundle.ts and provider.ts. 2025-10-25 11:20:09 +08:00
sunnylqm
15c8052459 Update version to 2.2.4 in package.json and enhance argument handling in runReactNativeBundleCommand for improved functionality. 2025-10-25 10:53:50 +08:00
sunnylqm
c633af549d Update version to 2.2.3 in package.json and implement recursive file copying with special handling for assets in bundle.ts 2025-10-24 23:58:57 +08:00
13 changed files with 150 additions and 168 deletions

View File

@@ -213,7 +213,7 @@
"rncli": {
"default": false
},
"disableHermes": {
"hermes": {
"default": false
},
"name": {
@@ -299,15 +299,6 @@
}
}
},
"hdiffFromPPK": {
"description": "Create hdiff patch from a Prepare package(.ppk)",
"options": {
"output": {
"default": "${tempDir}/output/hdiff-${time}.ppk-patch",
"hasValue": true
}
}
},
"hdiffFromApp": {
"description": "Create hdiff patch from a Harmony package(.app)",
"options": {
@@ -343,6 +334,10 @@
"hasValue": true
}
}
},
"install": {
"description": "Install optional dependencies to the CLI",
"options": {}
}
},
"globalOptions": {

View File

@@ -1,17 +1,13 @@
{
"name": "react-native-update-cli",
"version": "2.2.2",
"version": "2.4.2",
"description": "command line tool for react-native-update (remote updates for react native)",
"main": "index.js",
"bin": {
"pushy": "lib/index.js",
"cresc": "lib/index.js"
},
"files": [
"lib",
"src",
"cli.json"
],
"files": ["lib", "src", "cli.json"],
"scripts": {
"build": "swc src -d lib --strip-leading-paths",
"prepublishOnly": "npm run build && chmod +x lib/index.js",
@@ -21,13 +17,7 @@
"type": "git",
"url": "git+https://github.com/reactnativecn/react-native-update-cli.git"
},
"keywords": [
"react-native",
"ios",
"android",
"harmony",
"update"
],
"keywords": ["react-native", "ios", "android", "harmony", "update"],
"author": "reactnativecn",
"license": "BSD-3-Clause",
"bugs": {
@@ -81,8 +71,5 @@
"@types/yazl": "^2.4.6",
"typescript": "^5.8.3"
},
"trustedDependencies": [
"@biomejs/biome",
"@swc/core"
]
"trustedDependencies": ["@biomejs/biome", "@swc/core"]
}

View File

@@ -16,7 +16,7 @@ import os from 'os';
const properties = require('properties');
import { addGitIgnore } from './utils/add-gitignore';
import { checkLockFiles } from './utils/check-lockfile';
import { tempDir } from './utils/constants';
import { isPPKBundleFileName, scriptName, tempDir } from './utils/constants';
import { depVersions } from './utils/dep-versions';
import { t } from './utils/i18n';
import { versionCommands } from './versions';
@@ -42,7 +42,7 @@ async function runReactNativeBundleCommand({
platform,
sourcemapOutput,
config,
disableHermes,
forceHermes,
cli,
}: {
bundleName: string;
@@ -52,7 +52,7 @@ async function runReactNativeBundleCommand({
platform: string;
sourcemapOutput: string;
config?: string;
disableHermes?: boolean;
forceHermes?: boolean;
cli: {
taro?: boolean;
expo?: boolean;
@@ -85,14 +85,30 @@ async function runReactNativeBundleCommand({
const getExpoCli = () => {
try {
const searchPaths = [process.cwd()];
// 尝试添加 expo 包的路径作为额外的搜索路径
try {
const expoPath = require.resolve('expo/package.json', {
paths: [process.cwd()],
});
// 获取 expo 包的目录路径
const expoDir = expoPath.replace(/\/package\.json$/, '');
searchPaths.push(expoDir);
} catch {
// expo 包不存在,忽略
}
// 尝试从搜索路径中解析 @expo/cli
cliPath = require.resolve('@expo/cli', {
paths: [process.cwd()],
paths: searchPaths,
});
const expoCliVersion = JSON.parse(
fs
.readFileSync(
require.resolve('@expo/cli/package.json', {
paths: [process.cwd()],
paths: searchPaths,
}),
)
.toString(),
@@ -163,18 +179,25 @@ async function runReactNativeBundleCommand({
bundleCommand = 'build';
}
reactNativeBundleArgs.push(cliPath, bundleCommand);
if (platform === 'harmony') {
bundleName = 'bundle.harmony.js';
if (forceHermes === undefined) {
// enable hermes by default for harmony
forceHermes = true;
}
}
reactNativeBundleArgs.push(
cliPath,
bundleCommand,
'--assets-dest',
outputFolder,
'--bundle-output',
path.join(outputFolder, bundleName),
);
if (platform !== 'harmony') {
reactNativeBundleArgs.push(
'--platform',
platform,
'--assets-dest',
outputFolder,
'--bundle-output',
path.join(outputFolder, bundleName),
'--reset-cache',
);
reactNativeBundleArgs.push('--platform', platform, '--reset-cache');
}
if (cli.taro) {
@@ -211,9 +234,9 @@ async function runReactNativeBundleCommand({
} else {
let hermesEnabled: boolean | undefined = false;
if (disableHermes) {
hermesEnabled = false;
console.log(t('hermesDisabled'));
if (forceHermes) {
hermesEnabled = true;
console.log(t('forceHermes'));
} else if (platform === 'android') {
const gradlePropeties = await new Promise<{
hermesEnabled?: boolean;
@@ -240,8 +263,6 @@ async function runReactNativeBundleCommand({
fs.existsSync('ios/Pods/hermes-engine')
) {
hermesEnabled = true;
} else if (platform === 'harmony') {
await copyHarmonyBundle(outputFolder);
}
if (hermesEnabled) {
await compileHermesByteCode(
@@ -251,45 +272,25 @@ async function runReactNativeBundleCommand({
!isSentry,
);
}
if (platform === 'harmony') {
const harmonyRawAssetsPath =
'harmony/entry/src/main/resources/rawfile/assets';
// copy all files in outputFolder to harmonyRawPath
// assets should be in rawfile/assets
fs.ensureDirSync(harmonyRawAssetsPath);
fs.copySync(outputFolder, harmonyRawAssetsPath, { overwrite: true });
fs.moveSync(
`${harmonyRawAssetsPath}/bundle.harmony.js`,
`${harmonyRawAssetsPath}/../bundle.harmony.js`,
{ overwrite: true },
);
}
resolve(null);
}
});
});
}
async function copyHarmonyBundle(outputFolder: string) {
const harmonyRawPath = 'harmony/entry/src/main/resources/rawfile';
try {
await fs.ensureDir(harmonyRawPath);
try {
await fs.access(harmonyRawPath, fs.constants.W_OK);
} catch (error) {
await fs.chmod(harmonyRawPath, 0o755);
}
await fs.remove(path.join(harmonyRawPath, 'update.json'));
await fs.copy('update.json', path.join(harmonyRawPath, 'update.json'));
await fs.ensureDir(outputFolder);
const files = await fs.readdir(harmonyRawPath);
for (const file of files) {
if (file !== 'update.json' && file !== 'meta.json') {
const sourcePath = path.join(harmonyRawPath, file);
const destPath = path.join(outputFolder, file);
const stat = await fs.stat(sourcePath);
if (stat.isFile()) {
await fs.copy(sourcePath, destPath);
} else if (stat.isDirectory()) {
await fs.copy(sourcePath, destPath);
}
}
}
} catch (error: any) {
console.error(t('copyHarmonyBundleError', { error }));
throw new Error(t('copyFileFailed', { error: error.message }));
}
}
function getHermesOSBin() {
if (os.platform() === 'win32') return 'win64-bin';
if (os.platform() === 'darwin') return 'osx-bin';
@@ -478,7 +479,12 @@ async function uploadSourcemapForSentry(
}
}
const ignorePackingFileNames = ['.', '..', 'index.bundlejs.map'];
const ignorePackingFileNames = [
'.',
'..',
'index.bundlejs.map',
'bundle.harmony.js.map',
];
const ignorePackingExtensions = ['DS_Store', 'txt.map'];
async function pack(dir: string, output: string) {
console.log(t('packing'));
@@ -560,10 +566,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
// isFile
originMap[entry.crc32] = entry.fileName;
if (
entry.fileName === 'index.bundlejs' ||
entry.fileName === 'bundle.harmony.js'
) {
if (isPPKBundleFileName(entry.fileName)) {
// This is source.
return readEntry(entry, zipFile).then((v) => (originSource = v));
}
@@ -571,13 +574,10 @@ async function diffFromPPK(origin: string, next: string, output: string) {
});
if (!originSource) {
throw new Error(
'Bundle file not found! Please use default bundle file name and path.',
);
throw new Error(t('bundleFileNotFound'));
}
const copies = {};
const copiesv2 = {};
const zipfile = new YazlZipFile();
@@ -614,23 +614,13 @@ async function diffFromPPK(origin: string, next: string, output: string) {
if (!originEntries[entry.fileName]) {
addEntry(entry.fileName);
}
} else if (entry.fileName === 'index.bundlejs') {
} else if (isPPKBundleFileName(entry.fileName)) {
//console.log('Found bundle');
return readEntry(entry, nextZipfile).then((newSource) => {
//console.log('Begin diff');
zipfile.addBuffer(
diff(originSource, newSource),
'index.bundlejs.patch',
);
//console.log('End diff');
});
} else if (entry.fileName === 'bundle.harmony.js') {
//console.log('Found bundle');
return readEntry(entry, nextZipfile).then((newSource) => {
//console.log('Begin diff');
zipfile.addBuffer(
diff(originSource, newSource),
'bundle.harmony.js.patch',
`${entry.fileName}.patch`,
);
//console.log('End diff');
});
@@ -649,7 +639,6 @@ async function diffFromPPK(origin: string, next: string, output: string) {
addEntry(base);
}
copies[entry.fileName] = originMap[entry.crc32];
copiesv2[entry.crc32] = entry.fileName;
return;
}
@@ -682,7 +671,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
//console.log({copies, deletes});
zipfile.addBuffer(
Buffer.from(JSON.stringify({ copies, copiesv2, deletes })),
Buffer.from(JSON.stringify({ copies, deletes })),
'__diff.json',
);
zipfile.end();
@@ -723,13 +712,10 @@ async function diffFromPackage(
});
if (!originSource) {
throw new Error(
'Bundle file not found! Please use default bundle file name and path.',
);
throw new Error(t('bundleFileNotFound'));
}
const copies = {};
const copiesv2 = {};
const zipfile = new YazlZipFile();
@@ -746,23 +732,13 @@ async function diffFromPackage(
if (/\/$/.test(entry.fileName)) {
// Directory
zipfile.addEmptyDirectory(entry.fileName);
} else if (entry.fileName === 'index.bundlejs') {
} else if (isPPKBundleFileName(entry.fileName)) {
//console.log('Found bundle');
return readEntry(entry, nextZipfile).then((newSource) => {
//console.log('Begin diff');
zipfile.addBuffer(
diff(originSource, newSource),
'index.bundlejs.patch',
);
//console.log('End diff');
});
} else if (entry.fileName === 'bundle.harmony.js') {
//console.log('Found bundle');
return readEntry(entry, nextZipfile).then((newSource) => {
//console.log('Begin diff');
zipfile.addBuffer(
diff(originSource, newSource),
'bundle.harmony.js.patch',
`${entry.fileName}.patch`,
);
//console.log('End diff');
});
@@ -775,7 +751,6 @@ async function diffFromPackage(
// If moved from other place
if (originMap[entry.crc32]) {
copies[entry.fileName] = originMap[entry.crc32];
copiesv2[entry.crc32] = entry.fileName;
return;
}
@@ -794,10 +769,7 @@ async function diffFromPackage(
}
});
zipfile.addBuffer(
Buffer.from(JSON.stringify({ copies, copiesv2 })),
'__diff.json',
);
zipfile.addBuffer(Buffer.from(JSON.stringify({ copies })), '__diff.json');
zipfile.end();
await writePromise;
}
@@ -879,24 +851,21 @@ function diffArgsCheck(args: string[], options: any, diffFn: string) {
if (diffFn.startsWith('hdiff')) {
if (!hdiff) {
console.error(
`This function needs "node-hdiffpatch".
Please run "npm i node-hdiffpatch" to install`,
);
console.error(t('nodeHdiffpatchRequired', { scriptName }));
process.exit(1);
}
diff = hdiff;
} else {
if (!bsdiff) {
console.error(
`This function needs "node-bsdiff".
Please run "npm i node-bsdiff" to install`,
);
console.error(t('nodeBsdiffRequired', { scriptName }));
process.exit(1);
}
diff = bsdiff;
}
const { output } = options;
const { output } = translateOptions({
...options,
tempDir,
});
return {
origin,
@@ -919,7 +888,7 @@ export const bundleCommands = {
taro,
expo,
rncli,
disableHermes,
hermes,
name,
description,
metaInfo,
@@ -960,7 +929,7 @@ export const bundleCommands = {
outputFolder: intermediaDir,
platform,
sourcemapOutput: sourcemap || sourcemapPlugin ? sourcemapOutput : '',
disableHermes: !!disableHermes,
forceHermes: hermes as unknown as boolean,
cli: {
taro: !!taro,
expo: !!expo,
@@ -1027,14 +996,14 @@ export const bundleCommands = {
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diff');
await diffFromPPK(origin, next, realOutput);
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async hdiff({ args, options }) {
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiff');
await diffFromPPK(origin, next, realOutput);
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async diffFromApk({ args, options }) {
@@ -1050,7 +1019,7 @@ export const bundleCommands = {
realOutput,
'assets/index.android.bundle',
);
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async hdiffFromApk({ args, options }) {
@@ -1066,7 +1035,7 @@ export const bundleCommands = {
realOutput,
'assets/index.android.bundle',
);
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async diffFromApp({ args, options }) {
@@ -1081,7 +1050,7 @@ export const bundleCommands = {
realOutput,
'resources/rawfile/bundle.harmony.js',
);
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async hdiffFromApp({ args, options }) {
@@ -1096,7 +1065,7 @@ export const bundleCommands = {
realOutput,
'resources/rawfile/bundle.harmony.js',
);
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async diffFromIpa({ args, options }) {
@@ -1111,7 +1080,7 @@ export const bundleCommands = {
return m?.[1];
});
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
async hdiffFromIpa({ args, options }) {
@@ -1126,6 +1095,6 @@ export const bundleCommands = {
return m?.[1];
});
console.log(`${realOutput} generated.`);
console.log(t('diffPackageGenerated', { output: realOutput }));
},
};

View File

@@ -3,6 +3,7 @@
import { loadSession } from './api';
import { appCommands } from './app';
import { bundleCommands } from './bundle';
import { installCommands } from './install';
import { moduleManager } from './module-manager';
import { builtinModules } from './modules';
import { packageCommands } from './package';
@@ -33,6 +34,7 @@ function printUsage() {
...appCommands,
...packageCommands,
...versionCommands,
...installCommands,
};
for (const [name, handler] of Object.entries(legacyCommands)) {
@@ -76,6 +78,7 @@ const legacyCommands = {
...appCommands,
...packageCommands,
...versionCommands,
...installCommands,
help: printUsage,
};

19
src/install.ts Normal file
View File

@@ -0,0 +1,19 @@
import { spawnSync } from 'child_process';
import path from 'path';
import type { CommandContext } from './types';
export const installCommands = {
install: async ({ args }: CommandContext) => {
if (args.length === 0) {
return;
}
const cliDir = path.resolve(__dirname, '..');
spawnSync('npm', ['install', ...args], {
cwd: cliDir,
stdio: 'inherit',
shell: true,
});
},
};

View File

@@ -49,7 +49,7 @@ export default {
fileGenerated: '{{- file}} generated.',
fileSizeExceeded:
'This file size is {{fileSize}} , exceeding the current quota {{maxSize}} . You may consider upgrading to a higher plan to increase this quota. Details can be found at: {{- pricingPageUrl}}',
hermesDisabled: 'Hermes disabled',
forceHermes: 'Forcing Hermes enabled for this build',
hermesEnabledCompiling: 'Hermes enabled, now compiling to hermes bytecode:\n',
ipaUploadSuccess:
'Successfully uploaded IPA native package (id: {{id}}, version: {{version}}, buildTime: {{buildTime}})',
@@ -137,4 +137,11 @@ This can reduce the risk of inconsistent dependencies and supply chain attacks.
deletePackageError:
'Failed to delete native package {{packageId}}: {{error}}',
usageDeletePackage: 'Usage: cresc deletePackage [packageId] --appId [appId]',
bundleFileNotFound:
'Bundle file not found! Please use default bundle file name and path.',
diffPackageGenerated: '{{- output}} generated.',
nodeBsdiffRequired:
'This function needs "node-bsdiff". Please run "{{scriptName}} install node-bsdiff" to install',
nodeHdiffpatchRequired:
'This function needs "node-hdiffpatch". Please run "{{scriptName}} install node-hdiffpatch" to install',
};

View File

@@ -47,7 +47,7 @@ export default {
fileGenerated: '已生成 {{- file}}',
fileSizeExceeded:
'此文件大小 {{fileSize}} , 超出当前额度 {{maxSize}} 。您可以考虑升级付费业务以提升此额度。详情请访问: {{- pricingPageUrl}}',
hermesDisabled: 'Hermes 已禁用',
forceHermes: '强制启用 Hermes 编译',
hermesEnabledCompiling: 'Hermes 已启用,正在编译为 hermes 字节码:\n',
ipaUploadSuccess:
'已成功上传ipa原生包id: {{id}}, version: {{version}}, buildTime: {{buildTime}}',
@@ -129,4 +129,10 @@ export default {
deletePackageError: '删除原生包 {{packageId}} 失败: {{error}}',
usageDeletePackage:
'使用方法: pushy deletePackage [packageId] --appId [appId]',
bundleFileNotFound: '未找到 bundle 文件!请使用默认的 bundle 文件名和路径。',
diffPackageGenerated: '{{- output}} 已生成。',
nodeBsdiffRequired:
'此功能需要 "node-bsdiff"。请运行 "{{scriptName}} install node-bsdiff" 来安装',
nodeHdiffpatchRequired:
'此功能需要 "node-hdiffpatch"。请运行 "{{scriptName}} install node-hdiffpatch" 来安装',
};

View File

@@ -53,7 +53,7 @@ export const bundleModule: CLIModule = {
taro = false,
expo = false,
rncli = false,
disableHermes = false,
hermes = false,
output,
} = context.options;
@@ -73,7 +73,7 @@ export const bundleModule: CLIModule = {
taro,
expo,
rncli,
disableHermes,
hermes,
intermediaDir: '${tempDir}/intermedia/${platform}',
output: '${tempDir}/output/${platform}.${time}.ppk',
};
@@ -170,10 +170,10 @@ export const bundleModule: CLIModule = {
default: false,
description: 'Use React Native CLI',
},
disableHermes: {
hermes: {
hasValue: false,
default: false,
description: 'Disable Hermes',
description: 'Force enable Hermes',
},
name: {
hasValue: true,

View File

@@ -42,7 +42,7 @@ export class CLIProviderImpl implements CLIProvider {
taro: options.taro || false,
expo: options.expo || false,
rncli: options.rncli || false,
disableHermes: options.disableHermes || false,
hermes: options.hermes || false,
},
};

View File

@@ -65,7 +65,7 @@ export interface BundleOptions {
taro?: boolean;
expo?: boolean;
rncli?: boolean;
disableHermes?: boolean;
hermes?: boolean;
}
export interface PublishOptions {

View File

@@ -1,8 +1,12 @@
import path from 'path';
const scriptName = path.basename(process.argv[1]) as 'cresc' | 'pushy';
export const scriptName = path.basename(process.argv[1]) as 'cresc' | 'pushy';
export const IS_CRESC = scriptName === 'cresc';
export const ppkBundleFileNames = ['index.bundlejs', 'bundle.harmony.js'];
export const isPPKBundleFileName = (fileName: string) =>
ppkBundleFileNames.includes(fileName);
export const credentialFile = IS_CRESC ? '.cresc.token' : '.update';
export const updateJson = IS_CRESC ? 'cresc.config.json' : 'update.json';
export const tempDir = IS_CRESC ? '.cresc.temp' : '.pushy';

View File

@@ -1,4 +1,5 @@
import { defaultEndpoints } from './constants';
import fetch from 'node-fetch';
// const baseUrl = `http://localhost:9000`;
// let baseUrl = SERVER.main[0];

View File

@@ -122,17 +122,6 @@ export const bindVersionToPackages = async ({
console.log(chalk.yellow(t('dryRun')));
}
if (rollout !== undefined) {
const rolloutConfig: Record<string, number> = {};
for (const pkg of pkgs) {
rolloutConfig[pkg.name] = rollout;
}
if (!dryRun) {
await put(`/app/${appId}/version/${versionId}`, {
config: {
rollout: rolloutConfig,
},
});
}
console.log(
`${t('rolloutConfigSet', {
versions: pkgs.map((pkg: Package) => pkg.name).join(', '),
@@ -142,8 +131,10 @@ export const bindVersionToPackages = async ({
}
for (const pkg of pkgs) {
if (!dryRun) {
await put(`/app/${appId}/package/${pkg.id}`, {
await post(`/app/${appId}/binding`, {
versionId,
rollout,
packageId: pkg.id,
});
}
console.log(