pake-cli 3.3.1 → 3.3.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/README.md +22 -40
- package/dist/cli.js +143 -95
- package/package.json +6 -6
- package/src-tauri/.pake/pake.json +1 -1
- package/src-tauri/.pake/tauri.conf.json +4 -4
- package/src-tauri/.pake/tauri.macos.conf.json +2 -2
- package/src-tauri/Cargo.lock +152 -97
- package/src-tauri/src/app/window.rs +14 -17
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<img src=https://gw.alipayobjects.com/zos/k/fa/logo-modified.png width=138/>
|
|
4
4
|
</p>
|
|
5
5
|
<h1 align="center">Pake</h1>
|
|
6
|
-
<p align="center"><strong>Turn any webpage into a desktop app with
|
|
6
|
+
<p align="center"><strong>Turn any webpage into a desktop app with one command, supports macOS, Windows, and Linux</strong></p>
|
|
7
7
|
<div align="center">
|
|
8
8
|
<a href="https://twitter.com/HiTw93" target="_blank">
|
|
9
9
|
<img alt="twitter" src="https://img.shields.io/badge/follow-Tw93-red?style=flat-square&logo=Twitter"></a>
|
|
@@ -15,19 +15,20 @@
|
|
|
15
15
|
<img alt="GitHub commit" src="https://img.shields.io/github/commit-activity/m/tw93/Pake?style=flat-square"></a>
|
|
16
16
|
<a href="https://github.com/tw93/Pake/issues?q=is%3Aissue+is%3Aclosed" target="_blank">
|
|
17
17
|
<img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed/tw93/Pake.svg?style=flat-square"></a>
|
|
18
|
-
<a href="https://colab.research.google.com/drive/1bX345znvDZ30848xjRtpgtU8eypWwXrp?usp=sharing" target="_blank">
|
|
19
|
-
<img alt="Open in Colab" src="https://colab.research.google.com/assets/colab-badge.svg"></a>
|
|
20
18
|
</div>
|
|
21
19
|
|
|
22
|
-
<div align="left">Pake supports Mac, Windows, and Linux. Check out README for <a href="#popular-packages">Popular Packages</a>, <a href="#command-line-packaging">Command-Line Packaging</a>, and <a href="#development">Customized Development</a> information. Feel free to share your suggestions in <a href=https://github.com/tw93/Pake/discussions>Discussions</a>.</div>
|
|
23
|
-
|
|
24
20
|
## Features
|
|
25
21
|
|
|
26
|
-
- 🎐 Nearly 20 times smaller than
|
|
27
|
-
- 🚀
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
22
|
+
- 🎐 **Lightweight**: Nearly 20 times smaller than Electron packages, typically around 5M
|
|
23
|
+
- 🚀 **Fast**: Built with Rust Tauri, much faster than traditional JS frameworks with lower memory usage
|
|
24
|
+
- ⚡ **Easy to use**: One-command packaging via CLI or online building, no complex configuration needed
|
|
25
|
+
- 📦 **Feature-rich**: Supports shortcut pass-through, immersive windows, drag & drop, style customization, ad removal
|
|
26
|
+
|
|
27
|
+
## Getting Started
|
|
28
|
+
|
|
29
|
+
- **Beginners**: Download ready-made [Popular Packages](#popular-packages) or use [Online Building](docs/github-actions-usage.md) with no environment setup required
|
|
30
|
+
- **Developers**: Install [CLI Tool](docs/cli-usage.md) for one-command packaging of any website with customizable icons, window settings, and more
|
|
31
|
+
- **Advanced Users**: Clone the project locally for [Custom Development](#development), or check [Advanced Usage](docs/advanced-usage.md) for style customization and feature enhancement
|
|
31
32
|
|
|
32
33
|
## Popular Packages
|
|
33
34
|
|
|
@@ -152,58 +153,39 @@ In addition, double-click the title bar to switch to full-screen mode. For Mac u
|
|
|
152
153
|
|
|
153
154
|
</details>
|
|
154
155
|
|
|
155
|
-
## Before starting
|
|
156
|
-
|
|
157
|
-
1. **For beginners**: Play with Popular Packages to find out Pake's capabilities, or try to pack your application with [GitHub Actions](docs/github-actions-usage.md). Don't hesitate to reach for assistance at [Discussion](https://github.com/tw93/Pake/discussions)!
|
|
158
|
-
2. **For developers**: “Command-Line Packaging” supports macOS fully. For Windows/Linux users, it requires some tinkering. [Configure your environment](https://tauri.app/start/prerequisites/) before getting started.
|
|
159
|
-
3. **For hackers**: For people who are good at both front-end development and Rust, how about customizing your apps' function more with the following [Customized Development](#development)?
|
|
160
|
-
|
|
161
156
|
## Command-Line Packaging
|
|
162
157
|
|
|
163
158
|

|
|
164
159
|
|
|
165
|
-
**Pake provides a command line tool, making the flow of package customization quicker and easier. See the [CLI usage guide](docs/cli-usage.md) for more information.**
|
|
166
|
-
|
|
167
160
|
```bash
|
|
168
|
-
#
|
|
161
|
+
# Install
|
|
169
162
|
pnpm install -g pake-cli
|
|
170
163
|
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
# Command usage
|
|
175
|
-
pake url [OPTIONS]...
|
|
164
|
+
# Basic usage (auto-fetch website icon)
|
|
165
|
+
pake https://weekly.tw93.fun --name Weekly
|
|
176
166
|
|
|
177
|
-
#
|
|
178
|
-
pake https://weekly.tw93.fun --name Weekly --hide-title-bar
|
|
167
|
+
# Common options: --name app name, --icon custom icon, --width/--height window size, --hide-title-bar macOS immersive
|
|
168
|
+
pake https://weekly.tw93.fun --name Weekly --icon https://cdn.tw93.fun/pake/weekly.icns --hide-title-bar
|
|
179
169
|
```
|
|
180
170
|
|
|
181
|
-
|
|
171
|
+
First-time packaging requires environment setup and may be slower, subsequent builds are fast. For complete parameter documentation, see [CLI Usage Guide](docs/cli-usage.md). Don't want to use CLI? Try [GitHub Actions Online Building](docs/github-actions-usage.md).
|
|
182
172
|
|
|
183
173
|
## Development
|
|
184
174
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
If you are unfamiliar with these, it is better to try out the above tool to pack with one click.
|
|
175
|
+
Requires Rust `>=1.89` and Node `>=22`. For detailed installation guide, see [Tauri documentation](https://tauri.app/start/prerequisites/). If unfamiliar with development environment, use the CLI tool instead.
|
|
188
176
|
|
|
189
|
-
```
|
|
177
|
+
```bash
|
|
190
178
|
# Install dependencies
|
|
191
179
|
pnpm i
|
|
192
180
|
|
|
193
|
-
# Local development
|
|
181
|
+
# Local development [right-click to open debug mode]
|
|
194
182
|
pnpm run dev
|
|
195
183
|
|
|
196
184
|
# Build application
|
|
197
185
|
pnpm run build
|
|
198
186
|
```
|
|
199
187
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
- **[CLI Usage](docs/cli-usage.md)** | [中文](docs/cli-usage_CN.md) - Command-line interface reference
|
|
203
|
-
- **[Advanced Usage](docs/advanced-usage.md)** | [中文](docs/advanced-usage_CN.md) - Customization and advanced features
|
|
204
|
-
- **[GitHub Actions](docs/github-actions-usage.md)** | [中文](docs/github-actions-usage_CN.md) - Build apps online
|
|
205
|
-
- **[Pake Action](docs/pake-action.md)** - Use Pake as GitHub Action in your projects
|
|
206
|
-
- **[Contributing](CONTRIBUTING.md)** - How to contribute to development
|
|
188
|
+
For style customization, feature enhancement, container communication and other advanced features, see [Advanced Usage Documentation](docs/advanced-usage.md).
|
|
207
189
|
|
|
208
190
|
## Developers
|
|
209
191
|
|
|
@@ -548,6 +530,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
|
|
|
548
530
|
## Support
|
|
549
531
|
|
|
550
532
|
1. I have two cats, TangYuan and Coke. If you think Pake delights your life, you can feed them <a href="https://miaoyan.app/cats.html?name=Pake" target="_blank">some canned food 🥩</a>.
|
|
551
|
-
2. If you like Pake, you can star it on GitHub. Also, welcome to [recommend Pake](https://twitter.com/intent/tweet?url=https://github.com/tw93/Pake&text
|
|
533
|
+
2. If you like Pake, you can star it on GitHub. Also, welcome to [recommend Pake](https://twitter.com/intent/tweet?url=https://github.com/tw93/Pake&text=Pake%20-%20Turn%20any%20webpage%20into%20a%20desktop%20app%20with%20one%20command.%20Nearly%2020x%20smaller%20than%20Electron%20packages,%20supports%20macOS%20Windows%20Linux) to your friends.
|
|
552
534
|
3. You can follow my [Twitter](https://twitter.com/HiTw93) to get the latest news of Pake or join our [Telegram](https://t.me/+GclQS9ZnxyI2ODQ1) chat group.
|
|
553
535
|
4. I hope that you enjoy playing with it. Let us know if you find a website that would be great for a Mac App!
|
package/dist/cli.js
CHANGED
|
@@ -22,8 +22,8 @@ import sharp from 'sharp';
|
|
|
22
22
|
import * as psl from 'psl';
|
|
23
23
|
|
|
24
24
|
var name = "pake-cli";
|
|
25
|
-
var version = "3.3.
|
|
26
|
-
var description = "🤱🏻 Turn any webpage into a desktop app with
|
|
25
|
+
var version = "3.3.2";
|
|
26
|
+
var description = "🤱🏻 Turn any webpage into a desktop app with one command. 🤱🏻 一键打包网页生成轻量桌面应用。";
|
|
27
27
|
var engines = {
|
|
28
28
|
node: ">=18.0.0"
|
|
29
29
|
};
|
|
@@ -73,7 +73,7 @@ var exports = "./dist/cli.js";
|
|
|
73
73
|
var license = "MIT";
|
|
74
74
|
var dependencies = {
|
|
75
75
|
"@tauri-apps/api": "^2.8.0",
|
|
76
|
-
"@tauri-apps/cli": "^2.8.
|
|
76
|
+
"@tauri-apps/cli": "^2.8.4",
|
|
77
77
|
axios: "^1.11.0",
|
|
78
78
|
chalk: "^5.6.0",
|
|
79
79
|
commander: "^12.1.0",
|
|
@@ -85,7 +85,7 @@ var dependencies = {
|
|
|
85
85
|
ora: "^8.2.0",
|
|
86
86
|
prompts: "^2.4.2",
|
|
87
87
|
psl: "^1.15.0",
|
|
88
|
-
sharp: "^0.33.
|
|
88
|
+
sharp: "^0.33.5",
|
|
89
89
|
"tmp-promise": "^3.0.3",
|
|
90
90
|
"update-notifier": "^7.3.1"
|
|
91
91
|
};
|
|
@@ -96,7 +96,7 @@ var devDependencies = {
|
|
|
96
96
|
"@rollup/plugin-replace": "^6.0.2",
|
|
97
97
|
"@rollup/plugin-terser": "^0.4.4",
|
|
98
98
|
"@types/fs-extra": "^11.0.4",
|
|
99
|
-
"@types/node": "^20.19.
|
|
99
|
+
"@types/node": "^20.19.13",
|
|
100
100
|
"@types/page-icon": "^0.3.6",
|
|
101
101
|
"@types/prompts": "^2.4.9",
|
|
102
102
|
"@types/tmp": "^0.2.6",
|
|
@@ -104,7 +104,7 @@ var devDependencies = {
|
|
|
104
104
|
"app-root-path": "^3.1.0",
|
|
105
105
|
"cross-env": "^7.0.3",
|
|
106
106
|
prettier: "^3.6.2",
|
|
107
|
-
rollup: "^4.
|
|
107
|
+
rollup: "^4.50.0",
|
|
108
108
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
109
109
|
tslib: "^2.8.1",
|
|
110
110
|
typescript: "^5.9.2"
|
|
@@ -1150,20 +1150,54 @@ async function checkUpdateTips() {
|
|
|
1150
1150
|
});
|
|
1151
1151
|
}
|
|
1152
1152
|
|
|
1153
|
-
// Constants
|
|
1154
1153
|
const ICON_CONFIG = {
|
|
1155
1154
|
minFileSize: 100,
|
|
1156
|
-
downloadTimeout: 10000,
|
|
1157
1155
|
supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp', 'icns'],
|
|
1158
1156
|
whiteBackground: { r: 255, g: 255, b: 255 },
|
|
1157
|
+
transparentBackground: { r: 255, g: 255, b: 255, alpha: 0 },
|
|
1158
|
+
downloadTimeout: {
|
|
1159
|
+
ci: 5000,
|
|
1160
|
+
default: 15000,
|
|
1161
|
+
},
|
|
1162
|
+
};
|
|
1163
|
+
const PLATFORM_CONFIG = {
|
|
1164
|
+
win: { format: '.ico', sizes: [16, 32, 48, 64, 128, 256] },
|
|
1165
|
+
linux: { format: '.png', size: 512 },
|
|
1166
|
+
macos: { format: '.icns', sizes: [16, 32, 64, 128, 256, 512, 1024] },
|
|
1159
1167
|
};
|
|
1160
|
-
|
|
1161
|
-
const API_TOKENS = {
|
|
1162
|
-
// cspell:disable-next-line
|
|
1168
|
+
const API_KEYS = {
|
|
1163
1169
|
logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
|
|
1164
|
-
// cspell:disable-next-line
|
|
1165
1170
|
brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
|
|
1166
1171
|
};
|
|
1172
|
+
/**
|
|
1173
|
+
* Generates platform-specific icon paths and handles copying for Windows
|
|
1174
|
+
*/
|
|
1175
|
+
function generateIconPath(appName, isDefault = false) {
|
|
1176
|
+
const safeName = appName.toLowerCase().replace(/[^a-z0-9-_]/g, '_');
|
|
1177
|
+
const baseName = isDefault ? 'icon' : safeName;
|
|
1178
|
+
if (IS_WIN) {
|
|
1179
|
+
return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_256.ico`);
|
|
1180
|
+
}
|
|
1181
|
+
if (IS_LINUX) {
|
|
1182
|
+
return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_512.png`);
|
|
1183
|
+
}
|
|
1184
|
+
return path.join(npmDirectory, 'src-tauri', 'icons', `${baseName}.icns`);
|
|
1185
|
+
}
|
|
1186
|
+
async function copyWindowsIconIfNeeded(convertedPath, appName) {
|
|
1187
|
+
if (!IS_WIN || !convertedPath.endsWith('.ico')) {
|
|
1188
|
+
return convertedPath;
|
|
1189
|
+
}
|
|
1190
|
+
try {
|
|
1191
|
+
const finalIconPath = generateIconPath(appName);
|
|
1192
|
+
await fsExtra.ensureDir(path.dirname(finalIconPath));
|
|
1193
|
+
await fsExtra.copy(convertedPath, finalIconPath);
|
|
1194
|
+
return finalIconPath;
|
|
1195
|
+
}
|
|
1196
|
+
catch (error) {
|
|
1197
|
+
logger.warn(`Failed to copy Windows icon: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1198
|
+
return convertedPath;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1167
1201
|
/**
|
|
1168
1202
|
* Adds white background to transparent icons only
|
|
1169
1203
|
*/
|
|
@@ -1206,23 +1240,34 @@ async function convertIconFormat(inputPath, appName) {
|
|
|
1206
1240
|
const iconName = appName.toLowerCase();
|
|
1207
1241
|
// Generate platform-specific format
|
|
1208
1242
|
if (IS_WIN) {
|
|
1243
|
+
// Support multiple sizes for better Windows compatibility
|
|
1209
1244
|
await icongen(processedInputPath, platformOutputDir, {
|
|
1210
1245
|
report: false,
|
|
1211
|
-
ico: {
|
|
1246
|
+
ico: {
|
|
1247
|
+
name: `${iconName}_256`,
|
|
1248
|
+
sizes: PLATFORM_CONFIG.win.sizes,
|
|
1249
|
+
},
|
|
1212
1250
|
});
|
|
1213
|
-
return path.join(platformOutputDir, `${iconName}_256.
|
|
1251
|
+
return path.join(platformOutputDir, `${iconName}_256${PLATFORM_CONFIG.win.format}`);
|
|
1214
1252
|
}
|
|
1215
1253
|
if (IS_LINUX) {
|
|
1216
|
-
const outputPath = path.join(platformOutputDir, `${iconName}
|
|
1217
|
-
|
|
1254
|
+
const outputPath = path.join(platformOutputDir, `${iconName}_${PLATFORM_CONFIG.linux.size}${PLATFORM_CONFIG.linux.format}`);
|
|
1255
|
+
// Ensure we convert to proper PNG format with correct size
|
|
1256
|
+
await sharp(processedInputPath)
|
|
1257
|
+
.resize(PLATFORM_CONFIG.linux.size, PLATFORM_CONFIG.linux.size, {
|
|
1258
|
+
fit: 'contain',
|
|
1259
|
+
background: ICON_CONFIG.transparentBackground,
|
|
1260
|
+
})
|
|
1261
|
+
.png()
|
|
1262
|
+
.toFile(outputPath);
|
|
1218
1263
|
return outputPath;
|
|
1219
1264
|
}
|
|
1220
1265
|
// macOS
|
|
1221
1266
|
await icongen(processedInputPath, platformOutputDir, {
|
|
1222
1267
|
report: false,
|
|
1223
|
-
icns: { name: iconName, sizes:
|
|
1268
|
+
icns: { name: iconName, sizes: PLATFORM_CONFIG.macos.sizes },
|
|
1224
1269
|
});
|
|
1225
|
-
const outputPath = path.join(platformOutputDir, `${iconName}.
|
|
1270
|
+
const outputPath = path.join(platformOutputDir, `${iconName}${PLATFORM_CONFIG.macos.format}`);
|
|
1226
1271
|
return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
|
|
1227
1272
|
}
|
|
1228
1273
|
catch (error) {
|
|
@@ -1230,105 +1275,113 @@ async function convertIconFormat(inputPath, appName) {
|
|
|
1230
1275
|
return null;
|
|
1231
1276
|
}
|
|
1232
1277
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
const finalIconPath = path.join(npmDirectory, `src-tauri/png/${options.name.toLowerCase()}_256.ico`);
|
|
1252
|
-
await fsExtra.ensureDir(path.dirname(finalIconPath));
|
|
1253
|
-
await fsExtra.copy(convertedPath, finalIconPath);
|
|
1254
|
-
return finalIconPath;
|
|
1255
|
-
}
|
|
1256
|
-
return convertedPath;
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
return downloadedPath;
|
|
1260
|
-
}
|
|
1261
|
-
return path.resolve(options.icon);
|
|
1262
|
-
}
|
|
1263
|
-
// Try to get favicon from website if URL is provided
|
|
1264
|
-
if (url && url.startsWith('http') && options.name) {
|
|
1265
|
-
const faviconPath = await tryGetFavicon(url, options.name);
|
|
1266
|
-
if (faviconPath)
|
|
1267
|
-
return faviconPath;
|
|
1278
|
+
/**
|
|
1279
|
+
* Processes downloaded or local icon for platform-specific format
|
|
1280
|
+
*/
|
|
1281
|
+
async function processIcon(iconPath, appName) {
|
|
1282
|
+
if (!iconPath || !appName)
|
|
1283
|
+
return iconPath;
|
|
1284
|
+
// Check if already in correct platform format
|
|
1285
|
+
const ext = path.extname(iconPath).toLowerCase();
|
|
1286
|
+
const isCorrectFormat = (IS_WIN && ext === '.ico') ||
|
|
1287
|
+
(IS_LINUX && ext === '.png') ||
|
|
1288
|
+
(!IS_WIN && !IS_LINUX && ext === '.icns');
|
|
1289
|
+
if (isCorrectFormat) {
|
|
1290
|
+
return await copyWindowsIconIfNeeded(iconPath, appName);
|
|
1291
|
+
}
|
|
1292
|
+
// Convert to platform format
|
|
1293
|
+
const convertedPath = await convertIconFormat(iconPath, appName);
|
|
1294
|
+
if (convertedPath) {
|
|
1295
|
+
return await copyWindowsIconIfNeeded(convertedPath, appName);
|
|
1268
1296
|
}
|
|
1297
|
+
return iconPath;
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Gets default icon with platform-specific fallback logic
|
|
1301
|
+
*/
|
|
1302
|
+
async function getDefaultIcon() {
|
|
1269
1303
|
logger.info('✼ No icon provided, using default icon.');
|
|
1270
|
-
// For Windows, ensure we have proper fallback handling
|
|
1271
1304
|
if (IS_WIN) {
|
|
1272
|
-
const defaultIcoPath =
|
|
1305
|
+
const defaultIcoPath = generateIconPath('icon', true);
|
|
1273
1306
|
const defaultPngPath = path.join(npmDirectory, 'src-tauri/png/icon_512.png');
|
|
1274
|
-
//
|
|
1307
|
+
// Try default ico first
|
|
1275
1308
|
if (await fsExtra.pathExists(defaultIcoPath)) {
|
|
1276
1309
|
return defaultIcoPath;
|
|
1277
1310
|
}
|
|
1278
|
-
//
|
|
1311
|
+
// Convert from png if ico doesn't exist
|
|
1279
1312
|
if (await fsExtra.pathExists(defaultPngPath)) {
|
|
1280
1313
|
logger.info('✼ Default ico not found, converting from png...');
|
|
1281
1314
|
try {
|
|
1282
1315
|
const convertedPath = await convertIconFormat(defaultPngPath, 'icon');
|
|
1283
1316
|
if (convertedPath && (await fsExtra.pathExists(convertedPath))) {
|
|
1284
|
-
|
|
1285
|
-
const finalIconPath = path.join(npmDirectory, 'src-tauri/png/icon_256.ico');
|
|
1286
|
-
await fsExtra.ensureDir(path.dirname(finalIconPath));
|
|
1287
|
-
await fsExtra.copy(convertedPath, finalIconPath);
|
|
1288
|
-
return finalIconPath;
|
|
1317
|
+
return await copyWindowsIconIfNeeded(convertedPath, 'icon');
|
|
1289
1318
|
}
|
|
1290
1319
|
}
|
|
1291
1320
|
catch (error) {
|
|
1292
|
-
logger.warn(`Failed to convert default png to ico: ${error.message}`);
|
|
1321
|
+
logger.warn(`Failed to convert default png to ico: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1293
1322
|
}
|
|
1294
1323
|
}
|
|
1295
|
-
//
|
|
1324
|
+
// Fallback to png or empty
|
|
1296
1325
|
if (await fsExtra.pathExists(defaultPngPath)) {
|
|
1297
1326
|
logger.warn('✼ Using png as fallback for Windows (may cause issues).');
|
|
1298
1327
|
return defaultPngPath;
|
|
1299
1328
|
}
|
|
1300
|
-
// If nothing exists, return empty string to let merge.ts handle default icon
|
|
1301
1329
|
logger.warn('✼ No default icon found, will use pake default.');
|
|
1302
1330
|
return '';
|
|
1303
1331
|
}
|
|
1332
|
+
// Linux and macOS defaults
|
|
1304
1333
|
const iconPath = IS_LINUX
|
|
1305
1334
|
? 'src-tauri/png/icon_512.png'
|
|
1306
1335
|
: 'src-tauri/icons/icon.icns';
|
|
1307
1336
|
return path.join(npmDirectory, iconPath);
|
|
1308
1337
|
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Main icon handling function with simplified logic flow
|
|
1340
|
+
*/
|
|
1341
|
+
async function handleIcon(options, url) {
|
|
1342
|
+
// Handle custom icon (local file or remote URL)
|
|
1343
|
+
if (options.icon) {
|
|
1344
|
+
if (options.icon.startsWith('http')) {
|
|
1345
|
+
const downloadedPath = await downloadIcon(options.icon);
|
|
1346
|
+
if (downloadedPath) {
|
|
1347
|
+
const result = await processIcon(downloadedPath, options.name || '');
|
|
1348
|
+
if (result)
|
|
1349
|
+
return result;
|
|
1350
|
+
}
|
|
1351
|
+
return '';
|
|
1352
|
+
}
|
|
1353
|
+
// Local file path
|
|
1354
|
+
const resolvedPath = path.resolve(options.icon);
|
|
1355
|
+
const result = await processIcon(resolvedPath, options.name || '');
|
|
1356
|
+
return result || resolvedPath;
|
|
1357
|
+
}
|
|
1358
|
+
// Try favicon from website
|
|
1359
|
+
if (url && options.name) {
|
|
1360
|
+
const faviconPath = await tryGetFavicon(url, options.name);
|
|
1361
|
+
if (faviconPath)
|
|
1362
|
+
return faviconPath;
|
|
1363
|
+
}
|
|
1364
|
+
// Use default icon
|
|
1365
|
+
return await getDefaultIcon();
|
|
1366
|
+
}
|
|
1309
1367
|
/**
|
|
1310
1368
|
* Generates icon service URLs for a domain
|
|
1311
1369
|
*/
|
|
1312
1370
|
function generateIconServiceUrls(domain) {
|
|
1313
|
-
const logoDevUrls =
|
|
1371
|
+
const logoDevUrls = API_KEYS.logoDev
|
|
1314
1372
|
.sort(() => Math.random() - 0.5)
|
|
1315
1373
|
.map((token) => `https://img.logo.dev/${domain}?token=${token}&format=png&size=256`);
|
|
1316
|
-
const brandfetchUrls =
|
|
1374
|
+
const brandfetchUrls = API_KEYS.brandfetch
|
|
1317
1375
|
.sort(() => Math.random() - 0.5)
|
|
1318
1376
|
.map((key) => `https://cdn.brandfetch.io/${domain}/w/400/h/400?c=${key}`);
|
|
1319
1377
|
return [
|
|
1320
1378
|
...logoDevUrls,
|
|
1321
1379
|
...brandfetchUrls,
|
|
1322
1380
|
`https://logo.clearbit.com/${domain}?size=256`,
|
|
1323
|
-
`https://logo.uplead.com/${domain}`,
|
|
1324
1381
|
`https://www.google.com/s2/favicons?domain=${domain}&sz=256`,
|
|
1325
1382
|
`https://favicon.is/${domain}`,
|
|
1326
|
-
`https://icons.duckduckgo.com/ip3/${domain}.ico`,
|
|
1327
|
-
`https://icon.horse/icon/${domain}`,
|
|
1328
1383
|
`https://${domain}/favicon.ico`,
|
|
1329
1384
|
`https://www.${domain}/favicon.ico`,
|
|
1330
|
-
`https://${domain}/apple-touch-icon.png`,
|
|
1331
|
-
`https://${domain}/apple-touch-icon-precomposed.png`,
|
|
1332
1385
|
];
|
|
1333
1386
|
}
|
|
1334
1387
|
/**
|
|
@@ -1339,9 +1392,10 @@ async function tryGetFavicon(url, appName) {
|
|
|
1339
1392
|
const domain = new URL(url).hostname;
|
|
1340
1393
|
const spinner = getSpinner(`Fetching icon from ${domain}...`);
|
|
1341
1394
|
const serviceUrls = generateIconServiceUrls(domain);
|
|
1342
|
-
// Use shorter timeout for CI environments
|
|
1343
1395
|
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
1344
|
-
const downloadTimeout = isCI
|
|
1396
|
+
const downloadTimeout = isCI
|
|
1397
|
+
? ICON_CONFIG.downloadTimeout.ci
|
|
1398
|
+
: ICON_CONFIG.downloadTimeout.default;
|
|
1345
1399
|
for (const serviceUrl of serviceUrls) {
|
|
1346
1400
|
try {
|
|
1347
1401
|
const faviconPath = await downloadIcon(serviceUrl, false, downloadTimeout);
|
|
@@ -1349,22 +1403,20 @@ async function tryGetFavicon(url, appName) {
|
|
|
1349
1403
|
continue;
|
|
1350
1404
|
const convertedPath = await convertIconFormat(faviconPath, appName);
|
|
1351
1405
|
if (convertedPath) {
|
|
1352
|
-
|
|
1353
|
-
if (IS_WIN && convertedPath.endsWith('.ico')) {
|
|
1354
|
-
const finalIconPath = path.join(npmDirectory, `src-tauri/png/${appName.toLowerCase()}_256.ico`);
|
|
1355
|
-
await fsExtra.ensureDir(path.dirname(finalIconPath));
|
|
1356
|
-
await fsExtra.copy(convertedPath, finalIconPath);
|
|
1357
|
-
spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
|
|
1358
|
-
return finalIconPath;
|
|
1359
|
-
}
|
|
1406
|
+
const finalPath = await copyWindowsIconIfNeeded(convertedPath, appName);
|
|
1360
1407
|
spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
|
|
1361
|
-
return
|
|
1408
|
+
return finalPath;
|
|
1362
1409
|
}
|
|
1363
1410
|
}
|
|
1364
1411
|
catch (error) {
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1412
|
+
logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
|
|
1413
|
+
// Platform-specific error handling
|
|
1414
|
+
if ((IS_LINUX || IS_WIN) && error.code === 'ENOTFOUND') {
|
|
1415
|
+
logger.debug(`DNS resolution failed for ${serviceUrl}, trying next service...`);
|
|
1416
|
+
}
|
|
1417
|
+
// Windows-specific icon conversion errors
|
|
1418
|
+
if (IS_WIN && error.message.includes('icongen')) {
|
|
1419
|
+
logger.debug(`Windows icon conversion failed for ${serviceUrl}, trying next service...`);
|
|
1368
1420
|
}
|
|
1369
1421
|
continue;
|
|
1370
1422
|
}
|
|
@@ -1384,7 +1436,7 @@ async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
|
|
|
1384
1436
|
try {
|
|
1385
1437
|
const response = await axios.get(iconUrl, {
|
|
1386
1438
|
responseType: 'arraybuffer',
|
|
1387
|
-
timeout: customTimeout ||
|
|
1439
|
+
timeout: customTimeout || 10000,
|
|
1388
1440
|
});
|
|
1389
1441
|
const iconData = response.data;
|
|
1390
1442
|
if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize)
|
|
@@ -1408,15 +1460,11 @@ async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
|
|
|
1408
1460
|
*/
|
|
1409
1461
|
async function saveIconFile(iconData, extension) {
|
|
1410
1462
|
const buffer = Buffer.from(iconData);
|
|
1411
|
-
if (IS_LINUX) {
|
|
1412
|
-
const iconPath = 'png/linux_temp.png';
|
|
1413
|
-
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, buffer);
|
|
1414
|
-
return iconPath;
|
|
1415
|
-
}
|
|
1416
1463
|
const { path: tempPath } = await dir();
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1464
|
+
// Always save with the original extension first
|
|
1465
|
+
const originalIconPath = path.join(tempPath, `icon.${extension}`);
|
|
1466
|
+
await fsExtra.outputFile(originalIconPath, buffer);
|
|
1467
|
+
return originalIconPath;
|
|
1420
1468
|
}
|
|
1421
1469
|
|
|
1422
1470
|
// Extracts the domain from a given URL.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pake-cli",
|
|
3
|
-
"version": "3.3.
|
|
4
|
-
"description": "🤱🏻 Turn any webpage into a desktop app with
|
|
3
|
+
"version": "3.3.2",
|
|
4
|
+
"description": "🤱🏻 Turn any webpage into a desktop app with one command. 🤱🏻 一键打包网页生成轻量桌面应用。",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
7
7
|
},
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"license": "MIT",
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@tauri-apps/api": "^2.8.0",
|
|
54
|
-
"@tauri-apps/cli": "^2.8.
|
|
54
|
+
"@tauri-apps/cli": "^2.8.4",
|
|
55
55
|
"axios": "^1.11.0",
|
|
56
56
|
"chalk": "^5.6.0",
|
|
57
57
|
"commander": "^12.1.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"ora": "^8.2.0",
|
|
64
64
|
"prompts": "^2.4.2",
|
|
65
65
|
"psl": "^1.15.0",
|
|
66
|
-
"sharp": "^0.33.
|
|
66
|
+
"sharp": "^0.33.5",
|
|
67
67
|
"tmp-promise": "^3.0.3",
|
|
68
68
|
"update-notifier": "^7.3.1"
|
|
69
69
|
},
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@rollup/plugin-replace": "^6.0.2",
|
|
75
75
|
"@rollup/plugin-terser": "^0.4.4",
|
|
76
76
|
"@types/fs-extra": "^11.0.4",
|
|
77
|
-
"@types/node": "^20.19.
|
|
77
|
+
"@types/node": "^20.19.13",
|
|
78
78
|
"@types/page-icon": "^0.3.6",
|
|
79
79
|
"@types/prompts": "^2.4.9",
|
|
80
80
|
"@types/tmp": "^0.2.6",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"app-root-path": "^3.1.0",
|
|
83
83
|
"cross-env": "^7.0.3",
|
|
84
84
|
"prettier": "^3.6.2",
|
|
85
|
-
"rollup": "^4.
|
|
85
|
+
"rollup": "^4.50.0",
|
|
86
86
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
87
87
|
"tslib": "^2.8.1",
|
|
88
88
|
"typescript": "^5.9.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"productName": "
|
|
3
|
-
"identifier": "com.pake.
|
|
2
|
+
"productName": "GitHubAutoIconTest",
|
|
3
|
+
"identifier": "com.pake.3097fc",
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"app": {
|
|
6
6
|
"withGlobalTauri": true,
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
},
|
|
14
14
|
"bundle": {
|
|
15
15
|
"icon": [
|
|
16
|
-
"icons/
|
|
16
|
+
"icons/githubautoicontest.icns"
|
|
17
17
|
],
|
|
18
18
|
"active": true,
|
|
19
19
|
"targets": [
|
|
20
20
|
"app"
|
|
21
21
|
],
|
|
22
22
|
"resources": [
|
|
23
|
-
"icons/
|
|
23
|
+
"icons/githubautoicontest.icns"
|
|
24
24
|
]
|
|
25
25
|
}
|
|
26
26
|
}
|