English | 简体中文
Customize Pake apps with style modifications, JavaScript injection, and container communication.
Remove ads or customize appearance by modifying CSS.
Quick Process:
- Run
pnpm run devfor development - Use DevTools to find elements to modify
- Edit
src-tauri/src/inject/style.js:
const css = `
.ads-banner { display: none !important; }
.header { background: #1a1a1a !important; }
`;Add custom functionality like keyboard shortcuts.
Implementation:
- Edit
src-tauri/src/inject/event.js - Add event listeners:
document.addEventListener("keydown", (e) => {
if (e.ctrlKey && e.key === "k") {
// Custom action
}
});Pake automatically provides user-friendly download error notifications:
Features:
- Bilingual Support: Automatically detects browser language (Chinese/English)
- System Notifications: Uses native OS notifications when permission is granted
- Graceful Fallback: Falls back to console logging if notifications are unavailable
- Comprehensive Coverage: Handles all download types (HTTP, Data URI, Blob)
User Experience:
When a download fails, users will see a notification:
- English: "Download Error - Download failed: filename.pdf"
- Chinese: "下载错误 - 下载失败: filename.pdf"
Requesting Notification Permission:
To enable notifications, add this to your injected JavaScript:
// Request notification permission on app start
if (window.Notification && Notification.permission === "default") {
Notification.requestPermission();
}The download system automatically handles:
- Regular HTTP(S) downloads
- Data URI downloads (base64 encoded files)
- Blob URL downloads (dynamically generated files)
- Context menu initiated downloads
Send messages between web content and Pake container.
Web Side (JavaScript):
window.__TAURI__.invoke("handle_scroll", {
scrollY: window.scrollY,
scrollX: window.scrollX,
});Container Side (Rust):
#[tauri::command]
fn handle_scroll(scroll_y: f64, scroll_x: f64) {
println!("Scroll: {}, {}", scroll_x, scroll_y);
}Configure window properties in pake.json:
{
"windows": {
"width": 1200,
"height": 780,
"fullscreen": false,
"resizable": true
},
"hideTitleBar": true
}Package local HTML/CSS/JS files:
pake ./my-app/index.html --name my-static-app --use-local-fileRequirements: Pake CLI >= 3.0.0
By default, apps built with Pake do not request camera or microphone access. For sites that require these (for example, video conferencing or voice input), pass the relevant flags at build time:
pake https://chatgpt.com --name ChatGPT --microphone
pake https://meet.google.com --name GoogleMeet --camera --microphone--microphone— grants microphone access (com.apple.security.device.audio-input)--camera— grants camera access (com.apple.security.device.camera)
macOS will prompt the user for permission on first use. Only add these flags for sites that actually need them.
If you need separate apps for the same site, for example two Gmail accounts with different login state, build them with different app names:
pake https://gmail.com --name "Gmail Work"
pake https://gmail.com --name "Gmail Personal"Pake now generates a different app identifier for each URL + name pair, so these apps can be installed as separate desktop apps instead of resolving to the same app.
For advanced cases, Pake also supports a hidden --identifier option if you need to pin the bundle identifier explicitly:
pake https://gmail.com --name "Gmail Work" --identifier com.example.gmail.work--multi-instance is different. It only allows multiple processes for the same packaged app, it does not create separate app identities.
Understanding Pake's codebase structure will help you navigate and contribute effectively:
├── bin/ # CLI source code (TypeScript)
│ ├── builders/ # Platform-specific builders
│ ├── helpers/ # Utility functions
│ └── options/ # CLI option processing
├── docs/ # Project documentation
├── src-tauri/ # Tauri application core
│ ├── src/
│ │ ├── app/ # Core modules (window, tray, shortcuts)
│ │ ├── inject/ # Web page injection logic
│ │ └── lib.rs # Application entry point
│ ├── icons/ # macOS icons (.icns)
│ ├── png/ # Windows/Linux icons (.ico, .png)
│ ├── pake.json # App configuration
│ └── tauri.*.conf.json # Platform-specific configs
├── scripts/ # Build and utility scripts
└── tests/ # Test suites
- CLI Tool (
bin/): TypeScript-based command interface for packaging apps - Tauri App (
src-tauri/): Rust-based desktop framework - Injection System (
src-tauri/src/inject/): Custom CSS/JS injection for webpages - Configuration: Multi-platform app settings and build configurations
- Node.js ≥22.0.0 (recommended LTS, older versions ≥18.0.0 may work)
- Rust ≥1.85.0 (recommended stable)
macOS:
- Xcode Command Line Tools:
xcode-select --install
Windows:
-
CRITICAL: Consult Tauri prerequisites before proceeding
-
Windows 10 SDK (10.0.19041.0) and Visual Studio Build Tools 2022 (≥17.2)
-
Required redistributables:
- Microsoft Visual C++ 2015-2022 Redistributable (x64)
- Microsoft Visual C++ 2015-2022 Redistributable (x86)
- Microsoft Visual C++ 2012 Redistributable (x86) (optional)
- Microsoft Visual C++ 2013 Redistributable (x86) (optional)
- Microsoft Visual C++ 2008 Redistributable (x86) (optional)
-
Windows ARM (ARM64) support: Install C++ ARM64 build tools in Visual Studio Installer under "Individual Components" → "MSVC v143 - VS 2022 C++ ARM64 build tools"
Linux (Ubuntu):
sudo apt install libdbus-1-dev \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
gnome-video-effects \
gnome-video-effects-extra \
libglib2.0-dev \
pkg-config# Clone the repository
git clone https://github.com/tw93/Pake.git
cd Pake
# Install dependencies
pnpm install
# Start development
pnpm run dev- CLI Changes: Edit files in
bin/, then runpnpm run cli:build - Core App Changes: Edit files in
src-tauri/src/, then runpnpm run dev - Injection Logic: Modify files in
src-tauri/src/inject/for web customizations - Testing: Run
pnpm testfor comprehensive validation
- Dev mode:
pnpm run dev(hot reload) - Build:
pnpm run build - Debug build:
pnpm run build:debug - CLI build:
pnpm run cli:build
For CLI development with hot reloading, modify the DEFAULT_DEV_PAKE_OPTIONS configuration in bin/defaults.ts:
export const DEFAULT_DEV_PAKE_OPTIONS: PakeCliOptions & { url: string } = {
...DEFAULT_PAKE_OPTIONS,
url: "https://weekly.tw93.fun/en",
name: "Weekly",
};Then run:
pnpm run cli:devThis script reads the configuration and packages the specified app in watch mode, with hot updates for pake-cli code changes.
Comprehensive CLI build and release validation guidance for multi-platform packaging.
# Complete test suite (recommended)
pnpm test # Build the CLI, run the Vitest suite, then run real build + release workflow smoke tests
# Skip the real build and release workflow smoke tests
pnpm test -- --no-build
# Run the fast Vitest suite only
npx vitest run
# Build the CLI explicitly
pnpm run cli:build
# Run the release workflow smoke test directly
node ./tests/release.js- ✅ Vitest suite: unit, integration, builder, and CLI option coverage
- ✅ Real build smoke test: platform-aware packaging validation
- ✅ Release workflow smoke test: verifies the release build path used for popular apps
pnpm testruns the main CLI test runner intests/index.js, which:- builds the CLI,
- runs the Vitest suite,
- runs the real build smoke test unless
--no-buildis passed, - and then runs the release workflow smoke test when the real build phase succeeds.
Useful optional flags:
--no-unit: skip unit tests--no-integration: skip integration tests--no-builder: skip builder tests--no-build: skip the real build smoke test and the follow-up release workflow smoke test--e2e: add end-to-end configuration tests--pake-cli: add GitHub Actions related checks
If you only want the release workflow smoke test, run node ./tests/release.js directly.
- CLI file not found: Run
pnpm run cli:build - Test timeout: Build tests require extended time to complete
- Build failures: Check Rust toolchain with
rustup update - Permission errors: Ensure write permissions are available
- Rust compilation errors: Run
cargo cleaninsrc-tauri/directory - Node dependency issues: Delete
node_modulesand runpnpm install - Permission errors on macOS: Run
sudo xcode-select --reset