@flun/node-mobile-app 1.0.1 → 1.0.2
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/CHANGELOG.md +14 -0
- package/README.md +42 -43
- package/mobileAppConfig.js +14 -2
- package/package.json +17 -16
- package/src/copy.js +8 -13
- package/src/utils.js +34 -3
- package/template/App.tsx +2 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## [1.0.2] - 2026-09-21 08:24
|
|
2
|
+
|
|
3
|
+
### 修复
|
|
4
|
+
- **依赖树瘦身**:删除主包里未使用的 6 个依赖(`@babel/preset-env`、`@babel/runtime`、`@react-native/jest-preset`、`@react-native/new-app-screen`、`@react-native/typescript-config`、`react-native-safe-area-context`),安装体积与安装耗时下降
|
|
5
|
+
- **消除旧依赖链**:移除 `@react-native/eslint-config`,改为内置自写 ESLint flat config(`src/utils.js` 的 `buildEslintConfigSource()`,构建时覆写到 `node-mobile-app-build/eslint.config.js`)。随之消失的旧包:`inflight@1.0.6`、`rimraf@3.0.2`、`glob@7.2.3`、`@humanwhocodes/config-array`、`@humanwhocodes/object-schema`
|
|
6
|
+
- **ESLint 升级到 9**:统一使用 `eslint@^9`,不再出现 eslint 8 / 9 两份并存
|
|
7
|
+
- **模板 lint 清理**:修复 `template/App.tsx` 中逗号表达式触发的 `@typescript-eslint/no-unused-expressions` 报错,模板现在默认 `npx eslint` 零 error 零 warning
|
|
8
|
+
|
|
9
|
+
### 文档
|
|
10
|
+
- `mobileAppConfig.js` 与 `README.md` 更正签名说明:`build --release` **不配置 `android.signing` 也能出包**,默认沿用模板自带的 debug keystore 签名(可安装、可本地测试,不可上架);需要上架时再填 `keystore` / `storePassword` / `keyAlias` / `keyPassword`
|
|
11
|
+
|
|
12
|
+
## [1.0.1] - 2026-09-20 11:52
|
|
13
|
+
### 首发
|
|
14
|
+
- 发布将 Node.js 项目一键打包为 Android / iOS 移动应用(基于 nodejs-mobile-react-native);
|
package/README.md
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
直接给你 README 全文,复制到 `D:\Extend_npm\node-mobile-app\README.md` 即可。
|
|
2
1
|
# @flun/node-mobile-app
|
|
3
2
|
|
|
4
3
|
将 Node.js 项目一键打包为 Android / iOS 移动应用。基于 [nodejs-mobile-react-native](https://github.com/nodejs-mobile/nodejs-mobile-react-native)。
|
|
@@ -152,14 +151,14 @@ npx node-mobile-app build --release
|
|
|
152
151
|
|
|
153
152
|
## 命令说明
|
|
154
153
|
|
|
155
|
-
| 命令 | 用途
|
|
156
|
-
| ------------------------------------- |
|
|
157
|
-
| `npx node-mobile-app test` | 编译并安装到设备(**需连 USB**,走 Metro 热更新)
|
|
158
|
-
| `npx node-mobile-app test --ios` | iOS 版(仅 macOS)
|
|
159
|
-
| `npx node-mobile-app build` | 打 debug APK(**离线可用**)
|
|
160
|
-
| `npx node-mobile-app build --release` | 打 release APK
|
|
161
|
-
| `npx node-mobile-app build --ios` | 打 IPA(仅 macOS)
|
|
162
|
-
| `npx node-mobile-app clean` | 清理构建缓存
|
|
154
|
+
| 命令 | 用途 |
|
|
155
|
+
| ------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
156
|
+
| `npx node-mobile-app test` | 编译并安装到设备(**需连 USB**,走 Metro 热更新) |
|
|
157
|
+
| `npx node-mobile-app test --ios` | iOS 版(仅 macOS) |
|
|
158
|
+
| `npx node-mobile-app build` | 打 debug APK(**离线可用**) |
|
|
159
|
+
| `npx node-mobile-app build --release` | 打 release APK(默认用 debug keystore 签名,可安装;上架需配置 `android.signing`) |
|
|
160
|
+
| `npx node-mobile-app build --ios` | 打 IPA(仅 macOS) |
|
|
161
|
+
| `npx node-mobile-app clean` | 清理构建缓存 |
|
|
163
162
|
|
|
164
163
|
### 常用选项
|
|
165
164
|
|
|
@@ -215,47 +214,47 @@ adb install -r ./out/<appName>-<versionName>-debug.apk
|
|
|
215
214
|
|
|
216
215
|
### WebView
|
|
217
216
|
|
|
218
|
-
| 字段 | 类型 | 默认 | 说明
|
|
219
|
-
| --------------------- | --------- | ------------------- |
|
|
220
|
-
| `showLoading` | `boolean` | `true` | 是否显示加载指示器
|
|
221
|
-
| `loadingText` | `string` | `'正在启动服务...'` | 加载提示文字
|
|
222
|
-
| `enableJavaScript` | `boolean` | `true` | 是否启用 JavaScript
|
|
223
|
-
| `enableDomStorage` | `boolean` | `true` | 是否启用 DOM Storage
|
|
224
|
-
| `allowFileAccess` | `boolean` | `true` | 是否允许访问本地文件
|
|
225
|
-
| `mixedContentMode` | `string` | `'always'` | 混合内容模式:`never` / `always` / `compatibility`
|
|
217
|
+
| 字段 | 类型 | 默认 | 说明 |
|
|
218
|
+
| --------------------- | --------- | ------------------- | ------------------------------------------------------------------------------------------- |
|
|
219
|
+
| `showLoading` | `boolean` | `true` | 是否显示加载指示器 |
|
|
220
|
+
| `loadingText` | `string` | `'正在启动服务...'` | 加载提示文字 |
|
|
221
|
+
| `enableJavaScript` | `boolean` | `true` | 是否启用 JavaScript |
|
|
222
|
+
| `enableDomStorage` | `boolean` | `true` | 是否启用 DOM Storage |
|
|
223
|
+
| `allowFileAccess` | `boolean` | `true` | 是否允许访问本地文件 |
|
|
224
|
+
| `mixedContentMode` | `string` | `'always'` | 混合内容模式:`never` / `always` / `compatibility` |
|
|
226
225
|
| `backgroundColor` | 见下 | `'#ffffff'` | WebView 背景色。支持:固定色 `'#ffffff'` / 跟随系统 `'system'` / 深浅两值 `{ light, dark }` |
|
|
227
|
-
| `allowSelfSignedCert` | `boolean` | `false` | 见下文「HTTPS 自签证书」
|
|
226
|
+
| `allowSelfSignedCert` | `boolean` | `false` | 见下文「HTTPS 自签证书」 |
|
|
228
227
|
|
|
229
228
|
### Android
|
|
230
229
|
|
|
231
|
-
| 字段 | 类型 | 默认 | 说明
|
|
232
|
-
| ----------------------- | ---------------- | -------------------- |
|
|
233
|
-
| `sdkPath` | `string \| null` | `null` | Android SDK 路径(默认自动查找)
|
|
234
|
-
| `adbPath` | `string \| null` | `null` | adb 路径(默认自动查找)
|
|
235
|
-
| `minSdkVersion` | `int` | `29` | 最低 SDK(29=Android 10.0)
|
|
236
|
-
| `targetSdkVersion` | `int` | `36` | 目标 SDK
|
|
237
|
-
| `compileSdkVersion` | `int` | `37` | 编译 SDK
|
|
238
|
-
| `buildToolsVersion` | `string` | `'37.0.0'` | 构建工具版本
|
|
239
|
-
| `abiFilters` | `string[]` | `['arm64-v8a']` | 打包架构(真机 `arm64-v8a`,模拟器加 `x86_64`)
|
|
240
|
-
| `icon` | `string` | `'./build/icon.png'` | 应用图标(建议 512×512 PNG)
|
|
241
|
-
| `usesCleartextTraffic` | `boolean` | `true` | 是否允许明文 HTTP
|
|
242
|
-
| `permissions` | `string[]` | `[]` | 额外权限(如 `'android.permission.CAMERA'`)
|
|
243
|
-
| `signing.keystore` | `string` | — | 签名 keystore
|
|
244
|
-
| `signing.storePassword` | `string` | — | keystore 密码
|
|
245
|
-
| `signing.keyAlias` | `string` | — | key 别名
|
|
246
|
-
| `signing.keyPassword` | `string` | — | key 密码
|
|
247
|
-
| `buildNativeModules` | `boolean` | `false` | 是否在 `nodejs-project` 里编译原生模块(`bcrypt` 等)
|
|
230
|
+
| 字段 | 类型 | 默认 | 说明 |
|
|
231
|
+
| ----------------------- | ---------------- | -------------------- | ----------------------------------------------------------------------- |
|
|
232
|
+
| `sdkPath` | `string \| null` | `null` | Android SDK 路径(默认自动查找) |
|
|
233
|
+
| `adbPath` | `string \| null` | `null` | adb 路径(默认自动查找) |
|
|
234
|
+
| `minSdkVersion` | `int` | `29` | 最低 SDK(29=Android 10.0) |
|
|
235
|
+
| `targetSdkVersion` | `int` | `36` | 目标 SDK |
|
|
236
|
+
| `compileSdkVersion` | `int` | `37` | 编译 SDK |
|
|
237
|
+
| `buildToolsVersion` | `string` | `'37.0.0'` | 构建工具版本 |
|
|
238
|
+
| `abiFilters` | `string[]` | `['arm64-v8a']` | 打包架构(真机 `arm64-v8a`,模拟器加 `x86_64`) |
|
|
239
|
+
| `icon` | `string` | `'./build/icon.png'` | 应用图标(建议 512×512 PNG) |
|
|
240
|
+
| `usesCleartextTraffic` | `boolean` | `true` | 是否允许明文 HTTP |
|
|
241
|
+
| `permissions` | `string[]` | `[]` | 额外权限(如 `'android.permission.CAMERA'`) |
|
|
242
|
+
| `signing.keystore` | `string` | — | 签名 keystore 路径(相对你的项目根)。不填则用模板自带的 debug keystore |
|
|
243
|
+
| `signing.storePassword` | `string` | — | keystore 密码 |
|
|
244
|
+
| `signing.keyAlias` | `string` | — | key 别名 |
|
|
245
|
+
| `signing.keyPassword` | `string` | — | key 密码 |
|
|
246
|
+
| `buildNativeModules` | `boolean` | `false` | 是否在 `nodejs-project` 里编译原生模块(`bcrypt` 等) |
|
|
248
247
|
|
|
249
248
|
### iOS
|
|
250
249
|
|
|
251
|
-
| 字段 | 类型 | 默认 | 说明
|
|
252
|
-
| ----------------------------- | -------- | -------------------- |
|
|
253
|
-
| `deploymentTarget` | `string` | `'15.1'` | 最低 iOS 版本
|
|
254
|
-
| `icon` | `string` | `'./build/icon.png'` | 应用图标(建议 1024×1024 PNG)
|
|
255
|
-
| `signing.teamId` | `string` | — | Apple Developer Team ID
|
|
256
|
-
| `signing.provisioningProfile` | `string` | —
|
|
257
|
-
| `signing.certificate` | `string` | —
|
|
258
|
-
| `signing.certificatePassword` | `string` | —
|
|
250
|
+
| 字段 | 类型 | 默认 | 说明 |
|
|
251
|
+
| ----------------------------- | -------- | -------------------- | ------------------------------------------------------ |
|
|
252
|
+
| `deploymentTarget` | `string` | `'15.1'` | 最低 iOS 版本 |
|
|
253
|
+
| `icon` | `string` | `'./build/icon.png'` | 应用图标(建议 1024×1024 PNG) |
|
|
254
|
+
| `signing.teamId` | `string` | — | Apple Developer Team ID |
|
|
255
|
+
| `signing.provisioningProfile` | `string` | — | 描述文件路径(写入 `exportOptions.plist`) |
|
|
256
|
+
| `signing.certificate` | `string` | — | P12 证书路径(导入临时 keychain 供 xcodebuild 签名用) |
|
|
257
|
+
| `signing.certificatePassword` | `string` | — | P12 密码 |
|
|
259
258
|
|
|
260
259
|
### 高级
|
|
261
260
|
|
package/mobileAppConfig.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* npx node-mobile-app test 编译并安装到设备(需连 USB,走 Metro 热更新)
|
|
9
9
|
* npx node-mobile-app test --ios iOS 版(仅 macOS)
|
|
10
10
|
* npx node-mobile-app build 打 debug APK(离线可用)
|
|
11
|
-
* npx node-mobile-app build --release 打 release APK
|
|
11
|
+
* npx node-mobile-app build --release 打 release APK(默认 debug keystore 签名,可安装;上架需配 android.signing)
|
|
12
12
|
* npx node-mobile-app build --ios 打 IPA(仅 macOS)
|
|
13
13
|
* npx node-mobile-app clean 清理构建缓存
|
|
14
14
|
*
|
|
@@ -70,7 +70,19 @@ export default {
|
|
|
70
70
|
// 'android.permission.CAMERA',
|
|
71
71
|
// 'android.permission.READ_EXTERNAL_STORAGE',
|
|
72
72
|
],
|
|
73
|
-
//
|
|
73
|
+
// 签名配置(可选)
|
|
74
|
+
//
|
|
75
|
+
// 不配置也能打 release:模板默认用 debug keystore 签名(可安装、可本地测试,不可上架)。
|
|
76
|
+
// 需要上架时再配置下面任一种:
|
|
77
|
+
//
|
|
78
|
+
// 方式一:Android SDK 自带 debug keystore(本地测试常用)
|
|
79
|
+
// keystore: %USERPROFILE%\.android\debug.keystore (Windows)
|
|
80
|
+
// ~/.android/debug.keystore (macOS/Linux)
|
|
81
|
+
// storePassword: 'android'
|
|
82
|
+
// keyAlias: 'androiddebugkey'
|
|
83
|
+
// keyPassword: 'android'
|
|
84
|
+
//
|
|
85
|
+
// 自定义签名:取消下面注释,填入你的 keystore 信息
|
|
74
86
|
signing: {
|
|
75
87
|
// keystore: './build/release.keystore',
|
|
76
88
|
// storePassword: '',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flun/node-mobile-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "将 Node.js 项目一键打包为 Android / iOS 移动应用(基于 nodejs-mobile-react-native)",
|
|
5
5
|
"author": "flun <open@flun.top>",
|
|
6
6
|
"keywords": [
|
|
@@ -28,11 +28,12 @@
|
|
|
28
28
|
"scripts/",
|
|
29
29
|
"src/",
|
|
30
30
|
"template/",
|
|
31
|
-
"LICENSE",
|
|
32
|
-
"mobileAppConfig.js",
|
|
33
|
-
"README.md",
|
|
34
31
|
"自定义libnode指南.md",
|
|
35
32
|
"Android 构建指南.md",
|
|
33
|
+
"CHANGELOG.md",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"mobileAppConfig.js",
|
|
36
37
|
"package.json"
|
|
37
38
|
],
|
|
38
39
|
"scripts": {
|
|
@@ -40,28 +41,28 @@
|
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
43
|
"@babel/core": "^8.0.6",
|
|
43
|
-
"@babel/preset-env": "^8.0.6",
|
|
44
|
-
"@babel/runtime": "^8.0.5",
|
|
45
44
|
"@react-native-community/cli": "^20.2.0",
|
|
46
45
|
"@react-native-community/cli-platform-android": "^20.2.0",
|
|
47
46
|
"@react-native-community/cli-platform-ios": "^20.2.0",
|
|
48
47
|
"@react-native/babel-preset": "^0.87.1",
|
|
49
|
-
"@react-native/eslint-config": "^0.87.1",
|
|
50
|
-
"@react-native/jest-preset": "^0.87.1",
|
|
51
48
|
"@react-native/metro-config": "^0.87.1",
|
|
52
|
-
"
|
|
53
|
-
"@react-native/typescript-config": "^0.87.1",
|
|
54
|
-
"jimp": "^1.6.0",
|
|
49
|
+
"jimp": "^1.6.1",
|
|
55
50
|
"nodejs-mobile-react-native": "^18.20.4",
|
|
56
51
|
"react": "^19.3.0",
|
|
57
52
|
"react-native": "^0.87.1",
|
|
58
|
-
"react-native-
|
|
59
|
-
"react-native-webview": "^14.0.1"
|
|
60
|
-
},
|
|
61
|
-
"devDependencies": {
|
|
53
|
+
"react-native-webview": "^14.0.1",
|
|
62
54
|
"@types/react": "^19.3.0",
|
|
63
55
|
"prettier": "^3.9.8",
|
|
64
|
-
"
|
|
56
|
+
"eslint": "^10.11.0",
|
|
57
|
+
"@eslint/js": "^10.0.1",
|
|
58
|
+
"@babel/eslint-parser": "^7.29.9",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^8.70.0",
|
|
60
|
+
"@typescript-eslint/parser": "^8.70.0",
|
|
61
|
+
"eslint-config-prettier": "^10.1.8",
|
|
62
|
+
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
63
|
+
"eslint-plugin-react": "^7.37.5",
|
|
64
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
65
|
+
"eslint-plugin-react-native": "^5.0.0"
|
|
65
66
|
},
|
|
66
67
|
"allowScripts": {
|
|
67
68
|
"node": true,
|
package/src/copy.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ensureDir, removeDir, readJson, isExcluded, copyFileIfChanged, writeIfChanged, buildEslintConfigSource
|
|
5
|
+
} from './utils.js';
|
|
4
6
|
import { resolveSdkPath } from './config.js';
|
|
5
7
|
|
|
6
8
|
const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
@@ -66,6 +68,7 @@ const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
|
66
68
|
|
|
67
69
|
const keepSet = new Set((config && config.keepFiles) || []);
|
|
68
70
|
copyDirOverwrite(templateDir, buildDir, TEMPLATE_EXCLUDE, buildDir, keepSet);
|
|
71
|
+
fs.writeFileSync(path.join(buildDir, 'eslint.config.js'), buildEslintConfigSource(), 'utf-8');
|
|
69
72
|
console.log(' ✓ 模板已更新到', BUILD_DIR_NAME + '/');
|
|
70
73
|
if (keepSet.size > 0) console.log(' 保留文件:', Array.from(keepSet).join(', '));
|
|
71
74
|
},
|
|
@@ -121,8 +124,7 @@ const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
|
121
124
|
const fallback = path.join(pkgRoot, 'cli-assets', 'server.js');
|
|
122
125
|
if (!fs.existsSync(fallback)) throw new Error('入口文件不存在: ' + config.serverPath + '(CLI 内置模板也缺失)');
|
|
123
126
|
|
|
124
|
-
ensureDir(path.dirname(entryPath));
|
|
125
|
-
fs.copyFileSync(fallback, entryPath);
|
|
127
|
+
ensureDir(path.dirname(entryPath)), fs.copyFileSync(fallback, entryPath);
|
|
126
128
|
console.log(' ✓ 生成默认入口文件:', config.serverPath);
|
|
127
129
|
console.log(' (因为用户项目里没有这个文件,从 CLI 内置模板复制)');
|
|
128
130
|
|
|
@@ -161,17 +163,10 @@ const BUILD_DIR_NAME = 'node-mobile-app-build',
|
|
|
161
163
|
const before = c;
|
|
162
164
|
|
|
163
165
|
// defaultConfig 里的 ndk { abiFilters ... }
|
|
164
|
-
c = c.replace(
|
|
165
|
-
/(defaultConfig\s*\{[\s\S]*?ndk\s*\{\s*abiFilters\s+)("[^"]*"(?:\s*,\s*"[^"]*")*)/,
|
|
166
|
-
`$1${abiList}`
|
|
167
|
-
);
|
|
166
|
+
c = c.replace(/(defaultConfig\s*\{[\s\S]*?ndk\s*\{\s*abiFilters\s+)("[^"]*"(?:\s*,\s*"[^"]*")*)/, `$1${abiList}`);
|
|
168
167
|
// 兜底:没有 ndk {} 块时,插到 defaultConfig 里
|
|
169
|
-
if (!/ndk\s*\{\s*abiFilters/.test(c))
|
|
170
|
-
c = c.replace(
|
|
171
|
-
/(defaultConfig\s*\{)/,
|
|
172
|
-
`$1\n ndk {\n abiFilters ${abiList}\n }`
|
|
173
|
-
);
|
|
174
|
-
}
|
|
168
|
+
if (!/ndk\s*\{\s*abiFilters/.test(c))
|
|
169
|
+
c = c.replace(/(defaultConfig\s*\{)/, `$1\n ndk {\n abiFilters ${abiList}\n }`);
|
|
175
170
|
// 不 patch splits.abi.include:AGP 禁止它和 ndk.abiFilters 同时存在
|
|
176
171
|
if (c !== before) writeIfChanged(file, c), console.log(` ✓ 已设置 app ndk.abiFilters = [${abiList}]`);
|
|
177
172
|
|
package/src/utils.js
CHANGED
|
@@ -123,9 +123,40 @@ const ensureDir = dir => {
|
|
|
123
123
|
sanitizeFileName = s => {
|
|
124
124
|
const cleaned = String(s).replace(/[\\/:*?"<>|]/g, '_').trim();
|
|
125
125
|
return cleaned || 'app';
|
|
126
|
-
}
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* 生成 ESLint flat config 源码(替代 @react-native/eslint-config/flat)
|
|
129
|
+
*/
|
|
130
|
+
buildEslintConfigSource = () => `import js from '@eslint/js';
|
|
131
|
+
import babelParser from '@babel/eslint-parser';
|
|
132
|
+
import tsParser from '@typescript-eslint/parser';
|
|
133
|
+
import tsPlugin from '@typescript-eslint/eslint-plugin';
|
|
134
|
+
import reactPlugin from 'eslint-plugin-react';
|
|
135
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
136
|
+
import reactNative from 'eslint-plugin-react-native';
|
|
137
|
+
import prettier from 'eslint-config-prettier';
|
|
138
|
+
|
|
139
|
+
export default [
|
|
140
|
+
js.configs.recommended,
|
|
141
|
+
{
|
|
142
|
+
files: ['**/*.{js,jsx,ts,tsx}'],
|
|
143
|
+
languageOptions: {
|
|
144
|
+
parser: babelParser,
|
|
145
|
+
parserOptions: { requireConfigFile: false, babelOptions: { presets: ['module:@react-native/babel-preset'] } },
|
|
146
|
+
},
|
|
147
|
+
plugins: { react: reactPlugin, 'react-hooks': reactHooks, 'react-native': reactNative },
|
|
148
|
+
settings: { react: { version: 'detect' } },
|
|
149
|
+
rules: {
|
|
150
|
+
...reactPlugin.configs.recommended.rules,
|
|
151
|
+
...reactHooks.configs.recommended.rules,
|
|
152
|
+
'react/react-in-jsx-scope': 'off',
|
|
153
|
+
'react/prop-types': 'off',
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{ files: ['**/*.{ts,tsx}'], languageOptions: { parser: tsParser }, plugins: { '@typescript-eslint': tsPlugin },
|
|
157
|
+
rules: tsPlugin.configs.recommended.rules }, prettier];`;
|
|
127
158
|
|
|
128
159
|
export {
|
|
129
|
-
ensureDir, removeDir, isExcluded, copyDir, readJson, writeJson, writeIfChanged, copyFileIfChanged,
|
|
130
|
-
|
|
160
|
+
ensureDir, removeDir, isExcluded, copyDir, readJson, writeJson, writeIfChanged, copyFileIfChanged, run, runQuiet,
|
|
161
|
+
runSilent, findAdb, findHermesc, sanitizeFileName, buildEslintConfigSource
|
|
131
162
|
};
|
package/template/App.tsx
CHANGED
|
@@ -50,7 +50,8 @@ const App = () => {
|
|
|
50
50
|
if (typeof msg !== 'string') return;
|
|
51
51
|
if (msg.startsWith('Node started on ')) {
|
|
52
52
|
const target = msg.slice('Node started on '.length).trim();
|
|
53
|
-
setFailedReason(null)
|
|
53
|
+
setFailedReason(null);
|
|
54
|
+
setUrl(target);
|
|
54
55
|
} else if (msg.startsWith('Node failed: ')) {
|
|
55
56
|
const reason = msg.slice('Node failed: '.length).trim();
|
|
56
57
|
setFailedReason(reason);
|