✨ support multiple-instances
This commit is contained in:
5
bin/cli.ts
vendored
5
bin/cli.ts
vendored
@@ -160,6 +160,11 @@ program
|
|||||||
.default(DEFAULT.keepBinary)
|
.default(DEFAULT.keepBinary)
|
||||||
.hideHelp(),
|
.hideHelp(),
|
||||||
)
|
)
|
||||||
|
.addOption(
|
||||||
|
new Option('--multi-instance', 'Allow multiple app instances')
|
||||||
|
.default(DEFAULT.multiInstance)
|
||||||
|
.hideHelp(),
|
||||||
|
)
|
||||||
.addOption(
|
.addOption(
|
||||||
new Option('--installer-language <string>', 'Installer language')
|
new Option('--installer-language <string>', 'Installer language')
|
||||||
.default(DEFAULT.installerLanguage)
|
.default(DEFAULT.installerLanguage)
|
||||||
|
|||||||
1
bin/defaults.ts
vendored
1
bin/defaults.ts
vendored
@@ -27,6 +27,7 @@ export const DEFAULT_PAKE_OPTIONS: PakeCliOptions = {
|
|||||||
wasm: false,
|
wasm: false,
|
||||||
enableDragDrop: false,
|
enableDragDrop: false,
|
||||||
keepBinary: false,
|
keepBinary: false,
|
||||||
|
multiInstance: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Just for cli development
|
// Just for cli development
|
||||||
|
|||||||
2
bin/helpers/merge.ts
vendored
2
bin/helpers/merge.ts
vendored
@@ -63,6 +63,7 @@ export async function mergeConfig(
|
|||||||
title,
|
title,
|
||||||
wasm,
|
wasm,
|
||||||
enableDragDrop,
|
enableDragDrop,
|
||||||
|
multiInstance,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const { platform } = process;
|
const { platform } = process;
|
||||||
@@ -325,6 +326,7 @@ StartupNotify=true
|
|||||||
await fsExtra.writeFile(injectFilePath, '');
|
await fsExtra.writeFile(injectFilePath, '');
|
||||||
}
|
}
|
||||||
tauriConf.pake.proxy_url = proxyUrl || '';
|
tauriConf.pake.proxy_url = proxyUrl || '';
|
||||||
|
tauriConf.pake.multi_instance = multiInstance;
|
||||||
|
|
||||||
// Configure WASM support with required HTTP headers
|
// Configure WASM support with required HTTP headers
|
||||||
if (wasm) {
|
if (wasm) {
|
||||||
|
|||||||
3
bin/types.ts
vendored
3
bin/types.ts
vendored
@@ -87,6 +87,9 @@ export interface PakeCliOptions {
|
|||||||
|
|
||||||
// Keep raw binary file alongside installer, default false
|
// Keep raw binary file alongside installer, default false
|
||||||
keepBinary: boolean;
|
keepBinary: boolean;
|
||||||
|
|
||||||
|
// Allow multiple instances, default false (single instance)
|
||||||
|
multiInstance: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PakeAppOptions extends PakeCliOptions {
|
export interface PakeAppOptions extends PakeCliOptions {
|
||||||
|
|||||||
26
dist/cli.js
vendored
26
dist/cli.js
vendored
@@ -343,26 +343,21 @@ function generateLinuxPackageName(name) {
|
|||||||
.replace(/-+/g, '-');
|
.replace(/-+/g, '-');
|
||||||
}
|
}
|
||||||
function generateIdentifierSafeName(name) {
|
function generateIdentifierSafeName(name) {
|
||||||
// Support Chinese characters (CJK Unified Ideographs: U+4E00-U+9FFF)
|
const cleaned = name.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '').toLowerCase();
|
||||||
// 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
|
|
||||||
if (cleaned === '') {
|
if (cleaned === '') {
|
||||||
// Convert to ASCII-safe representation using character codes
|
|
||||||
const fallback = Array.from(name)
|
const fallback = Array.from(name)
|
||||||
.map(char => {
|
.map((char) => {
|
||||||
const code = char.charCodeAt(0);
|
const code = char.charCodeAt(0);
|
||||||
// Keep ASCII alphanumeric, convert others to their hex codes
|
if ((code >= 48 && code <= 57) ||
|
||||||
if ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
|
(code >= 65 && code <= 90) ||
|
||||||
|
(code >= 97 && code <= 122)) {
|
||||||
return char.toLowerCase();
|
return char.toLowerCase();
|
||||||
}
|
}
|
||||||
return code.toString(16);
|
return code.toString(16);
|
||||||
})
|
})
|
||||||
.join('')
|
.join('')
|
||||||
.slice(0, 50); // Limit length to avoid extremely long names
|
.slice(0, 50);
|
||||||
return fallback || 'pake-app'; // Ultimate fallback
|
return fallback || 'pake-app';
|
||||||
}
|
}
|
||||||
return cleaned;
|
return cleaned;
|
||||||
}
|
}
|
||||||
@@ -387,7 +382,7 @@ async function mergeConfig(url, options, tauriConf) {
|
|||||||
await fsExtra.copy(sourcePath, destPath);
|
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 { platform } = process;
|
||||||
const platformHideOnClose = hideOnClose ?? platform === 'darwin';
|
const platformHideOnClose = hideOnClose ?? platform === 'darwin';
|
||||||
const tauriConfWindowOptions = {
|
const tauriConfWindowOptions = {
|
||||||
@@ -602,6 +597,7 @@ StartupNotify=true
|
|||||||
await fsExtra.writeFile(injectFilePath, '');
|
await fsExtra.writeFile(injectFilePath, '');
|
||||||
}
|
}
|
||||||
tauriConf.pake.proxy_url = proxyUrl || '';
|
tauriConf.pake.proxy_url = proxyUrl || '';
|
||||||
|
tauriConf.pake.multi_instance = multiInstance;
|
||||||
// Configure WASM support with required HTTP headers
|
// Configure WASM support with required HTTP headers
|
||||||
if (wasm) {
|
if (wasm) {
|
||||||
tauriConf.app.security = {
|
tauriConf.app.security = {
|
||||||
@@ -1181,6 +1177,7 @@ const DEFAULT_PAKE_OPTIONS = {
|
|||||||
wasm: false,
|
wasm: false,
|
||||||
enableDragDrop: false,
|
enableDragDrop: false,
|
||||||
keepBinary: false,
|
keepBinary: false,
|
||||||
|
multiInstance: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function checkUpdateTips() {
|
async function checkUpdateTips() {
|
||||||
@@ -1704,6 +1701,9 @@ program
|
|||||||
.addOption(new Option('--keep-binary', 'Keep raw binary file alongside installer')
|
.addOption(new Option('--keep-binary', 'Keep raw binary file alongside installer')
|
||||||
.default(DEFAULT_PAKE_OPTIONS.keepBinary)
|
.default(DEFAULT_PAKE_OPTIONS.keepBinary)
|
||||||
.hideHelp())
|
.hideHelp())
|
||||||
|
.addOption(new Option('--multi-instance', 'Allow multiple app instances')
|
||||||
|
.default(DEFAULT_PAKE_OPTIONS.multiInstance)
|
||||||
|
.hideHelp())
|
||||||
.addOption(new Option('--installer-language <string>', 'Installer language')
|
.addOption(new Option('--installer-language <string>', 'Installer language')
|
||||||
.default(DEFAULT_PAKE_OPTIONS.installerLanguage)
|
.default(DEFAULT_PAKE_OPTIONS.installerLanguage)
|
||||||
.hideHelp())
|
.hideHelp())
|
||||||
|
|||||||
@@ -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).
|
**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]
|
#### [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`.
|
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`.
|
||||||
|
|||||||
@@ -349,6 +349,17 @@ pake https://github.com --name GitHub --keep-binary
|
|||||||
|
|
||||||
**输出结果**:同时创建安装包和独立可执行文件(Unix 系统为 `AppName-binary`,Windows 为 `AppName.exe`)。
|
**输出结果**:同时创建安装包和独立可执行文件(Unix 系统为 `AppName-binary`,Windows 为 `AppName.exe`)。
|
||||||
|
|
||||||
|
#### [multi-instance]
|
||||||
|
|
||||||
|
允许打包后的应用同时运行多个实例。默认为 `false`,此时再次启动只会聚焦已有窗口。启用该选项后,可以同时打开同一个应用的多个窗口。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
--multi-instance
|
||||||
|
|
||||||
|
# 示例:允许聊天应用同时开多个窗口
|
||||||
|
pake https://chat.example.com --name ChatApp --multi-instance
|
||||||
|
```
|
||||||
|
|
||||||
#### [installer-language]
|
#### [installer-language]
|
||||||
|
|
||||||
设置 Windows 安装包语言。支持 `zh-CN`、`ja-JP`,更多在 [Tauri 文档](https://tauri.app/distribute/windows-installer/#internationalization)。默认为 `en-US`。
|
设置 Windows 安装包语言。支持 `zh-CN`、`ja-JP`,更多在 [Tauri 文档](https://tauri.app/distribute/windows-installer/#internationalization)。默认为 `en-US`。
|
||||||
|
|||||||
@@ -30,5 +30,6 @@
|
|||||||
},
|
},
|
||||||
"system_tray_path": "icons/icon.png",
|
"system_tray_path": "icons/icon.png",
|
||||||
"inject": [],
|
"inject": [],
|
||||||
"proxy_url": ""
|
"proxy_url": "",
|
||||||
|
"multi_instance": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ pub struct PakeConfig {
|
|||||||
pub system_tray: FunctionON,
|
pub system_tray: FunctionON,
|
||||||
pub system_tray_path: String,
|
pub system_tray_path: String,
|
||||||
pub proxy_url: String,
|
pub proxy_url: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub multi_instance: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PakeConfig {
|
impl PakeConfig {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ pub fn run_app() {
|
|||||||
let hide_on_close = pake_config.windows[0].hide_on_close;
|
let hide_on_close = pake_config.windows[0].hide_on_close;
|
||||||
let activation_shortcut = pake_config.windows[0].activation_shortcut.clone();
|
let activation_shortcut = pake_config.windows[0].activation_shortcut.clone();
|
||||||
let init_fullscreen = pake_config.windows[0].fullscreen;
|
let init_fullscreen = pake_config.windows[0].fullscreen;
|
||||||
|
let multi_instance = pake_config.multi_instance;
|
||||||
|
|
||||||
let window_state_plugin = WindowStatePlugin::default()
|
let window_state_plugin = WindowStatePlugin::default()
|
||||||
.with_state_flags(if init_fullscreen {
|
.with_state_flags(if init_fullscreen {
|
||||||
@@ -35,19 +36,25 @@ pub fn run_app() {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
tauri_app
|
let mut app_builder = tauri_app
|
||||||
.plugin(window_state_plugin)
|
.plugin(window_state_plugin)
|
||||||
.plugin(tauri_plugin_oauth::init())
|
.plugin(tauri_plugin_oauth::init())
|
||||||
.plugin(tauri_plugin_http::init())
|
.plugin(tauri_plugin_http::init())
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_notification::init())
|
.plugin(tauri_plugin_notification::init());
|
||||||
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
|
||||||
|
// 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") {
|
if let Some(window) = app.get_webview_window("pake") {
|
||||||
let _ = window.unminimize();
|
let _ = window.unminimize();
|
||||||
let _ = window.show();
|
let _ = window.show();
|
||||||
let _ = window.set_focus();
|
let _ = window.set_focus();
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
app_builder
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
download_file,
|
download_file,
|
||||||
download_file_by_binary,
|
download_file_by_binary,
|
||||||
|
|||||||
Reference in New Issue
Block a user