UNPKG

create-appjet

Version:

Create Appjet desktop apps

271 lines (212 loc) 7.13 kB
# Appjet ✈️ > ⚠️ **This project is in early development** - Only basic template is currently available. **Fast, simple desktop apps with modern web technologies** Appjet is a lightweight alternative to Electron, built for speed and simplicity. Create desktop applications using Vue.js, HTML, CSS, and JavaScript - powered by Bun and native webviews. ## 📋 Prerequisites ### Required - **[Bun](https://bun.sh)** (not Node.js compatible) - **System webview libraries**: #### Windows - Windows 11: ✅ Built-in (no additional setup) - Windows 10: May require WebView2 runtime #### macOS - Built-in WebKit (no additional setup required) #### Linux Install GTK 4 and WebkitGTK 6: ```bash # Debian/Ubuntu sudo apt install libgtk-4-1 libwebkitgtk-6.0-4 # Arch Linux sudo pacman -S gtk4 webkitgtk-6.0 # Fedora sudo dnf install gtk4 webkitgtk6.0 ``` ## ⚡ Why Appjet? - **🚀 Lightning Fast** - Built on Bun, compiles to native executables - **🪶 Lightweight** - No bundled Chromium, uses system webview - **🎯 Simple** - Minimal API, focus on your app logic - **🔧 Modern Stack** - Vue.js, Vite, TypeScript out of the box - **📦 Single Binary** - Compile to standalone executables - **🔥 Hot Reload** - Instant updates during development - **🔗 Auto Binding** - Automatic function binding between backend and frontend ## 🚀 Quick Start Create a new Appjet app: ```bash bun create appjet my-app cd my-app ``` ### Setup Frontend (Vue.js example) ```bash cd frontend bun create vue@latest . bun install # Start frontend dev server bun dev ``` ### Setup Backend ```bash cd ../backend bun install # Start backend (in another terminal) bun dev ``` ## ⚙️ Configuration ### Window & Webview Settings (`appjet.config.ts`) ```typescript import type { AppjetConfig } from "appjet"; export const config: AppjetConfig = { window: { debug: true, // Enable dev tools height: 800, // Window height width: 1200, // Window width resizable: true, // Allow window resize title: "My Appjet App", // Window title }, frontend: { distPath: "../frontend/dist", // Production build path entryPointFile: "index.html", // Entry HTML file viteServer: "http://localhost:5173", // Dev server URL }, }; ``` ### Build Configuration (`appjet.build.ts`) ```typescript import { buildAppjetApp, type BuildConfig } from "appjet"; export const build: BuildConfig = { appName: "my-app", // Executable name entrypoint: "./appjet.ts", // Backend entry point outputDir: "./dist", // Build output directory frontendDir: "../frontend", // Frontend source directory targets: ["bun-linux-x64"], // Target platforms }; await buildAppjetApp(build); ``` ## 🔗 Backend ↔ Frontend Communication Appjet's **magic**: just register a function in your backend, and it's automatically available in your frontend! ### Backend (`backend/api.ts`) ```typescript import { registerBinding } from "appjet"; import { readdir, writeFile } from "fs/promises"; // Simple function const greetUser = (name: string) => { return `Hello ${name}! Welcome to Appjet ✈️`; }; // Async function with file system access const listFiles = async (directory: string) => { try { const files = await readdir(directory); return { success: true, files }; } catch (error) { return { success: false, error: error.message }; } }; // Complex function with multiple operations const saveUserData = async (userData: { name: string; email: string }) => { await writeFile('user.json', JSON.stringify(userData, null, 2)); console.log("User data saved!"); return { saved: true, timestamp: Date.now() }; }; // Register functions (they become available in frontend automatically!) registerBinding("greetUser", greetUser); registerBinding("listFiles", listFiles); registerBinding("saveUserData", saveUserData); // Or register multiple at once registerBinding({ getCurrentTime: () => new Date().toISOString(), getSystemInfo: () => ({ platform: process.platform, arch: process.arch }) }); ``` ### Frontend (Vue.js, React, or vanilla JS) ```typescript // Cast window to access bound functions const w = window as any; // Call the backend functions directly const greeting = await w.greetUser("Alice"); console.log(greeting); // "Hello Alice! Welcome to Appjet ✈️" // File system operations from frontend const result = await w.listFiles("/home/user/documents"); if (result.success) { console.log("Files:", result.files); } // Save data await w.saveUserData({ name: "Bob", email: "bob@example.com" }); // Get system info const info = await w.getSystemInfo(); console.log(info); // { platform: "linux", arch: "x64" } ``` **💡 Pro tip:** For better TypeScript support, you can create a types file: ```typescript // types/appjet.d.ts declare global { interface Window { greetUser: (name: string) => Promise<string>; listFiles: (directory: string) => Promise<{success: boolean, files?: string[], error?: string}>; saveUserData: (userData: {name: string, email: string}) => Promise<{saved: boolean, timestamp: number}>; getSystemInfo: () => Promise<{platform: string, arch: string}>; } } ``` Then use with full type safety: ```typescript const greeting = await window.greetUser("Alice"); // ✅ Fully typed! ``` **✨ That's it!** No IPC setup, no manual bindings, no complex messaging. Just write functions in your backend and call them from your frontend like magic! 🪄 ## 🛠️ Build for Production ### For Vue.js Projects 1. **Update your router** (`src/router/index.ts`) to use memory history: ```typescript import { createRouter, createMemoryHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' const router = createRouter({ history: createMemoryHistory(), // Use memory history for embedded apps routes: [ { path: '/', name: 'home', component: HomeView, }, { path: '/about', name: 'about', component: () => import('../views/AboutView.vue'), }, ], }) export default router ``` 2. **Update your `vite.config.ts`** for single-file output: ```typescript export default defineConfig({ // ... other config build: { assetsInlineLimit: 999999999, // Inline all assets cssCodeSplit: false, // Single CSS file rollupOptions: { output: { manualChunks: undefined, inlineDynamicImports: true, entryFileNames: 'assets/index.js', chunkFileNames: 'assets/index.js', assetFileNames: 'assets/index.[ext]', }, }, }, }); ``` ### Build Commands ```bash # Build everything cd backend bun run build # Or build executable directly bun run appjet.build.ts ``` ## 📚 Available Targets - `bun-linux-x64` - Linux 64-bit - `bun-windows-x64` - Windows 64-bit - `bun-darwin-x64` - macOS Intel - `bun-darwin-arm64` - macOS Apple Silicon ## 🤝 Contributing Contributions welcome! This project is in early development. ## 📄 License MIT © Bastien Etienne