A modern, production-ready template for building UserScripts using TypeScript and Vite. This template provides a solid foundation with best practices, type safety, and modern development tools for creating sophisticated Tampermonkey and Greasemonkey scripts.
- š Modern Tech Stack: TypeScript, Vite, ESLint, Prettier, Bun
- š”ļø Type Safety: Strict TypeScript configuration with comprehensive UserScript API definitions
- š§ Development Tools: ESLint, Prettier, Bun-powered automated build pipeline
- šÆ Environment Support: Separate development and production configurations
- š¦ Modular Architecture: Component system with reusable utilities
- š¾ Storage Management: Type-safe wrapper for GM_setValue/GM_getValue
- š ļø Build System: Optimized Vite configuration with automatic header generation
- šØ DOM Utilities: Helper functions for element manipulation and waiting
- ⨠Optional bQuery Upgrade Path: Advanced example using
@bquery/bquery/core,reactive, andmedia - š Error Handling: Comprehensive error boundary system
- ā” Event System: Type-safe event emitter for module communication
- š± Mobile Support: Touch-optimized interface with mobile browser detection
- š¤ Touch Gestures: Built-in touch event handling and gesture recognition
- š² Responsive Design: Mobile-first CSS with safe area support for notched devices
git clone https://github.com/JosunLP/UserScriptProjectTemplate.git
cd UserScriptProjectTemplate
bun install# Install dependencies bun install # Start development mode with auto-rebuild bun run dev # Type checking bun run type-check # Linting and formatting bun run validate
src/ āāā types/ # TypeScript type definitions āāā utils/ # Utility functions (Storage, DOM, Events) āāā core/ # Core application logic āāā modules/ # Feature modules, including the optional bQuery example āāā index.ts # Main application entry point tools/ āāā userScriptHeader.ts # UserScript header generator assets/ # Icons and static resources āāā icon.afdesign
The main configuration is in header.config.json. This file controls UserScript metadata generation:
{
"environments": {
"development": {
"includes": ["http://localhost:*/*", "https://localhost:*/*"],
"grants": ["GM_setValue", "GM_getValue", "GM_log", "GM_notification"]
},
"production": {
"includes": ["https://your-domain.com/*"],
"grants": ["GM_setValue", "GM_getValue"]
}
}
}The template now ships with a selective @bquery/bquery example instead of replacing the existing utility layer.
- The existing
DOMUtils,EventEmitter,Storage, and mobile helpers remain the default foundation. - The advanced example in
src/modules/bquery-example.tsdemonstrates when bQuery adds value:@bquery/bquery/corefor DOM updates and delegated events@bquery/bquery/reactivefor signal-driven state@bquery/bquery/mediafor responsive viewport state
- Only subpath imports are used so the bundle stays as small as possible.
- Because bQuery ships modern ESM, the advanced path now targets current UserScript-capable browsers and runtime versions (
node >=24,bun >=1.3.11). - If you do not want the advanced path, remove the
bquery-examplemodule import fromsrc/index.tsand uninstall@bquery/bquery.
This keeps the base template approachable while still providing a modern upgrade path for more interactive UserScripts.
# Development bun run dev # Start development with watch mode bun run dev:build # Single development build with dev header bun run dev:header # Generate header for an existing dev build # Production bun run build # Build for production bun run build:prod # Explicit production build # Quality Assurance bun run validate # Type check + lint bun run lint # ESLint bun run lint:fix # ESLint with auto-fix bun run format # Prettier formatting # Utilities bun run clean # Clean dist folder bun run type-check # TypeScript type checking
The template features advanced build optimization for production:
| Build Type | File Size | Compressed | Features |
|---|---|---|---|
| Development | ~115 KB | ~30 KB | Source maps, debug info, readable code |
| Production | ~25 KB | ~6 KB | Minified, tree-shaken, optimized |
Production optimizations include:
- ā” Terser minification with aggressive compression settings
- š³ Tree-shaking to remove unused code
- šÆ Dead code elimination for DEV blocks
- š¦ Module inlining for single-file output
- š§ Property mangling for smaller variable names
- š ES2020 target for modern JavaScript features
- š¾ GZIP compression reducing size by ~75%
- Configure your script in
header.config.json - Install dependencies:
bun install - Start development:
bun run dev - Write your code in the
src/directory - Build for production:
bun run build - Install the UserScript from
dist/folder in Tampermonkey/Greasemonkey
The template includes a type-safe storage system:
import { Storage } from '@/utils/storage'; // Save data Storage.set('userData', { name: 'John', visits: 5 }); // Get data with default value const userData = Storage.get('userData', { name: '', visits: 0 }); // Check if key exists if (Storage.has('userData')) { // Key exists } // Remove data Storage.remove('userData');
Helper functions for DOM manipulation:
import { DOMUtils } from '@/utils/dom'; // Wait for element to appear const element = await DOMUtils.waitForElement('.my-selector'); // Add custom styles DOMUtils.addStyles(` .my-class { color: red; } `); // Create element with attributes const button = DOMUtils.createElement('button', { textContent: 'Click me', onclick: () => console.log('Clicked!'), });
Type-safe communication between modules:
import { EventEmitter } from '@/utils/events'; interface MyEvents { userAction: { userId: string }; dataLoaded: { count: number }; } const emitter = new EventEmitter<MyEvents>(); // Listen for events emitter.on('userAction', ({ userId }) => { console.log(`User ${userId} performed an action`); }); // Emit events emitter.emit('userAction', { userId: '123' });
Create reusable, event-driven modules:
import { EventEmitter } from '@/utils/events'; interface ModuleEvents { initialized: void; actionPerformed: { action: string }; } export class MyModule extends EventEmitter<ModuleEvents> { async initialize() { // Module initialization logic this.emit('initialized', undefined); } }
The included advanced example module shows a selective integration strategy:
- keep GM storage in
Storage - keep the existing template modules intact
- add bQuery only where it improves ergonomics
It uses:
- reactive signals for counter and panel state
- delegated event handling via bQuery core
- viewport/media tracking via bQuery media helpers
That makes it a good starting point for overlays, dashboards, and richer in-page tools without forcing a full framework-style migration.
Mobile-specific functionality for touch-enabled devices:
import { MobileUtils } from '@/utils/mobile'; // Detect mobile browser and capabilities const detection = MobileUtils.detect(); console.log('Is Mobile:', detection.isMobile); console.log('Has Touch:', detection.hasTouch); console.log('Browser:', detection.browser); // Add mobile-optimized styles if (detection.isMobile) { MobileUtils.addMobileStyles(); } // Unified touch/mouse event handling MobileUtils.addUnifiedEventListener(element, 'start', event => { const position = MobileUtils.getEventPosition(event); console.log('Touch/click at:', position); }); // Create mobile-friendly buttons const button = mobileModule.createMobileButton('Action', () => { console.log('Button pressed'); }); // Orientation detection console.log('Portrait mode:', MobileUtils.isPortrait());
- Tampermonkey: Full support with all GM_* APIs
- Greasemonkey: Compatible with standard UserScript APIs
- Violentmonkey: Full compatibility
- Safari: Works with userscript managers
Android:
- Kiwi Browser: Full Chrome extension + UserScript support
- Microsoft Edge Mobile: Tampermonkey support
- Firefox Mobile: Greasemonkey, Tampermonkey, Violentmonkey
- Yandex Browser: Chrome extension support
iOS:
- Safari Mobile: Tampermonkey or Userscripts App
- Limited support due to iOS restrictions
- Touch Gestures: Tap, swipe, and pinch detection
- Responsive Design: Mobile-first CSS with viewport adaptation
- Safe Area Support: Automatic handling of notched devices
- Orientation Detection: Portrait/landscape change handling
- Mobile-Optimized UI: Touch-friendly buttons and menus
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and ensure tests pass:
bun run validate - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow TypeScript best practices
- Use meaningful variable and function names
- Add proper error handling
- Write self-documenting code
- Follow the established project structure
- Run
bun run validatebefore committing
This project is licensed under the MIT License.
Jonas Pfalzgraf
- Email: [email protected]
- GitHub: @JosunLP
- Website: josunlp.de
Built with ā¤ļø for the UserScript community