react-native-update-cli 2.8.5 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/lib/api.d.ts +18 -0
  2. package/lib/app.d.ts +38 -0
  3. package/lib/app.js +5 -4
  4. package/lib/bundle-pack.d.ts +1 -0
  5. package/lib/bundle-pack.js +104 -0
  6. package/lib/bundle-runner.d.ts +20 -0
  7. package/lib/bundle-runner.js +404 -0
  8. package/lib/bundle.d.ts +6 -0
  9. package/lib/bundle.js +73 -471
  10. package/lib/diff.d.ts +13 -0
  11. package/lib/diff.js +144 -123
  12. package/lib/exports.d.ts +12 -0
  13. package/lib/index.d.ts +5 -0
  14. package/lib/index.js +5 -13
  15. package/lib/install.d.ts +4 -0
  16. package/lib/locales/en.d.ts +137 -0
  17. package/lib/locales/zh.d.ts +136 -0
  18. package/lib/module-manager.d.ts +20 -0
  19. package/lib/module-manager.js +3 -9
  20. package/lib/modules/app-module.d.ts +2 -0
  21. package/lib/modules/app-module.js +84 -44
  22. package/lib/modules/bundle-module.d.ts +2 -0
  23. package/lib/modules/bundle-module.js +7 -8
  24. package/lib/modules/index.d.ts +6 -0
  25. package/lib/modules/package-module.d.ts +2 -0
  26. package/lib/modules/user-module.d.ts +2 -0
  27. package/lib/modules/user-module.js +55 -44
  28. package/lib/modules/version-module.d.ts +2 -0
  29. package/lib/package.d.ts +58 -0
  30. package/lib/package.js +103 -139
  31. package/lib/provider.d.ts +26 -0
  32. package/lib/provider.js +115 -217
  33. package/lib/types.d.ts +120 -0
  34. package/lib/user.d.ts +8 -0
  35. package/lib/utils/add-gitignore.d.ts +1 -0
  36. package/lib/utils/app-info-parser/aab.d.ts +22 -0
  37. package/lib/utils/app-info-parser/aab.js +0 -4
  38. package/lib/utils/app-info-parser/apk.d.ts +14 -0
  39. package/lib/utils/app-info-parser/apk.js +6 -4
  40. package/lib/utils/app-info-parser/app.d.ts +4 -0
  41. package/lib/utils/app-info-parser/app.js +3 -0
  42. package/lib/utils/app-info-parser/index.d.ts +16 -0
  43. package/lib/utils/app-info-parser/index.js +2 -0
  44. package/lib/utils/app-info-parser/ipa.d.ts +14 -0
  45. package/lib/utils/app-info-parser/ipa.js +1 -1
  46. package/lib/utils/app-info-parser/resource-finder.d.ts +49 -0
  47. package/lib/utils/app-info-parser/utils.d.ts +31 -0
  48. package/lib/utils/app-info-parser/utils.js +1 -0
  49. package/lib/utils/app-info-parser/xml-parser/binary.d.ts +56 -0
  50. package/lib/utils/app-info-parser/xml-parser/manifest.d.ts +10 -0
  51. package/lib/utils/app-info-parser/zip.d.ts +18 -0
  52. package/lib/utils/app-info-parser/zip.js +7 -9
  53. package/lib/utils/check-lockfile.d.ts +1 -0
  54. package/lib/utils/check-plugin.d.ts +7 -0
  55. package/lib/utils/command-result.d.ts +3 -0
  56. package/lib/utils/command-result.js +35 -0
  57. package/lib/utils/constants.d.ts +9 -0
  58. package/lib/utils/dep-versions.d.ts +1 -0
  59. package/lib/utils/git.d.ts +8 -0
  60. package/lib/utils/http-helper.d.ts +4 -0
  61. package/lib/utils/i18n.d.ts +12 -0
  62. package/lib/utils/index.d.ts +22 -0
  63. package/lib/utils/index.js +52 -22
  64. package/lib/utils/latest-version/cli.d.ts +1 -0
  65. package/lib/utils/latest-version/cli.js +24 -60
  66. package/lib/utils/latest-version/index.d.ts +146 -0
  67. package/lib/utils/latest-version/index.js +22 -22
  68. package/lib/utils/options.d.ts +4 -0
  69. package/lib/utils/options.js +63 -0
  70. package/lib/utils/plugin-config.d.ts +9 -0
  71. package/lib/utils/zip-entries.d.ts +3 -0
  72. package/lib/versions.d.ts +43 -0
  73. package/lib/workflow-runner.d.ts +2 -0
  74. package/lib/workflow-runner.js +25 -0
  75. package/package.json +20 -5
  76. package/src/api.ts +1 -1
  77. package/src/app.ts +20 -11
  78. package/src/bundle-pack.ts +51 -0
  79. package/src/bundle-runner.ts +463 -0
  80. package/src/bundle.ts +184 -571
  81. package/src/diff.ts +208 -174
  82. package/src/index.ts +15 -17
  83. package/src/module-manager.ts +15 -15
  84. package/src/modules/app-module.ts +120 -48
  85. package/src/modules/bundle-module.ts +21 -11
  86. package/src/modules/package-module.ts +0 -1
  87. package/src/modules/user-module.ts +117 -58
  88. package/src/package.ts +158 -138
  89. package/src/provider.ts +164 -240
  90. package/src/types.ts +13 -8
  91. package/src/utils/app-info-parser/aab.ts +0 -7
  92. package/src/utils/app-info-parser/apk.ts +9 -6
  93. package/src/utils/app-info-parser/app.ts +5 -1
  94. package/src/utils/app-info-parser/index.ts +11 -6
  95. package/src/utils/app-info-parser/ipa.ts +1 -1
  96. package/src/utils/app-info-parser/utils.ts +3 -0
  97. package/src/utils/app-info-parser/xml-parser/manifest.ts +3 -1
  98. package/src/utils/app-info-parser/zip.ts +12 -14
  99. package/src/utils/command-result.ts +24 -0
  100. package/src/utils/index.ts +138 -39
  101. package/src/utils/latest-version/cli.ts +22 -20
  102. package/src/utils/latest-version/index.ts +20 -20
  103. package/src/utils/options.ts +56 -0
  104. package/src/utils/zip-entries.ts +1 -1
  105. package/src/workflow-runner.ts +24 -0
  106. package/index.js +0 -1
