support multiple-instances

This commit is contained in:
Tw93
2025-10-06 12:25:38 +08:00
parent 7ee7924eec
commit 3d4c018641
10 changed files with 61 additions and 18 deletions

5
bin/cli.ts vendored
View File

@@ -160,6 +160,11 @@ program
.default(DEFAULT.keepBinary)
.hideHelp(),
)
.addOption(
new Option('--multi-instance', 'Allow multiple app instances')
.default(DEFAULT.multiInstance)
.hideHelp(),
)
.addOption(
new Option('--installer-language <string>', 'Installer language')
.default(DEFAULT.installerLanguage)

1
bin/defaults.ts vendored
View File

@@ -27,6 +27,7 @@ export const DEFAULT_PAKE_OPTIONS: PakeCliOptions = {
wasm: false,
enableDragDrop: false,
keepBinary: false,
multiInstance: false,
};
// Just for cli development

View File

@@ -63,6 +63,7 @@ export async function mergeConfig(
title,
wasm,
enableDragDrop,
multiInstance,
} = options;
const { platform } = process;
@@ -325,6 +326,7 @@ StartupNotify=true
await fsExtra.writeFile(injectFilePath, '');
}
tauriConf.pake.proxy_url = proxyUrl || '';
tauriConf.pake.multi_instance = multiInstance;
// Configure WASM support with required HTTP headers
if (wasm) {

3
bin/types.ts vendored
View File

@@ -87,6 +87,9 @@ export interface PakeCliOptions {
// Keep raw binary file alongside installer, default false
keepBinary: boolean;
// Allow multiple instances, default false (single instance)
multiInstance: boolean;
}
export interface PakeAppOptions extends PakeCliOptions {

26
dist/cli.js vendored
View File

@@ -343,26 +343,21 @@ function generateLinuxPackageName(name) {
.replace(/-+/g, '-');
}
function generateIdentifierSafeName(name) {
// Support Chinese characters (CJK Unified Ideographs: U+4E00-U+9FFF)
// and other common Unicode letter categories
const cleaned = name
.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '')
.toLowerCase();
// If result is empty after cleaning, generate a fallback based on original name
const cleaned = name.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '').toLowerCase();
if (cleaned === '') {
// Convert to ASCII-safe representation using character codes
const fallback = Array.from(name)
.map(char => {
.map((char) => {
const code = char.charCodeAt(0);
// Keep ASCII alphanumeric, convert others to their hex codes
if ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
if ((code >= 48 && code <= 57) ||
(code >= 65 && code <= 90) ||
(code >= 97 && code <= 122)) {
return char.toLowerCase();
}
return code.toString(16);
})
.join('')
.slice(0, 50); // Limit length to avoid extremely long names
return fallback || 'pake-app'; // Ultimate fallback
.slice(0, 50);
return fallback || 'pake-app';
}
return cleaned;
}
@@ -387,7 +382,7 @@ async function mergeConfig(url, options, tauriConf) {
await fsExtra.copy(sourcePath, destPath);
}
}));
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;
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;
const { platform } = process;
const platformHideOnClose = hideOnClose ?? platform === 'darwin';
const tauriConfWindowOptions = {
@@ -602,6 +597,7 @@ StartupNotify=true
await fsExtra.writeFile(injectFilePath, '');
}
tauriConf.pake.proxy_url = proxyUrl || '';
tauriConf.pake.multi_instance = multiInstance;
// Configure WASM support with required HTTP headers
if (wasm) {
tauriConf.app.security = {
@@ -1181,6 +1177,7 @@ const DEFAULT_PAKE_OPTIONS = {
wasm: false,
enableDragDrop: false,
keepBinary: false,
multiInstance: false,
};
async function checkUpdateTips() {
@@ -1704,6 +1701,9 @@ program
.addOption(new Option('--keep-binary', 'Keep raw binary file alongside installer')
.default(DEFAULT_PAKE_OPTIONS.keepBinary)
.hideHelp())
.addOption(new Option('--multi-instance', 'Allow multiple app instances')
.default(DEFAULT_PAKE_OPTIONS.multiInstance)
.hideHelp())
.addOption(new Option('--installer-language <string>', 'Installer language')
.default(DEFAULT_PAKE_OPTIONS.installerLanguage)
.hideHelp())

View File

@@ -350,6 +350,17 @@ pake https://github.com --name GitHub --keep-binary
**Output**: Creates both installer and standalone executable (`AppName-binary` on Unix, `AppName.exe` on Windows).
#### [multi-instance]
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.
```shell
--multi-instance
# Example: Allow multiple chat windows
pake https://chat.example.com --name ChatApp --multi-instance
```
#### [installer-language]
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`.

View File

@@ -349,6 +349,17 @@ pake https://github.com --name GitHub --keep-binary
**输出结果**同时创建安装包和独立可执行文件Unix 系统为 `AppName-binary`Windows 为 `AppName.exe`)。
#### [multi-instance]
允许打包后的应用同时运行多个实例。默认为 `false`,此时再次启动只会聚焦已有窗口。启用该选项后,可以同时打开同一个应用的多个窗口。
```shell
--multi-instance
# 示例:允许聊天应用同时开多个窗口
pake https://chat.example.com --name ChatApp --multi-instance
```
#### [installer-language]
设置 Windows 安装包语言。支持 `zh-CN`、`ja-JP`,更多在 [Tauri 文档](https://tauri.app/distribute/windows-installer/#internationalization)。默认为 `en-US`。

View File

@@ -30,5 +30,6 @@
},
"system_tray_path": "icons/icon.png",
"inject": [],
"proxy_url": ""
"proxy_url": "",
"multi_instance": false
}

View File

@@ -59,6 +59,8 @@ pub struct PakeConfig {
pub system_tray: FunctionON,
pub system_tray_path: String,
pub proxy_url: String,
#[serde(default)]
pub multi_instance: bool,
}
impl PakeConfig {

View File

@@ -24,6 +24,7 @@ pub fn run_app() {
let hide_on_close = pake_config.windows[0].hide_on_close;
let activation_shortcut = pake_config.windows[0].activation_shortcut.clone();
let init_fullscreen = pake_config.windows[0].fullscreen;
let multi_instance = pake_config.multi_instance;
let window_state_plugin = WindowStatePlugin::default()
.with_state_flags(if init_fullscreen {
@@ -35,19 +36,25 @@ pub fn run_app() {
.build();
#[allow(deprecated)]
tauri_app
let mut app_builder = tauri_app
.plugin(window_state_plugin)
.plugin(tauri_plugin_oauth::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
.plugin(tauri_plugin_notification::init());
// Only add single instance plugin if multiple instances are not allowed
if !multi_instance {
app_builder = app_builder.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
if let Some(window) = app.get_webview_window("pake") {
let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
}
}))
}));
}
app_builder
.invoke_handler(tauri::generate_handler![
download_file,
download_file_by_binary,