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

fix expo cli

This commit is contained in:
sunnylqm
2025-01-11 20:20:16 +08:00
parent 26725200b7
commit 4f0784172f
5 changed files with 87 additions and 73 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "react-native-update-cli", "name": "react-native-update-cli",
"version": "1.38.1", "version": "1.38.2",
"description": "Command tools for javaScript updater with `pushy` service for react native apps.", "description": "Command tools for javaScript updater with `pushy` service for react native apps.",
"main": "index.js", "main": "index.js",
"bin": { "bin": {

View File

@@ -3,6 +3,7 @@ import fs from 'node:fs';
import Table from 'tty-table'; import Table from 'tty-table';
import { post, get, doDelete } from './api'; import { post, get, doDelete } from './api';
import type { Platform } from './types';
const validPlatforms = { const validPlatforms = {
ios: 1, ios: 1,
@@ -10,14 +11,14 @@ const validPlatforms = {
harmony: 1, harmony: 1,
}; };
export function checkPlatform(platform) { export function checkPlatform(platform: Platform) {
if (!validPlatforms[platform]) { if (!validPlatforms[platform]) {
throw new Error(`无法识别的平台 '${platform}'`); throw new Error(`无法识别的平台 '${platform}'`);
} }
return platform; return platform;
} }
export function getSelectedApp(platform) { export function getSelectedApp(platform: Platform) {
checkPlatform(platform); checkPlatform(platform);
if (!fs.existsSync('update.json')) { if (!fs.existsSync('update.json')) {
@@ -34,7 +35,7 @@ export function getSelectedApp(platform) {
return updateInfo[platform]; return updateInfo[platform];
} }
export async function listApp(platform) { export async function listApp(platform: Platform) {
const { data } = await get('/app/list'); const { data } = await get('/app/list');
const list = platform ? data.filter((v) => v.platform === platform) : data; const list = platform ? data.filter((v) => v.platform === platform) : data;
@@ -58,12 +59,12 @@ export async function listApp(platform) {
return list; return list;
} }
export async function chooseApp(platform) { export async function chooseApp(platform: Platform) {
const list = await listApp(platform); const list = await listApp(platform);
while (true) { while (true) {
const id = await question('输入应用 id:'); const id = await question('输入应用 id:');
const app = list.find((v) => v.id === (id | 0)); const app = list.find((v) => v.id === Number(id));
if (app) { if (app) {
return app; return app;
} }

View File

@@ -6,12 +6,14 @@ import { open as openZipFile } from 'yauzl';
import { question, printVersionCommand } from './utils'; import { question, printVersionCommand } from './utils';
import { checkPlatform } from './app'; import { checkPlatform } from './app';
import { spawn, spawnSync } from 'node:child_process'; import { spawn, spawnSync } from 'node:child_process';
import semverSatisfies from 'semver/functions/satisfies';
const g2js = require('gradle-to-js/lib/parser'); const g2js = require('gradle-to-js/lib/parser');
import os from 'os'; import os from 'node:os';
const properties = require('properties'); const properties = require('properties');
const path = require('path');
let bsdiff, hdiff, diff; let bsdiff;
let hdiff;
let diff;
try { try {
bsdiff = require('node-bsdiff').diff; bsdiff = require('node-bsdiff').diff;
} catch (e) {} } catch (e) {}
@@ -39,9 +41,9 @@ async function runReactNativeBundleCommand(
} }
} }
let reactNativeBundleArgs = []; const reactNativeBundleArgs = [];
let envArgs = process.env.PUSHY_ENV_ARGS; const envArgs = process.env.PUSHY_ENV_ARGS;
if (envArgs) { if (envArgs) {
Array.prototype.push.apply( Array.prototype.push.apply(
@@ -59,8 +61,19 @@ async function runReactNativeBundleCommand(
cliPath = require.resolve('@expo/cli', { cliPath = require.resolve('@expo/cli', {
paths: [process.cwd()], paths: [process.cwd()],
}); });
usingExpo = true; const expoCliVersion = JSON.parse(
} catch (e) { fs.readFileSync(
require.resolve('@expo/cli/package.json', {
paths: [process.cwd()],
}),
),
).version;
// expo cli 0.10.17 (expo 49) 开始支持 bundle:embed
if (semverSatisfies(expoCliVersion, '>= 0.10.17')) {
usingExpo = true;
}
} catch (e) {}
if (!usingExpo) {
try { try {
// rn >= 0.75 // rn >= 0.75
cliPath = require.resolve('@react-native-community/cli/build/bin.js', { cliPath = require.resolve('@react-native-community/cli/build/bin.js', {
@@ -73,8 +86,12 @@ async function runReactNativeBundleCommand(
}); });
} }
} }
const bundleCommand = usingExpo ? 'export:embed' : platform === 'harmony' ? 'bundle-harmony' : 'bundle'; const bundleCommand = usingExpo
if (platform == 'harmony') { ? 'export:embed'
: platform === 'harmony'
? 'bundle-harmony'
: 'bundle';
if (platform === 'harmony') {
Array.prototype.push.apply(reactNativeBundleArgs, [ Array.prototype.push.apply(reactNativeBundleArgs, [
cliPath, cliPath,
bundleCommand, bundleCommand,
@@ -91,8 +108,7 @@ async function runReactNativeBundleCommand(
if (config) { if (config) {
reactNativeBundleArgs.push('--config', config); reactNativeBundleArgs.push('--config', config);
} }
} } else {
else{
Array.prototype.push.apply(reactNativeBundleArgs, [ Array.prototype.push.apply(reactNativeBundleArgs, [
cliPath, cliPath,
bundleCommand, bundleCommand,
@@ -108,16 +124,16 @@ async function runReactNativeBundleCommand(
platform, platform,
'--reset-cache', '--reset-cache',
]); ]);
if (sourcemapOutput) { if (sourcemapOutput) {
reactNativeBundleArgs.push('--sourcemap-output', sourcemapOutput); reactNativeBundleArgs.push('--sourcemap-output', sourcemapOutput);
} }
if (config) { if (config) {
reactNativeBundleArgs.push('--config', config); reactNativeBundleArgs.push('--config', config);
} }
} }
const reactNativeBundleProcess = spawn('node', reactNativeBundleArgs); const reactNativeBundleProcess = spawn('node', reactNativeBundleArgs);
console.log( console.log(
`Running bundle command: node ${reactNativeBundleArgs.join(' ')}`, `Running bundle command: node ${reactNativeBundleArgs.join(' ')}`,
@@ -147,7 +163,7 @@ async function runReactNativeBundleCommand(
properties.parse( properties.parse(
'./android/gradle.properties', './android/gradle.properties',
{ path: true }, { path: true },
function (error, props) { (error, props) => {
if (error) { if (error) {
console.error(error); console.error(error);
resolve(null); resolve(null);
@@ -166,7 +182,7 @@ async function runReactNativeBundleCommand(
fs.existsSync('ios/Pods/hermes-engine') fs.existsSync('ios/Pods/hermes-engine')
) { ) {
hermesEnabled = true; hermesEnabled = true;
}else if (platform === 'harmony') { } else if (platform === 'harmony') {
await copyHarmonyBundle(outputFolder); await copyHarmonyBundle(outputFolder);
} }
if (hermesEnabled) { if (hermesEnabled) {
@@ -193,7 +209,7 @@ async function copyHarmonyBundle(outputFolder) {
} }
await fs.remove(path.join(harmonyRawPath, 'update.json')); await fs.remove(path.join(harmonyRawPath, 'update.json'));
await fs.copy('update.json', path.join(harmonyRawPath, 'update.json')); await fs.copy('update.json', path.join(harmonyRawPath, 'update.json'));
await fs.ensureDir(outputFolder); await fs.ensureDir(outputFolder);
await fs.copy(harmonyRawPath, outputFolder); await fs.copy(harmonyRawPath, outputFolder);
} catch (error) { } catch (error) {
@@ -238,7 +254,7 @@ async function compileHermesByteCode(
outputFolder, outputFolder,
sourcemapOutput, sourcemapOutput,
) { ) {
console.log(`Hermes enabled, now compiling to hermes bytecode:\n`); console.log('Hermes enabled, now compiling to hermes bytecode:\n');
// >= rn 0.69 // >= rn 0.69
const rnDir = path.dirname( const rnDir = path.dirname(
require.resolve('react-native', { require.resolve('react-native', {
@@ -264,13 +280,11 @@ async function compileHermesByteCode(
if (sourcemapOutput) { if (sourcemapOutput) {
fs.copyFileSync( fs.copyFileSync(
sourcemapOutput, sourcemapOutput,
path.join(outputFolder, bundleName + '.txt.map'), path.join(outputFolder, `${bundleName}.txt.map`),
); );
args.push('-output-source-map'); args.push('-output-source-map');
} }
console.log( console.log(`Running hermesc: ${hermesCommand} ${args.join(' ')}`);
'Running hermesc: ' + hermesCommand + ' ' + args.join(' ') + '\n',
);
spawnSync(hermesCommand, args, { spawnSync(hermesCommand, args, {
stdio: 'ignore', stdio: 'ignore',
}); });
@@ -280,13 +294,13 @@ async function compileHermesByteCode(
if (!fs.existsSync(composerPath)) { if (!fs.existsSync(composerPath)) {
return; return;
} }
console.log(`Composing source map`); console.log('Composing source map');
spawnSync( spawnSync(
'node', 'node',
[ [
composerPath, composerPath,
path.join(outputFolder, bundleName + '.txt.map'), path.join(outputFolder, `${bundleName}.txt.map`),
path.join(outputFolder, bundleName + '.map'), path.join(outputFolder, `${bundleName}.map`),
'-o', '-o',
sourcemapOutput, sourcemapOutput,
], ],
@@ -295,7 +309,7 @@ async function compileHermesByteCode(
}, },
); );
} }
fs.removeSync(path.join(outputFolder, bundleName + '.txt.map')); fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
} }
async function pack(dir, output) { async function pack(dir, output) {
@@ -320,7 +334,7 @@ async function pack(dir, output) {
zipfile.addFile(fullPath, rel + name); zipfile.addFile(fullPath, rel + name);
} else if (stat.isDirectory()) { } else if (stat.isDirectory()) {
//console.log('adding: ' + rel+name+'/'); //console.log('adding: ' + rel+name+'/');
addDirectory(fullPath, rel + name + '/'); addDirectory(fullPath, `${rel}${name}/`);
} }
} }
} }
@@ -328,14 +342,12 @@ async function pack(dir, output) {
addDirectory(dir, ''); addDirectory(dir, '');
zipfile.outputStream.on('error', (err) => reject(err)); zipfile.outputStream.on('error', (err) => reject(err));
zipfile.outputStream zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
.pipe(fs.createWriteStream(output)) resolve();
.on('close', function () { });
resolve();
});
zipfile.end(); zipfile.end();
}); });
console.log('ppk热更包已生成并保存到: ' + output); console.log(`ppk热更包已生成并保存到: ${output}`);
} }
export function readEntire(entry, zipFile) { export function readEntire(entry, zipFile) {
@@ -360,7 +372,7 @@ export function readEntire(entry, zipFile) {
function basename(fn) { function basename(fn) {
const m = /^(.+\/)[^\/]+\/?$/.exec(fn); const m = /^(.+\/)[^\/]+\/?$/.exec(fn);
return m && m[1]; return m?.[1];
} }
async function diffFromPPK(origin, next, output) { async function diffFromPPK(origin, next, output) {
@@ -377,7 +389,10 @@ async function diffFromPPK(origin, next, output) {
// isFile // isFile
originMap[entry.crc32] = entry.fileName; originMap[entry.crc32] = entry.fileName;
if (entry.fileName === 'index.bundlejs' || entry.fileName === 'bundle.harmony.js') { if (
entry.fileName === 'index.bundlejs' ||
entry.fileName === 'bundle.harmony.js'
) {
// This is source. // This is source.
return readEntire(entry, zipFile).then((v) => (originSource = v)); return readEntire(entry, zipFile).then((v) => (originSource = v));
} }
@@ -386,7 +401,7 @@ async function diffFromPPK(origin, next, output) {
if (!originSource) { if (!originSource) {
throw new Error( throw new Error(
`Bundle file not found! Please use default bundle file name and path.`, 'Bundle file not found! Please use default bundle file name and path.',
); );
} }
@@ -398,11 +413,9 @@ async function diffFromPPK(origin, next, output) {
zipfile.outputStream.on('error', (err) => { zipfile.outputStream.on('error', (err) => {
throw err; throw err;
}); });
zipfile.outputStream zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
.pipe(fs.createWriteStream(output)) resolve();
.on('close', function () { });
resolve();
});
}); });
const addedEntry = {}; const addedEntry = {};
@@ -439,7 +452,7 @@ async function diffFromPPK(origin, next, output) {
); );
//console.log('End diff'); //console.log('End diff');
}); });
}else if (entry.fileName === 'bundle.harmony.js') { } else if (entry.fileName === 'bundle.harmony.js') {
//console.log('Found bundle'); //console.log('Found bundle');
return readEntire(entry, nextZipfile).then((newSource) => { return readEntire(entry, nextZipfile).then((newSource) => {
//console.log('Begin diff'); //console.log('Begin diff');
@@ -471,7 +484,7 @@ async function diffFromPPK(origin, next, output) {
addEntry(basename(entry.fileName)); addEntry(basename(entry.fileName));
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
nextZipfile.openReadStream(entry, function (err, readStream) { nextZipfile.openReadStream(entry, (err, readStream) => {
if (err) { if (err) {
return reject(err); return reject(err);
} }
@@ -487,9 +500,9 @@ async function diffFromPPK(origin, next, output) {
const deletes = {}; const deletes = {};
for (let k in originEntries) { for (const k in originEntries) {
if (!newEntries[k]) { if (!newEntries[k]) {
console.log('Delete ' + k); console.log(`Delete ${k}`);
deletes[k] = 1; deletes[k] = 1;
} }
} }
@@ -538,7 +551,7 @@ async function diffFromPackage(
if (!originSource) { if (!originSource) {
throw new Error( throw new Error(
`Bundle file not found! Please use default bundle file name and path.`, 'Bundle file not found! Please use default bundle file name and path.',
); );
} }
@@ -550,11 +563,9 @@ async function diffFromPackage(
zipfile.outputStream.on('error', (err) => { zipfile.outputStream.on('error', (err) => {
throw err; throw err;
}); });
zipfile.outputStream zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
.pipe(fs.createWriteStream(output)) resolve();
.on('close', function () { });
resolve();
});
}); });
await enumZipEntries(next, (entry, nextZipfile) => { await enumZipEntries(next, (entry, nextZipfile) => {
@@ -581,7 +592,7 @@ async function diffFromPackage(
); );
//console.log('End diff'); //console.log('End diff');
}); });
}else { } else {
// If same file. // If same file.
if (originEntries[entry.fileName] === entry.crc32) { if (originEntries[entry.fileName] === entry.crc32) {
copies[entry.fileName] = ''; copies[entry.fileName] = '';
@@ -594,7 +605,7 @@ async function diffFromPackage(
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
nextZipfile.openReadStream(entry, function (err, readStream) { nextZipfile.openReadStream(entry, (err, readStream) => {
if (err) { if (err) {
return reject(err); return reject(err);
} }
@@ -630,7 +641,7 @@ export async function enumZipEntries(zipFn, callback, nestedPath = '') {
!entry.fileName.endsWith('/') && !entry.fileName.endsWith('/') &&
entry.fileName.toLowerCase().endsWith('.hap') entry.fileName.toLowerCase().endsWith('.hap')
) { ) {
const tempDir = path.join(os.tmpdir(), 'nested_zip_' + Date.now()); const tempDir = path.join(os.tmpdir(), `nested_zip_${Date.now()}`);
await fs.ensureDir(tempDir); await fs.ensureDir(tempDir);
const tempZipPath = path.join(tempDir, 'temp.zip'); const tempZipPath = path.join(tempDir, 'temp.zip');
@@ -644,7 +655,7 @@ export async function enumZipEntries(zipFn, callback, nestedPath = '') {
}); });
}); });
await enumZipEntries(tempZipPath, callback, fullPath + '/'); await enumZipEntries(tempZipPath, callback, `${fullPath}/`);
await fs.remove(tempDir); await fs.remove(tempDir);
} }
@@ -697,7 +708,7 @@ function diffArgsCheck(args, options, diffFn) {
return { return {
origin, origin,
next, next,
realOutput: output.replace(/\$\{time\}/g, '' + Date.now()), realOutput: output.replace(/\$\{time\}/g, `${Date.now()}`),
}; };
} }
@@ -707,15 +718,15 @@ export const commands = {
options.platform || (await question('平台(ios/android/harmony):')), options.platform || (await question('平台(ios/android/harmony):')),
); );
let { bundleName, entryFile, intermediaDir, output, dev, sourcemap } = const { bundleName, entryFile, intermediaDir, output, dev, sourcemap } =
translateOptions({ translateOptions({
...options, ...options,
platform, platform,
}); });
const sourcemapOutput = path.join(intermediaDir, bundleName + '.map'); const sourcemapOutput = path.join(intermediaDir, `${bundleName}.map`);
const realOutput = output.replace(/\$\{time\}/g, '' + Date.now()); const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
if (!platform) { if (!platform) {
throw new Error('Platform must be specified.'); throw new Error('Platform must be specified.');
@@ -723,7 +734,7 @@ export const commands = {
const { version, major, minor } = getRNVersion(); const { version, major, minor } = getRNVersion();
console.log('Bundling with react-native: ', version); console.log(`Bundling with react-native: ${version}`);
await runReactNativeBundleCommand( await runReactNativeBundleCommand(
bundleName, bundleName,
@@ -817,7 +828,7 @@ export const commands = {
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => { await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => {
const m = /^Payload\/[^/]+\/(.+)$/.exec(v); const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
return m && m[1]; return m?.[1];
}); });
console.log(`${realOutput} generated.`); console.log(`${realOutput} generated.`);
@@ -832,7 +843,7 @@ export const commands = {
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => { await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => {
const m = /^Payload\/[^/]+\/(.+)$/.exec(v); const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
return m && m[1]; return m?.[1];
}); });
console.log(`${realOutput} generated.`); console.log(`${realOutput} generated.`);

View File

@@ -6,3 +6,5 @@ declare global {
export interface Session { export interface Session {
token: string; token: string;
} }
export type Platform = 'ios' | 'android' | 'harmony';

View File

@@ -22,12 +22,12 @@ export async function question(query, password) {
export function translateOptions(options) { export function translateOptions(options) {
const ret = {}; const ret = {};
for (let key in options) { for (const key in options) {
const v = options[key]; const v = options[key];
if (typeof v === 'string') { if (typeof v === 'string') {
ret[key] = v.replace(/\$\{(\w+)\}/g, function (v, n) { ret[key] = v.replace(/\$\{(\w+)\}/g, (v, n) =>
return options[n] || process.env[n] || v; options[n] || process.env[n] || v,
}); );
} else { } else {
ret[key] = v; ret[key] = v;
} }
@@ -217,7 +217,7 @@ export async function printVersionCommand() {
); );
} else if (semverSatisfies(pushyVersion, '10.0.0 - 10.17.0')) { } else if (semverSatisfies(pushyVersion, '10.0.0 - 10.17.0')) {
console.warn( console.warn(
`当前版本已不再支持,请升级到 v10 的最新小版本(代码无需改动,可直接热更): npm i react-native-update@10`, '当前版本已不再支持,请升级到 v10 的最新小版本(代码无需改动,可直接热更): npm i react-native-update@10',
); );
} }
} }