@@ -0,0 +1,51 @@
1
+ import path from 'path';
2
+ import * as fs from 'fs-extra';
3
+ import { ZipFile as YazlZipFile } from 'yazl';
4
+ import { t } from './utils/i18n';
5
+
6
+ const ignorePackingFileNames = [
7
+ '.',
8
+ '..',
9
+ 'index.bundlejs.map',
10
+ 'bundle.harmony.js.map',
11
+ ];
12
+ const ignorePackingExtensions = ['DS_Store', 'txt.map'];
13
+
14
+ export async function packBundle(dir: string, output: string): Promise<void> {
15
+ console.log(t('packing'));
16
+ fs.ensureDirSync(path.dirname(output));
17
+ await new Promise<void>((resolve, reject) => {
18
+ const zipfile = new YazlZipFile();
19
+
20
+ function addDirectory(root: string, rel: string) {
21
+ if (rel) {
22
+ zipfile.addEmptyDirectory(rel);
23
+ }
24
+ const children = fs.readdirSync(root);
25
+ for (const name of children) {
26
+ if (
27
+ ignorePackingFileNames.includes(name) ||
28
+ ignorePackingExtensions.some((ext) => name.endsWith(`.${ext}`))
29
+ ) {
30
+ continue;
31
+ }
32
+ const fullPath = path.join(root, name);
33
+ const stat = fs.statSync(fullPath);
34
+ if (stat.isFile()) {
35
+ zipfile.addFile(fullPath, rel + name);
36
+ } else if (stat.isDirectory()) {
37
+ addDirectory(fullPath, `${rel}${name}/`);
38
+ }
39
+ }
40
+ }
41
+
42
+ addDirectory(dir, '');
43
+
44
+ zipfile.outputStream.on('error', (err: unknown) => reject(err));
45
+ zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
46
+ resolve();
47
+ });
48
+ zipfile.end();
49
+ });
50
+ console.log(t('fileGenerated', { file: output }));
51
+ }
@@ -0,0 +1,463 @@
1
+ import { spawn, spawnSync } from 'child_process';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { satisfies } from 'compare-versions';
5
+ import * as fs from 'fs-extra';
6
+ import { t } from './utils/i18n';
7
+
8
+ const g2js = require('gradle-to-js/lib/parser');
9
+ const properties = require('properties');
10
+
11
+ export interface BundleCliOptions {
12
+ taro?: boolean;
13
+ expo?: boolean;
14
+ rncli?: boolean;
15
+ }
16
+
17
+ export interface RunBundleCommandOptions {
18
+ bundleName: string;
19
+ dev: string;
20
+ entryFile: string;
21
+ outputFolder: string;
22
+ platform: string;
23
+ sourcemapOutput: string;
24
+ config?: string;
25
+ forceHermes?: boolean;
26
+ cli: BundleCliOptions;
27
+ isSentry: boolean;
28
+ }
29
+
30
+ interface GradleConfig {
31
+ crunchPngs?: boolean;
32
+ enableHermes?: boolean;
33
+ }
34
+
35
+ export async function runReactNativeBundleCommand({
36
+ bundleName,
37
+ dev,
38
+ entryFile,
39
+ outputFolder,
40
+ platform,
41
+ sourcemapOutput,
42
+ config,
43
+ forceHermes,
44
+ cli,
45
+ isSentry,
46
+ }: RunBundleCommandOptions): Promise<void> {
47
+ let gradleConfig: GradleConfig = {};
48
+ if (platform === 'android') {
49
+ gradleConfig = await checkGradleConfig();
50
+ if (gradleConfig.crunchPngs !== false) {
51
+ console.warn(t('androidCrunchPngsWarning'));
52
+ }
53
+ }
54
+
55
+ const reactNativeBundleArgs: string[] = [];
56
+ const envArgs = process.env.PUSHY_ENV_ARGS;
57
+
58
+ if (envArgs) {
59
+ reactNativeBundleArgs.push(...envArgs.trim().split(/\s+/));
60
+ }
61
+
62
+ fs.emptyDirSync(outputFolder);
63
+
64
+ let cliPath = '';
65
+ let usingExpo = false;
66
+
67
+ const getExpoCli = () => {
68
+ try {
69
+ const searchPaths = [process.cwd()];
70
+
71
+ try {
72
+ const expoPath = require.resolve('expo/package.json', {
73
+ paths: [process.cwd()],
74
+ });
75
+ const expoDir = expoPath.replace(/\/package\.json$/, '');
76
+ searchPaths.push(expoDir);
77
+ } catch {
78
+ // expo 包不存在,忽略
79
+ }
80
+
81
+ cliPath = require.resolve('@expo/cli', {
82
+ paths: searchPaths,
83
+ });
84
+
85
+ const expoCliVersion = JSON.parse(
86
+ fs
87
+ .readFileSync(
88
+ require.resolve('@expo/cli/package.json', {
89
+ paths: searchPaths,
90
+ }),
91
+ )
92
+ .toString(),
93
+ ).version;
94
+ if (satisfies(expoCliVersion, '>= 0.10.17')) {
95
+ usingExpo = true;
96
+ } else {
97
+ cliPath = '';
98
+ }
99
+ } catch {
100
+ // fallback 到 RN CLI
101
+ }
102
+ };
103
+
104
+ const getRnCli = () => {
105
+ try {
106
+ cliPath = require.resolve('react-native/local-cli/cli.js', {
107
+ paths: [process.cwd()],
108
+ });
109
+ } catch {
110
+ cliPath = require.resolve('@react-native-community/cli/build/bin.js', {
111
+ paths: [process.cwd()],
112
+ });
113
+ }
114
+ };
115
+
116
+ const getTaroCli = () => {
117
+ try {
118
+ cliPath = require.resolve('@tarojs/cli/bin/taro', {
119
+ paths: [process.cwd()],
120
+ });
121
+ } catch {
122
+ // fallback 到 RN CLI
123
+ }
124
+ };
125
+
126
+ if (cli.expo) {
127
+ getExpoCli();
128
+ } else if (cli.taro) {
129
+ getTaroCli();
130
+ } else if (cli.rncli) {
131
+ getRnCli();
132
+ }
133
+
134
+ if (!cliPath) {
135
+ getExpoCli();
136
+ if (!usingExpo) {
137
+ getRnCli();
138
+ }
139
+ }
140
+
141
+ if (isSentry) {
142
+ if (platform === 'ios') {
143
+ process.env.SENTRY_PROPERTIES = 'ios/sentry.properties';
144
+ } else if (platform === 'android') {
145
+ process.env.SENTRY_PROPERTIES = 'android/sentry.properties';
146
+ }
147
+ }
148
+
149
+ let bundleCommand = 'bundle';
150
+ if (usingExpo) {
151
+ bundleCommand = 'export:embed';
152
+ } else if (platform === 'harmony') {
153
+ bundleCommand = 'bundle-harmony';
154
+ } else if (cli.taro) {
155
+ bundleCommand = 'build';
156
+ }
157
+
158
+ if (platform === 'harmony') {
159
+ bundleName = 'bundle.harmony.js';
160
+ if (forceHermes === undefined) {
161
+ forceHermes = true;
162
+ }
163
+ }
164
+
165
+ reactNativeBundleArgs.push(
166
+ cliPath,
167
+ bundleCommand,
168
+ '--assets-dest',
169
+ outputFolder,
170
+ '--bundle-output',
171
+ path.join(outputFolder, bundleName),
172
+ );
173
+
174
+ if (platform !== 'harmony') {
175
+ reactNativeBundleArgs.push('--platform', platform, '--reset-cache');
176
+ }
177
+
178
+ if (cli.taro) {
179
+ reactNativeBundleArgs.push('--type', 'rn');
180
+ } else {
181
+ reactNativeBundleArgs.push('--dev', dev, '--entry-file', entryFile);
182
+ }
183
+
184
+ if (sourcemapOutput) {
185
+ reactNativeBundleArgs.push('--sourcemap-output', sourcemapOutput);
186
+ }
187
+
188
+ if (config) {
189
+ reactNativeBundleArgs.push('--config', config);
190
+ }
191
+
192
+ const reactNativeBundleProcess = spawn('node', reactNativeBundleArgs);
193
+ console.log(
194
+ `Running bundle command: node ${reactNativeBundleArgs.join(' ')}`,
195
+ );
196
+
197
+ await new Promise<void>((resolve, reject) => {
198
+ reactNativeBundleProcess.stdout.on('data', (data) => {
199
+ console.log(data.toString().trim());
200
+ });
201
+
202
+ reactNativeBundleProcess.stderr.on('data', (data) => {
203
+ console.error(data.toString().trim());
204
+ });
205
+
206
+ reactNativeBundleProcess.on('close', async (exitCode) => {
207
+ if (exitCode) {
208
+ reject(new Error(t('bundleCommandError', { code: exitCode })));
209
+ return;
210
+ }
211
+
212
+ let hermesEnabled: boolean | undefined = false;
213
+
214
+ if (forceHermes) {
215
+ hermesEnabled = true;
216
+ console.log(t('forceHermes'));
217
+ } else if (platform === 'android') {
218
+ const gradleProperties = await new Promise<{ hermesEnabled?: boolean }>(
219
+ (resolve) => {
220
+ properties.parse(
221
+ './android/gradle.properties',
222
+ { path: true },
223
+ (
224
+ error: Error | null,
225
+ props: { hermesEnabled?: boolean } = {},
226
+ ) => {
227
+ if (error) {
228
+ console.error(error);
229
+ resolve({});
230
+ return;
231
+ }
232
+ resolve(props);
233
+ },
234
+ );
235
+ },
236
+ );
237
+ hermesEnabled = gradleProperties.hermesEnabled;
238
+
239
+ if (typeof hermesEnabled !== 'boolean') {
240
+ hermesEnabled = gradleConfig.enableHermes;
241
+ }
242
+ } else if (
243
+ platform === 'ios' &&
244
+ fs.existsSync('ios/Pods/hermes-engine')
245
+ ) {
246
+ hermesEnabled = true;
247
+ }
248
+
249
+ if (hermesEnabled) {
250
+ await compileHermesByteCode(
251
+ bundleName,
252
+ outputFolder,
253
+ sourcemapOutput,
254
+ !isSentry,
255
+ );
256
+ }
257
+
258
+ if (platform === 'harmony') {
259
+ const harmonyRawAssetsPath =
260
+ 'harmony/entry/src/main/resources/rawfile/assets';
261
+ fs.ensureDirSync(harmonyRawAssetsPath);
262
+ fs.copySync(outputFolder, harmonyRawAssetsPath, { overwrite: true });
263
+ fs.moveSync(
264
+ `${harmonyRawAssetsPath}/bundle.harmony.js`,
265
+ `${harmonyRawAssetsPath}/../bundle.harmony.js`,
266
+ { overwrite: true },
267
+ );
268
+ }
269
+
270
+ resolve();
271
+ });
272
+ });
273
+ }
274
+
275
+ function getHermesOSBin() {
276
+ if (os.platform() === 'win32') return 'win64-bin';
277
+ if (os.platform() === 'darwin') return 'osx-bin';
278
+ if (os.platform() === 'linux') return 'linux64-bin';
279
+ }
280
+
281
+ async function checkGradleConfig(): Promise<GradleConfig> {
282
+ let enableHermes = false;
283
+ let crunchPngs: boolean | undefined;
284
+ try {
285
+ const gradleConfig = await g2js.parseFile('android/app/build.gradle');
286
+ crunchPngs = gradleConfig.android.buildTypes.release.crunchPngs;
287
+ const projectConfig = gradleConfig['project.ext.react'];
288
+ if (projectConfig) {
289
+ for (const packagerConfig of projectConfig) {
290
+ if (
291
+ packagerConfig.includes('enableHermes') &&
292
+ packagerConfig.includes('true')
293
+ ) {
294
+ enableHermes = true;
295
+ break;
296
+ }
297
+ }
298
+ }
299
+ } catch {
300
+ // ignore parsing failures
301
+ }
302
+ return {
303
+ enableHermes,
304
+ crunchPngs,
305
+ };
306
+ }
307
+
308
+ async function compileHermesByteCode(
309
+ bundleName: string,
310
+ outputFolder: string,
311
+ sourcemapOutput: string,
312
+ shouldCleanSourcemap: boolean,
313
+ ) {
314
+ console.log(t('hermesEnabledCompiling'));
315
+ const rnDir = path.dirname(
316
+ require.resolve('react-native', {
317
+ paths: [process.cwd()],
318
+ }),
319
+ );
320
+ let hermesPath = path.join(rnDir, `/sdks/hermesc/${getHermesOSBin()}`);
321
+
322
+ if (!fs.existsSync(hermesPath)) {
323
+ hermesPath = `node_modules/hermes-engine/${getHermesOSBin()}`;
324
+ }
325
+
326
+ const hermesCommand = `${hermesPath}/hermesc`;
327
+
328
+ const args = [
329
+ '-emit-binary',
330
+ '-out',
331
+ path.join(outputFolder, bundleName),
332
+ path.join(outputFolder, bundleName),
333
+ '-O',
334
+ ];
335
+ if (sourcemapOutput) {
336
+ fs.copyFileSync(
337
+ sourcemapOutput,
338
+ path.join(outputFolder, `${bundleName}.txt.map`),
339
+ );
340
+ args.push('-output-source-map');
341
+ }
342
+ console.log(
343
+ t('runningHermesc', { command: hermesCommand, args: args.join(' ') }),
344
+ );
345
+ spawnSync(hermesCommand, args, {
346
+ stdio: 'ignore',
347
+ });
348
+ if (sourcemapOutput) {
349
+ const composerPath =
350
+ 'node_modules/react-native/scripts/compose-source-maps.js';
351
+ if (!fs.existsSync(composerPath)) {
352
+ return;
353
+ }
354
+ console.log(t('composingSourceMap'));
355
+ spawnSync(
356
+ 'node',
357
+ [
358
+ composerPath,
359
+ path.join(outputFolder, `${bundleName}.txt.map`),
360
+ path.join(outputFolder, `${bundleName}.map`),
361
+ '-o',
362
+ sourcemapOutput,
363
+ ],
364
+ {
365
+ stdio: 'ignore',
366
+ },
367
+ );
368
+ }
369
+ if (shouldCleanSourcemap) {
370
+ fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
371
+ }
372
+ }
373
+
374
+ export async function copyDebugidForSentry(
375
+ bundleName: string,
376
+ outputFolder: string,
377
+ sourcemapOutput: string,
378
+ ): Promise<void> {
379
+ if (sourcemapOutput) {
380
+ let copyDebugidPath: string | undefined;
381
+ try {
382
+ copyDebugidPath = require.resolve(
383
+ '@sentry/react-native/scripts/copy-debugid.js',
384
+ {
385
+ paths: [process.cwd()],
386
+ },
387
+ );
388
+ } catch {
389
+ console.error(t('sentryCliNotFound'));
390
+ return;
391
+ }
392
+
393
+ if (!fs.existsSync(copyDebugidPath)) {
394
+ return;
395
+ }
396
+ console.log(t('copyingDebugId'));
397
+ spawnSync(
398
+ 'node',
399
+ [
400
+ copyDebugidPath,
401
+ path.join(outputFolder, `${bundleName}.txt.map`),
402
+ path.join(outputFolder, `${bundleName}.map`),
403
+ ],
404
+ {
405
+ stdio: 'ignore',
406
+ },
407
+ );
408
+ }
409
+ fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
410
+ }
411
+
412
+ export async function uploadSourcemapForSentry(
413
+ bundleName: string,
414
+ outputFolder: string,
415
+ sourcemapOutput: string,
416
+ version: string,
417
+ ): Promise<void> {
418
+ if (!sourcemapOutput) {
419
+ return;
420
+ }
421
+
422
+ let sentryCliPath: string | undefined;
423
+ try {
424
+ sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
425
+ paths: [process.cwd()],
426
+ });
427
+ } catch {
428
+ console.error(t('sentryCliNotFound'));
429
+ return;
430
+ }
431
+
432
+ if (!fs.existsSync(sentryCliPath)) {
433
+ return;
434
+ }
435
+
436
+ spawnSync(
437
+ 'node',
438
+ [sentryCliPath, 'releases', 'set-commits', version, '--auto'],
439
+ {
440
+ stdio: 'inherit',
441
+ },
442
+ );
443
+ console.log(t('sentryReleaseCreated', { version }));
444
+
445
+ console.log(t('uploadingSourcemap'));
446
+ spawnSync(
447
+ 'node',
448
+ [
449
+ sentryCliPath,
450
+ 'releases',
451
+ 'files',
452
+ version,
453
+ 'upload-sourcemaps',
454
+ '--strip-prefix',
455
+ path.join(process.cwd(), outputFolder),
456
+ path.join(outputFolder, bundleName),
457
+ path.join(outputFolder, `${bundleName}.map`),
458
+ ],
459
+ {
460
+ stdio: 'inherit',
461
+ },
462
+ );
463
+ }