Skip to content

Commit 3d4c018

Browse files
committed
✨ support multiple-instances
1 parent 7ee7924 commit 3d4c018

File tree

10 files changed

+61
-18
lines changed

10 files changed

+61
-18
lines changed

bin/cli.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ program
160160
.default(DEFAULT.keepBinary)
161161
.hideHelp(),
162162
)
163+
.addOption(
164+
new Option('--multi-instance', 'Allow multiple app instances')
165+
.default(DEFAULT.multiInstance)
166+
.hideHelp(),
167+
)
163168
.addOption(
164169
new Option('--installer-language <string>', 'Installer language')
165170
.default(DEFAULT.installerLanguage)

bin/defaults.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const DEFAULT_PAKE_OPTIONS: PakeCliOptions = {
2727
wasm: false,
2828
enableDragDrop: false,
2929
keepBinary: false,
30+
multiInstance: false,
3031
};
3132

3233
// Just for cli development

bin/helpers/merge.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export async function mergeConfig(
6363
title,
6464
wasm,
6565
enableDragDrop,
66+
multiInstance,
6667
} = options;
6768

6869
const { platform } = process;
@@ -325,6 +326,7 @@ StartupNotify=true
325326
await fsExtra.writeFile(injectFilePath, '');
326327
}
327328
tauriConf.pake.proxy_url = proxyUrl || '';
329+
tauriConf.pake.multi_instance = multiInstance;
328330

