react-native-update-cli 1.38.2 → 1.39.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.
package/lib/bundle.js CHANGED
@@ -134,6 +134,9 @@ async function runReactNativeBundleCommand(bundleName, development, entryFile, o
134
134
  });
135
135
  }
136
136
  }
137
+ const bundleParams = await (0, _utils.checkPlugins)();
138
+ const minifyOption = bundleParams.minify;
139
+ const isSentry = bundleParams.sentry;
137
140
  const bundleCommand = usingExpo ? 'export:embed' : platform === 'harmony' ? 'bundle-harmony' : 'bundle';
138
141
  if (platform === 'harmony') {
139
142
  Array.prototype.push.apply(reactNativeBundleArgs, [
@@ -164,7 +167,9 @@ async function runReactNativeBundleCommand(bundleName, development, entryFile, o
164
167
  entryFile,
165
168
  '--platform',
166
169
  platform,
167
- '--reset-cache'
170
+ '--reset-cache',
171
+ '--minify',
172
+ minifyOption
168
173
  ]);
169
174
  if (sourcemapOutput) {
170
175
  reactNativeBundleArgs.push('--sourcemap-output', sourcemapOutput);
@@ -207,7 +212,7 @@ async function runReactNativeBundleCommand(bundleName, development, entryFile, o
207
212
  await copyHarmonyBundle(outputFolder);
208
213
  }
209
214
  if (hermesEnabled) {
210
- await compileHermesByteCode(bundleName, outputFolder, sourcemapOutput);
215
+ await compileHermesByteCode(bundleName, outputFolder, sourcemapOutput, !isSentry);
211
216
  }
212
217
  resolve(null);
213
218
  }
@@ -258,7 +263,7 @@ async function checkGradleConfig() {
258
263
  crunchPngs
259
264
  };
260
265
  }
261
- async function compileHermesByteCode(bundleName, outputFolder, sourcemapOutput) {
266
+ async function compileHermesByteCode(bundleName, outputFolder, sourcemapOutput, shouldCleanSourcemap) {
262
267
  console.log('Hermes enabled, now compiling to hermes bytecode:\n');
263
268
  // >= rn 0.69
264
269
  const rnDir = _nodepath.default.dirname(require.resolve('react-native', {
@@ -303,8 +308,79 @@ async function compileHermesByteCode(bundleName, outputFolder, sourcemapOutput)
303
308
  stdio: 'ignore'
304
309
  });
305
310
  }
311
+ if (shouldCleanSourcemap) {
312
+ _fsextra.removeSync(_nodepath.default.join(outputFolder, `${bundleName}.txt.map`));
313
+ }
314
+ }
315
+ async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
316
+ if (sourcemapOutput) {
317
+ let copyDebugidPath;
318
+ try {
319
+ copyDebugidPath = require.resolve('@sentry/react-native/scripts/copy-debugid.js', {
320
+ paths: [
321
+ process.cwd()
322
+ ]
323
+ });
324
+ } catch (error) {
325
+ console.error('无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native');
326
+ return;
327
+ }
328
+ if (!_fsextra.existsSync(copyDebugidPath)) {
329
+ return;
330
+ }
331
+ console.log('Copying debugid');
332
+ (0, _nodechild_process.spawnSync)('node', [
333
+ copyDebugidPath,
334
+ _nodepath.default.join(outputFolder, `${bundleName}.txt.map`),
335
+ _nodepath.default.join(outputFolder, `${bundleName}.map`)
336
+ ], {
337
+ stdio: 'ignore'
338
+ });
339
+ }
306
340
  _fsextra.removeSync(_nodepath.default.join(outputFolder, `${bundleName}.txt.map`));
307
341
  }
342
+ async function uploadSourcemapForSentry(bundleName, outputFolder, sourcemapOutput, version) {
343
+ if (sourcemapOutput) {
344
+ let sentryCliPath;
345
+ try {
346
+ sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
347
+ paths: [
348
+ process.cwd()
349
+ ]
350
+ });
351
+ } catch (error) {
352
+ console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
353
+ return;
354
+ }
355
+ if (!_fsextra.existsSync(sentryCliPath)) {
356
+ return;
357
+ }
358
+ (0, _nodechild_process.spawnSync)('node', [
359
+ sentryCliPath,
360
+ 'releases',
361
+ 'set-commits',
362
+ version,
363
+ '--auto'
364
+ ], {
365
+ stdio: 'inherit'
366
+ });
367
+ console.log(`Sentry release created for version: ${version}`);
368
+ console.log('Uploading sourcemap');
369
+ (0, _nodechild_process.spawnSync)('node', [
370
+ sentryCliPath,
371
+ 'releases',
372
+ 'files',
373
+ version,
374
+ 'upload-sourcemaps',
375
+ '--strip-prefix',
376
+ _nodepath.default.join(process.cwd(), outputFolder),
377
+ _nodepath.default.join(outputFolder, bundleName),
378
+ _nodepath.default.join(outputFolder, `${bundleName}.map`)
379
+ ], {
380
+ stdio: 'inherit'
381
+ });
382
+ }
383
+ }
308
384
  async function pack(dir, output) {
309
385
  console.log('Packing');
310
386
  _fsextra.ensureDirSync(_nodepath.default.dirname(output));
@@ -628,10 +704,13 @@ function diffArgsCheck(args, options, diffFn) {
628
704
  const commands = {
629
705
  bundle: async function({ options }) {
630
706
  const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
631
- const { bundleName, entryFile, intermediaDir, output, dev, sourcemap } = (0, _utils.translateOptions)({
707
+ const { bundleName, entryFile, intermediaDir, output, dev } = (0, _utils.translateOptions)({
632
708
  ...options,
633
709
  platform
634
710
  });
711
+ const bundleParams = await (0, _utils.checkPlugins)();
712
+ const sourcemap = bundleParams.sourcemap;
713
+ const isSentry = bundleParams.sentry;
635
714
  const sourcemapOutput = _nodepath.default.join(intermediaDir, `${bundleName}.map`);
636
715
  const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
637
716
  if (!platform) {
@@ -643,7 +722,7 @@ const commands = {
643
722
  await pack(_nodepath.default.resolve(intermediaDir), realOutput);
644
723
  const v = await (0, _utils.question)('是否现在上传此热更包?(Y/N)');
645
724
  if (v.toLowerCase() === 'y') {
646
- await this.publish({
725
+ const versionName = await this.publish({
647
726
  args: [
648
727
  realOutput
649
728
  ],
@@ -651,6 +730,10 @@ const commands = {
651
730
  platform
652
731
  }
653
732
  });
733
+ if (isSentry) {
734
+ await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
735
+ await uploadSourcemapForSentry(bundleName, intermediaDir, sourcemapOutput, versionName);
736
+ }
654
737
  }
655
738
  },
656
739
  async diff ({ args, options }) {
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "checkPlugins", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return checkPlugins;
9
+ }
10
+ });
11
+ const _pluginconfig = require("./plugin-config");
12
+ async function checkPlugins() {
13
+ const params = {
14
+ sentry: false,
15
+ minify: true,
16
+ sourcemap: false
17
+ };
18
+ for (const plugin of _pluginconfig.plugins){
19
+ try {
20
+ const isEnabled = await plugin.detect();
21
+ if (isEnabled && plugin.bundleParams) {
22
+ Object.assign(params, plugin.bundleParams);
23
+ console.log(`检测到 ${plugin.name} 插件,应用相应打包配置`);
24
+ }
25
+ } catch (err) {
26
+ console.warn(`检测 ${plugin.name} 插件时出错:`, err);
27
+ }
28
+ }
29
+ return params;
30
+ }
@@ -9,6 +9,9 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
+ checkPlugins: function() {
13
+ return _checkplugin.checkPlugins;
14
+ },
12
15
  getApkInfo: function() {
13
16
  return getApkInfo;
14
17
  },
@@ -45,6 +48,7 @@ const _appinfoparser = /*#__PURE__*/ _interop_require_default(require("./app-inf
45
48
  const _satisfies = /*#__PURE__*/ _interop_require_default(require("semver/functions/satisfies"));
46
49
  const _chalk = /*#__PURE__*/ _interop_require_default(require("chalk"));
47
50
  const _latestversion = /*#__PURE__*/ _interop_require_default(require("@badisi/latest-version"));
51
+ const _checkplugin = require("./check-plugin");
48
52
  const _read = require("read");
49
53
  function _interop_require_default(obj) {
50
54
  return obj && obj.__esModule ? obj : {
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "plugins", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return plugins;
9
+ }
10
+ });
11
+ const _fsextra = /*#__PURE__*/ _interop_require_default(require("fs-extra"));
12
+ function _interop_require_default(obj) {
13
+ return obj && obj.__esModule ? obj : {
14
+ default: obj
15
+ };
16
+ }
17
+ const plugins = [
18
+ {
19
+ name: 'sentry',
20
+ bundleParams: {
21
+ sentry: true,
22
+ minify: false,
23
+ sourcemap: true
24
+ },
25
+ detect: async ()=>{
26
+ try {
27
+ await _fsextra.default.access('ios/sentry.properties');
28
+ return true;
29
+ } catch (e) {
30
+ try {
31
+ await _fsextra.default.access('android/sentry.properties');
32
+ return true;
33
+ } catch (e) {
34
+ return false;
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ];
package/lib/versions.js CHANGED
@@ -86,8 +86,9 @@ const commands = {
86
86
  const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
87
87
  const { appId } = await (0, _app.getSelectedApp)(platform);
88
88
  const { hash } = await (0, _api.uploadFile)(fn);
89
+ const versionName = name || await (0, _utils.question)('输入版本名称: ') || '(未命名)';
89
90
  const { id } = await (0, _api.post)(`/app/${appId}/version/create`, {
90
- name: name || await (0, _utils.question)('输入版本名称: ') || '(未命名)',
91
+ name: versionName,
91
92
  hash,
92
93
  description: description || await (0, _utils.question)('输入版本描述:'),
93
94
  metaInfo: metaInfo || await (0, _utils.question)('输入自定义的 meta info:')
@@ -105,6 +106,7 @@ const commands = {
105
106
  }
106
107
  });
107
108
  }
109
+ return versionName;
108
110
  },
109
111
  versions: async ({ options })=>{
110
112
  const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-update-cli",
3
- "version": "1.38.2",
3
+ "version": "1.39.0",
4
4
  "description": "Command tools for javaScript updater with `pushy` service for react native apps.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/src/bundle.js CHANGED
@@ -3,7 +3,7 @@ import { getRNVersion, translateOptions } from './utils';
3
3
  import * as fs from 'fs-extra';
4
4
  import { ZipFile } from 'yazl';
5
5
  import { open as openZipFile } from 'yauzl';
6
- import { question, printVersionCommand } from './utils';
6
+ import { question, checkPlugins } from './utils';
7
7
  import { checkPlatform } from './app';
8
8
  import { spawn, spawnSync } from 'node:child_process';
9
9
  import semverSatisfies from 'semver/functions/satisfies';
@@ -86,6 +86,9 @@ async function runReactNativeBundleCommand(
86
86
  });
87
87
  }
88
88
  }
89
+ const bundleParams = await checkPlugins();
90
+ const minifyOption = bundleParams.minify;
91
+ const isSentry = bundleParams.sentry;
89
92
  const bundleCommand = usingExpo
90
93
  ? 'export:embed'
91
94
  : platform === 'harmony'
@@ -123,6 +126,8 @@ async function runReactNativeBundleCommand(
123
126
  '--platform',
124
127
  platform,
125
128
  '--reset-cache',
129
+ '--minify',
130
+ minifyOption,
126
131
  ]);
127
132
 
128
133
  if (sourcemapOutput) {
@@ -190,6 +195,7 @@ async function runReactNativeBundleCommand(
190
195
  bundleName,
191
196
  outputFolder,
192
197
  sourcemapOutput,
198
+ !isSentry,
193
199
  );
194
200
  }
195
201
  resolve(null);
@@ -253,6 +259,7 @@ async function compileHermesByteCode(
253
259
  bundleName,
254
260
  outputFolder,
255
261
  sourcemapOutput,
262
+ shouldCleanSourcemap,
256
263
  ) {
257
264
  console.log('Hermes enabled, now compiling to hermes bytecode:\n');
258
265
  // >= rn 0.69
@@ -309,9 +316,98 @@ async function compileHermesByteCode(
309
316
  },
310
317
  );
311
318
  }
319
+ if (shouldCleanSourcemap) {
320
+ fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
321
+ }
322
+ }
323
+
324
+ async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
325
+ if (sourcemapOutput) {
326
+ let copyDebugidPath;
327
+ try {
328
+ copyDebugidPath = require.resolve(
329
+ '@sentry/react-native/scripts/copy-debugid.js',
330
+ {
331
+ paths: [process.cwd()],
332
+ },
333
+ );
334
+ } catch (error) {
335
+ console.error(
336
+ '无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native',
337
+ );
338
+ return;
339
+ }
340
+
341
+ if (!fs.existsSync(copyDebugidPath)) {
342
+ return;
343
+ }
344
+ console.log('Copying debugid');
345
+ spawnSync(
346
+ 'node',
347
+ [
348
+ copyDebugidPath,
349
+ path.join(outputFolder, `${bundleName}.txt.map`),
350
+ path.join(outputFolder, `${bundleName}.map`),
351
+ ],
352
+ {
353
+ stdio: 'ignore',
354
+ },
355
+ );
356
+ }
312
357
  fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
313
358
  }
314
359
 
360
+ async function uploadSourcemapForSentry(
361
+ bundleName,
362
+ outputFolder,
363
+ sourcemapOutput,
364
+ version,
365
+ ) {
366
+ if (sourcemapOutput) {
367
+ let sentryCliPath;
368
+ try {
369
+ sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
370
+ paths: [process.cwd()],
371
+ });
372
+ } catch (error) {
373
+ console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
374
+ return;
375
+ }
376
+
377
+ if (!fs.existsSync(sentryCliPath)) {
378
+ return;
379
+ }
380
+
381
+ spawnSync(
382
+ 'node',
383
+ [sentryCliPath, 'releases', 'set-commits', version, '--auto'],
384
+ {
385
+ stdio: 'inherit',
386
+ },
387
+ );
388
+ console.log(`Sentry release created for version: ${version}`);
389
+
390
+ console.log('Uploading sourcemap');
391
+ spawnSync(
392
+ 'node',
393
+ [
394
+ sentryCliPath,
395
+ 'releases',
396
+ 'files',
397
+ version,
398
+ 'upload-sourcemaps',
399
+ '--strip-prefix',
400
+ path.join(process.cwd(), outputFolder),
401
+ path.join(outputFolder, bundleName),
402
+ path.join(outputFolder, `${bundleName}.map`),
403
+ ],
404
+ {
405
+ stdio: 'inherit',
406
+ },
407
+ );
408
+ }
409
+ }
410
+
315
411
  async function pack(dir, output) {
316
412
  console.log('Packing');
317
413
  fs.ensureDirSync(path.dirname(output));
@@ -718,12 +814,16 @@ export const commands = {
718
814
  options.platform || (await question('平台(ios/android/harmony):')),
719
815
  );
720
816
 
721
- const { bundleName, entryFile, intermediaDir, output, dev, sourcemap } =
817
+ const { bundleName, entryFile, intermediaDir, output, dev } =
722
818
  translateOptions({
723
819
  ...options,
724
820
  platform,
725
821
  });
726
822
 
823
+ const bundleParams = await checkPlugins();
824
+ const sourcemap = bundleParams.sourcemap;
825
+ const isSentry = bundleParams.sentry;
826
+
727
827
  const sourcemapOutput = path.join(intermediaDir, `${bundleName}.map`);
728
828
 
729
829
  const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
@@ -749,12 +849,21 @@ export const commands = {
749
849
 
750
850
  const v = await question('是否现在上传此热更包?(Y/N)');
751
851
  if (v.toLowerCase() === 'y') {
752
- await this.publish({
852
+ const versionName = await this.publish({
753
853
  args: [realOutput],
754
854
  options: {
755
855
  platform,
756
856
  },
757
857
  });
858
+ if (isSentry) {
859
+ await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
860
+ await uploadSourcemapForSentry(
861
+ bundleName,
862
+ intermediaDir,
863
+ sourcemapOutput,
864
+ versionName,
865
+ );
866
+ }
758
867
  }
759
868
  },
760
869
 
@@ -0,0 +1,30 @@
1
+ import { plugins } from './plugin-config';
2
+
3
+ interface BundleParams {
4
+ sentry: boolean;
5
+ minify: boolean;
6
+ sourcemap: boolean;
7
+ [key: string]: any;
8
+ }
9
+
10
+ export async function checkPlugins(): Promise<BundleParams> {
11
+ const params: BundleParams = {
12
+ sentry: false,
13
+ minify: true,
14
+ sourcemap: false,
15
+ };
16
+
17
+ for (const plugin of plugins) {
18
+ try {
19
+ const isEnabled = await plugin.detect();
20
+ if (isEnabled && plugin.bundleParams) {
21
+ Object.assign(params, plugin.bundleParams);
22
+ console.log(`检测到 ${plugin.name} 插件,应用相应打包配置`);
23
+ }
24
+ } catch (err) {
25
+ console.warn(`检测 ${plugin.name} 插件时出错:`, err);
26
+ }
27
+ }
28
+
29
+ return params;
30
+ }
@@ -6,6 +6,7 @@ import AppInfoParser from './app-info-parser';
6
6
  import semverSatisfies from 'semver/functions/satisfies';
7
7
  import chalk from 'chalk';
8
8
  import latestVersion from '@badisi/latest-version';
9
+ import { checkPlugins } from './check-plugin';
9
10
 
10
11
  import { read } from 'read';
11
12
 
@@ -225,3 +226,5 @@ export async function printVersionCommand() {
225
226
  }
226
227
 
227
228
  export const pricingPageUrl = 'https://pushy.reactnative.cn/pricing.html';
229
+
230
+ export { checkPlugins };
@@ -0,0 +1,34 @@
1
+ import fs from 'fs-extra';
2
+
3
+ interface PluginConfig {
4
+ name: string;
5
+ bundleParams?: {
6
+ minify?: boolean;
7
+ [key: string]: any;
8
+ };
9
+ detect: () => Promise<boolean>;
10
+ }
11
+
12
+ export const plugins: PluginConfig[] = [
13
+ {
14
+ name: 'sentry',
15
+ bundleParams: {
16
+ sentry: true,
17
+ minify: false,
18
+ sourcemap: true,
19
+ },
20
+ detect: async () => {
21
+ try {
22
+ await fs.access('ios/sentry.properties');
23
+ return true;
24
+ } catch {
25
+ try {
26
+ await fs.access('android/sentry.properties');
27
+ return true;
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ];
package/src/versions.js CHANGED
@@ -97,8 +97,9 @@ export const commands = {
97
97
 
98
98
  const { hash } = await uploadFile(fn);
99
99
 
100
+ const versionName = name || (await question('输入版本名称: ')) || '(未命名)';
100
101
  const { id } = await post(`/app/${appId}/version/create`, {
101
- name: name || (await question('输入版本名称: ')) || '(未命名)',
102
+ name: versionName,
102
103
  hash,
103
104
  description: description || (await question('输入版本描述:')),
104
105
  metaInfo: metaInfo || (await question('输入自定义的 meta info:')),
@@ -111,6 +112,7 @@ export const commands = {
111
112
  if (v.toLowerCase() === 'y') {
112
113
  await this.update({ args: [], options: { versionId: id, platform } });
113
114
  }
115
+ return versionName;
114
116
  },
115
117
  versions: async ({ options }) => {
116
118
  const platform = checkPlatform(