329331
// Configure WASM support with required HTTP headers
330332
if (wasm) {

bin/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ export interface PakeCliOptions {
8787

8888
// Keep raw binary file alongside installer, default false
8989
keepBinary: boolean;
90+
91+
// Allow multiple instances, default false (single instance)
92+
multiInstance: boolean;
9093
}
9194

9295
export interface PakeAppOptions extends PakeCliOptions {

dist/cli.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -343,26 +343,21 @@ function generateLinuxPackageName(name) {
343343
.replace(/-+/g, '-');
344344
}
345345
function generateIdentifierSafeName(name) {
346-
// Support Chinese characters (CJK Unified Ideographs: U+4E00-U+9FFF)
347-
// and other common Unicode letter categories
348-
const cleaned = name
349-
.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '')
350-
.toLowerCase();
351-
// If result is empty after cleaning, generate a fallback based on original name
346+
const cleaned = name.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '').toLowerCase();
352347
if (cleaned === '') {
353-
// Convert to ASCII-safe representation using character codes
354348
const fallback = Array.from(name)
355-
.map(char => {
349+
.map((char) => {
356350
const code = char.charCodeAt(0);
357-
// Keep ASCII alphanumeric, convert others to their hex codes
358-
if ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
351+
if ((code >= 48 && code <= 57) ||
352+
(code >= 65 && code <= 90) ||
353+
(code >= 97 && code <= 122)) {
359354
return char.toLowerCase();
360355
}
361356
return code.toString(16);
362357
})
363358
.join('')
364-
.slice(0, 50); // Limit length to avoid extremely long names
365-
return fallback || 'pake-app'; // Ultimate fallback
359+
.slice(0, 50);
360+
return fallback || 'pake-app';
366361
}
367362
return cleaned;
368363
}
@@ -387,7 +382,7 @@ async function mergeConfig(url, options, tauriConf) {
387382
await fsExtra.copy(sourcePath, destPath);
388383
}
389384
}));
390-
const { width, height, fullscreen, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, } = options;
385+
const { width, height, fullscreen, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, } = options;
391386
const { platform } = process;
392387
const platformHideOnClose = hideOnClose ?? platform === 'darwin';
393388
const tauriConfWindowOptions = {
@@ -602,6 +597,7 @@ StartupNotify=true
602597
await fsExtra.writeFile(injectFilePath, '');
603598
}
604599
tauriConf.pake.proxy_url = proxyUrl || '';
600+
tauriConf.pake.multi_instance = multiInstance;
605601
// Configure WASM support with required HTTP headers
606602
if (wasm) {
607603
tauriConf.app.security = {
@@ -1181,6 +1177,7 @@ const DEFAULT_PAKE_OPTIONS = {
11811177
wasm: false,
11821178
enableDragDrop: false,
11831179
keepBinary: false,
1180+
multiInstance: false,
11841181
};
11851182

11861183
async function checkUpdateTips() {
@@ -1704,6 +1701,9 @@ program
17041701
.addOption(new Option('--keep-binary', 'Keep raw binary file alongside installer')
17051702
.default(DEFAULT_PAKE_OPTIONS.keepBinary)
17061703
.hideHelp())
1704+
.addOption(new Option('--multi-instance', 'Allow multiple app instances')
1705+
.default(DEFAULT_PAKE_OPTIONS.multiInstance)
1706+
.hideHelp())
17071707
.addOption(new Option('--installer-language <string>', 'Installer language')
17081708
.default(DEFAULT_PAKE_OPTIONS.installerLanguage)
17091709
.hideHelp())

docs/cli-usage.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,17 @@ pake https://github.com --name GitHub --keep-binary
350350

351351
**Output**: Creates both installer and standalone executable (`AppName-binary` on Unix, `AppName.exe` on Windows).
352352

353+
#### [multi-instance]
354+
355+
Allow the packaged app to run more than one instance at the same time. Default is `false`, which means launching a second instance simply focuses the existing window. Enable this when you need to open several windows of the same app simultaneously.
356+
357+
```shell
358+
--multi-instance
359+
360+
# Example: Allow multiple chat windows
361+
pake https://chat.example.com --name ChatApp --multi-instance
362+
```
363+
353364
#### [installer-language]
354365

355366
Set the Windows Installer language. Options include `zh-CN`, `ja-JP`, More at [Tauri Document](https://tauri.app/distribute/windows-installer/#internationalization). Default is `en-US`.

docs/cli-usage_CN.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,17 @@ pake https://github.com --name GitHub --keep-binary
349349

350350
**输出结果**:同时创建安装包和独立可执行文件(Unix 系统为 `AppName-binary`,Windows 为 `AppName.exe`)。
351351

352+
#### [multi-instance]
353+
354+
允许打包后的应用同时运行多个实例。默认为 `false`,此时再次启动只会聚焦已有窗口。启用该选项后,可以同时打开同一个应用的多个窗口。
355+
356+
```shell
357+
--multi-instance
358+
359+
# 示例:允许聊天应用同时开多个窗口
360+
pake https://chat.example.com --name ChatApp --multi-instance
361+
```
362+
352363
#### [installer-language]
353364

354365
设置 Windows 安装包语言。支持 `zh-CN``ja-JP`,更多在 [Tauri 文档](https://tauri.app/distribute/windows-installer/#internationalization)。默认为 `en-US`

src-tauri/pake.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@
3030
},
3131
"system_tray_path": "icons/icon.png",
3232
"inject": [],
33-
"proxy_url": ""
33+
"proxy_url": "",
34+
"multi_instance": false
3435
}

src-tauri/src/app/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub struct PakeConfig {
5959
pub system_tray: FunctionON,
6060
pub system_tray_path: String,
6161
pub proxy_url: String,
62+
#[serde(default)]
63+
pub multi_instance: bool,
6264
}
6365

6466
impl PakeConfig {

src-tauri/src/lib.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub fn run_app() {
2424
let hide_on_close = pake_config.windows[0].hide_on_close;
2525
let activation_shortcut = pake_config.windows[0].activation_shortcut.clone();
2626
let init_fullscreen = pake_config.windows[0].fullscreen;
27+
let multi_instance = pake_config.multi_instance;
2728

2829
let window_state_plugin = WindowStatePlugin::default()
2930
.with_state_flags(if init_fullscreen {
@@ -35,19 +36,25 @@ pub fn run_app() {
3536
.build();
3637

3738
#[allow(deprecated)]
38-
tauri_app
39+
let mut app_builder = tauri_app
3940
.plugin(window_state_plugin)
4041
.plugin(tauri_plugin_oauth::init())
4142
.plugin(tauri_plugin_http::init())
4243
.plugin(tauri_plugin_shell::init())
43-
.plugin(tauri_plugin_notification::init())
44-
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
44+
.plugin(tauri_plugin_notification::init());
45+
46+
// Only add single instance plugin if multiple instances are not allowed
47+
if !multi_instance {
48+
app_builder = app_builder.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
4549
if let Some(window) = app.get_webview_window("pake") {
4650
let _ = window.unminimize();
4751
let _ = window.show();
4852
let _ = window.set_focus();
4953
}
50-
}))
54+
}));
55+
}
56+
57+
app_builder
5158
.invoke_handler(tauri::generate_handler![
5259
download_file,
5360
download_file_by_binary,

0 commit comments

Comments
 (0)