Compare commits

..

No commits in common. "8ebb1871478463fe146cb12a9c1210dfe477c0a7" and "dcb2a449aa105df12784f2ceee9a617545dd361f" have entirely different histories.

6 changed files with 60 additions and 216 deletions

119
README.md
View file

@ -1,24 +1,8 @@
# UserScript Project Template # UserScript Project Template
[![GitHub license](https://img.shields.io/github/license/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate/blob/main/LICENSE) [![GitHub license](https://img.shields.io/github/license/JosunLP/UserScriptProjectTemplate)](https://github.com/JosunLP/UserScriptProjectTemplate/blob/main/LICENSE)
[![GitHub issues](https://img.shields.io/github/issues/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate/issues) [![GitHub issues](https://img.shields.io/github/issues/JosunLP/UserScriptProjectTemplate)](https://github.com/JosunLP/UserScriptProjectTemplate/issues)
[![GitHub stars](https://img.shields.io/github/stars/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate/stargazers) [![GitHub stars](https://img.shields.io/github/stars/JosunLP/UserScriptProjectTemplate)](https://github.com/JosunLP/UserScriptProjectTemplate/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate/network)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.4+-blue?logo=typescript&style=for-the-badge)](https://www.typescriptlang.org/)
[![Vite](https://img.shields.io/badge/Vite-7.0+-646CFF?logo=vite&style=for-the-badge)](https://vitejs.dev/)
[![ESLint](https://img.shields.io/badge/ESLint-8.57+-4B32C3?logo=eslint&style=for-the-badge)](https://eslint.org/)
[![Prettier](https://img.shields.io/badge/Prettier-3.6+-F7B93E?logo=prettier&style=for-the-badge)](https://prettier.io/)
[![Node.js](https://img.shields.io/badge/Node.js-18+-339933?logo=node.js&style=for-the-badge)](https://nodejs.org/)
[![Tampermonkey](https://img.shields.io/badge/Tampermonkey-Compatible-00485B?logo=tampermonkey&style=for-the-badge)](https://www.tampermonkey.net/)
[![Greasemonkey](https://img.shields.io/badge/Greasemonkey-Compatible-FF6600?logo=firefox&style=for-the-badge)](https://www.greasespot.net/)
[![Violentmonkey](https://img.shields.io/badge/Violentmonkey-Compatible-663399?logo=violentmonkey&style=for-the-badge)](https://violentmonkey.github.io/)
[![Mobile Support](https://img.shields.io/badge/Mobile-Support-00C851?logo=android&style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate#mobile-browser-support)
[![Last Commit](https://img.shields.io/github/last-commit/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate/commits)
[![Contributors](https://img.shields.io/github/contributors/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate/graphs/contributors)
[![Repository Size](https://img.shields.io/github/repo-size/JosunLP/UserScriptProjectTemplate?style=for-the-badge)](https://github.com/JosunLP/UserScriptProjectTemplate)
## Description ## Description
@ -26,19 +10,19 @@ A modern, production-ready template for building UserScripts using TypeScript an
## Features ## Features
- 🚀 **Modern Tech Stack:** TypeScript, Vite, ESLint, Prettier 🚀 **Modern Tech Stack:** TypeScript, Vite, ESLint, Prettier
- 🛡️ **Type Safety:** Strict TypeScript configuration with comprehensive UserScript API definitions 🛡️ **Type Safety:** Strict TypeScript configuration with comprehensive UserScript API definitions
- 🔧 **Development Tools:** ESLint, Prettier, automated build pipeline 🔧 **Development Tools:** ESLint, Prettier, automated build pipeline
- 🎯 **Environment Support:** Separate development and production configurations 🎯 **Environment Support:** Separate development and production configurations
- 📦 **Modular Architecture:** Component system with reusable utilities 📦 **Modular Architecture:** Component system with reusable utilities
- 💾 **Storage Management:** Type-safe wrapper for GM_setValue/GM_getValue 💾 **Storage Management:** Type-safe wrapper for GM_setValue/GM_getValue
- 🛠️ **Build System:** Optimized Vite configuration with automatic header generation 🛠️ **Build System:** Optimized Vite configuration with automatic header generation
- 🎨 **DOM Utilities:** Helper functions for element manipulation and waiting 🎨 **DOM Utilities:** Helper functions for element manipulation and waiting
- 🔒 **Error Handling:** Comprehensive error boundary system 🔒 **Error Handling:** Comprehensive error boundary system
-**Event System:** Type-safe event emitter for module communication **Event System:** Type-safe event emitter for module communication
- 📱 **Mobile Support:** Touch-optimized interface with mobile browser detection 📱 **Mobile Support:** Touch-optimized interface with mobile browser detection
- 🤏 **Touch Gestures:** Built-in touch event handling and gesture recognition 🤏 **Touch Gestures:** Built-in touch event handling and gesture recognition
- 📲 **Responsive Design:** Mobile-first CSS with safe area support for notched devices 📲 **Responsive Design:** Mobile-first CSS with safe area support for notched devices
## Installation ## Installation
@ -80,9 +64,9 @@ src/
tools/ tools/
├── userScriptHeader.ts # UserScript header generator ├── userScriptHeader.ts # UserScript header generator
└── userScriptHeader.js # Compiled header generator
assets/ # Icons and static resources assets/ # Icons and static resources
└── icon.afdesign
``` ```
### Configuration ### Configuration
@ -126,25 +110,6 @@ npm run clean # Clean dist folder
npm run type-check # TypeScript type checking npm run type-check # TypeScript type checking
``` ```
### Build Optimization
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%
### Development Workflow ### Development Workflow
1. **Configure your script** in `header.config.json` 1. **Configure your script** in `header.config.json`
@ -275,10 +240,10 @@ console.log('Portrait mode:', MobileUtils.isPortrait());
## UserScript Compatibility ## UserScript Compatibility
- **Tampermonkey:** Full support with all GM\_\* APIs **Tampermonkey:** Full support with all GM\_\* APIs
- **Greasemonkey:** Compatible with standard UserScript APIs **Greasemonkey:** Compatible with standard UserScript APIs
- **Violentmonkey:** Full compatibility **Violentmonkey:** Full compatibility
- **Safari:** Works with userscript managers **Safari:** Works with userscript managers
### Mobile Browser Support ### Mobile Browser Support
@ -296,11 +261,11 @@ console.log('Portrait mode:', MobileUtils.isPortrait());
### Mobile Features ### Mobile Features
- **Touch Gestures:** Tap, swipe, and pinch detection **Touch Gestures:** Tap, swipe, and pinch detection
- **Responsive Design:** Mobile-first CSS with viewport adaptation **Responsive Design:** Mobile-first CSS with viewport adaptation
- **Safe Area Support:** Automatic handling of notched devices **Safe Area Support:** Automatic handling of notched devices
- **Orientation Detection:** Portrait/landscape change handling **Orientation Detection:** Portrait/landscape change handling
- **Mobile-Optimized UI:** Touch-friendly buttons and menus **Mobile-Optimized UI:** Touch-friendly buttons and menus
## Contributing ## Contributing
@ -313,12 +278,12 @@ console.log('Portrait mode:', MobileUtils.isPortrait());
## Development Guidelines ## Development Guidelines
- Follow TypeScript best practices Follow TypeScript best practices
- Use meaningful variable and function names Use meaningful variable and function names
- Add proper error handling Add proper error handling
- Write self-documenting code Write self-documenting code
- Follow the established project structure Follow the established project structure
- Run `npm run validate` before committing Run `npm run validate` before committing
## License ## License
@ -328,9 +293,23 @@ This project is licensed under the [MIT License](https://opensource.org/licenses
**_Jonas Pfalzgraf_** **_Jonas Pfalzgraf_**
- Email: [info@josunlp.de](mailto:info@josunlp.de) • Email: [info@josunlp.de](mailto:info@josunlp.de)
- GitHub: [@JosunLP](https://github.com/JosunLP) • GitHub: [@JosunLP](https://github.com/JosunLP)
- Website: [josunlp.de](https://josunlp.de)
## Changelog
### v0.0.1 (Current)
• ✨ Modern TypeScript setup with strict type checking
• 🛡️ Comprehensive UserScript API definitions
• 🎨 Modular architecture with utilities and components
• 🔧 ESLint and Prettier configuration
• 📦 Optimized Vite build system
• 🚀 Environment-based configuration
• 💾 Type-safe storage management
• 🎯 Event-driven module system
• ⚡ DOM manipulation utilities
• 🛠️ Automated header generation
--- ---

View file

@ -9,7 +9,7 @@
"dev:header": "npm run build-userScriptHeader", "dev:header": "npm run build-userScriptHeader",
"dev:build": "vite build --mode development && npm run build-userScriptHeader", "dev:build": "vite build --mode development && npm run build-userScriptHeader",
"build": "vite build && npm run build-userScriptHeader", "build": "vite build && npm run build-userScriptHeader",
"build:prod": "npm run clean && vite build --mode production && npm run build-userScriptHeader", "build:prod": "vite build --mode production && npm run build-userScriptHeader",
"build-tooling": "tsc ./tools/userScriptHeader.ts --resolveJsonModule --esModuleInterop", "build-tooling": "tsc ./tools/userScriptHeader.ts --resolveJsonModule --esModuleInterop",
"build-userScriptHeader": "npm run build-tooling && node ./tools/userScriptHeader.js", "build-userScriptHeader": "npm run build-tooling && node ./tools/userScriptHeader.js",
"validate": "npm run type-check && npm run lint", "validate": "npm run type-check && npm run lint",

View file

@ -25,14 +25,6 @@ class App extends EventEmitter<AppEvents> {
constructor() { constructor() {
super(); super();
// Development-only debug information
if (__DEV__) {
console.log('🔧 UserScript starting in development mode');
console.log('📦 Version:', __VERSION__);
console.log('🕐 Build time:', __BUILD_TIME__);
}
this.initialize(); this.initialize();
} }

View file

@ -22,7 +22,6 @@ interface ExampleModuleEvents {
export class ExampleModule extends EventEmitter<ExampleModuleEvents> { export class ExampleModule extends EventEmitter<ExampleModuleEvents> {
private isInitialized = false; private isInitialized = false;
private actionCount = 0; private actionCount = 0;
private lastActionTime = 0;
constructor() { constructor() {
super(); super();
@ -37,7 +36,6 @@ export class ExampleModule extends EventEmitter<ExampleModuleEvents> {
// Load persistent data // Load persistent data
this.actionCount = Storage.get<number>('exampleModule.actionCount', 0) || 0; this.actionCount = Storage.get<number>('exampleModule.actionCount', 0) || 0;
this.lastActionTime = Storage.get<number>('exampleModule.lastActionTime', 0) || 0;
// Wait for required DOM elements (example) // Wait for required DOM elements (example)
await this.waitForPageElements(); await this.waitForPageElements();
@ -166,11 +164,9 @@ export class ExampleModule extends EventEmitter<ExampleModuleEvents> {
public performAction(trigger: string): void { public performAction(trigger: string): void {
this.actionCount++; this.actionCount++;
const timestamp = Date.now(); const timestamp = Date.now();
this.lastActionTime = timestamp;
// Store the updated count and last action time // Store the updated count
Storage.set('exampleModule.actionCount', this.actionCount); Storage.set('exampleModule.actionCount', this.actionCount);
Storage.set('exampleModule.lastActionTime', timestamp);
// Emit event // Emit event
this.emit('actionPerformed', { action: trigger, timestamp }); this.emit('actionPerformed', { action: trigger, timestamp });
@ -209,7 +205,7 @@ export class ExampleModule extends EventEmitter<ExampleModuleEvents> {
const stats = { const stats = {
initialized: this.isInitialized, initialized: this.isInitialized,
actionCount: this.actionCount, actionCount: this.actionCount,
lastAction: this.lastActionTime, lastAction: Storage.get<number>('exampleModule.lastActionTime', 0),
}; };
const message = [ const message = [
@ -234,7 +230,6 @@ export class ExampleModule extends EventEmitter<ExampleModuleEvents> {
Storage.remove('exampleModule.actionCount'); Storage.remove('exampleModule.actionCount');
Storage.remove('exampleModule.lastActionTime'); Storage.remove('exampleModule.lastActionTime');
this.actionCount = 0; this.actionCount = 0;
this.lastActionTime = 0;
console.log('🧹 Example module data reset'); console.log('🧹 Example module data reset');
this.showNotification('Module data reset!'); this.showNotification('Module data reset!');
} }

View file

@ -94,15 +94,6 @@ declare global {
* UnsafeWindow for accessing page's global scope * UnsafeWindow for accessing page's global scope
*/ */
const unsafeWindow: Window & typeof globalThis; const unsafeWindow: Window & typeof globalThis;
/**
* Build-time constants injected by Vite
*/
const __DEV__: boolean;
const __VERSION__: string;
const __DEBUG__: boolean;
const __USERSCRIPT__: boolean;
const __BUILD_TIME__: string;
} }
export {}; export {};

View file

@ -1,7 +1,7 @@
import { resolve } from 'path'; import { resolve } from "path";
import { defineConfig } from 'vite'; import { defineConfig } from "vite";
import tsconfigPaths from 'vite-tsconfig-paths'; import tsconfigPaths from "vite-tsconfig-paths";
import pkgjsn from './package.json'; import pkgjsn from "./package.json";
export default defineConfig(({ mode }) => { export default defineConfig(({ mode }) => {
const isDev = mode === 'development'; const isDev = mode === 'development';
@ -9,106 +9,18 @@ export default defineConfig(({ mode }) => {
return { return {
build: { build: {
rollupOptions: { rollupOptions: {
input: resolve(__dirname, 'src/index.ts'), input: resolve(__dirname, "src/index.ts"),
output: { output: {
entryFileNames: `${pkgjsn.name}${isDev ? '.dev' : ''}.user.js`, entryFileNames: `${pkgjsn.name}${isDev ? '.dev' : ''}.user.js`,
dir: resolve(__dirname, 'dist'), dir: resolve(__dirname, "dist"),
// Disable code splitting - everything in one file for UserScript
inlineDynamicImports: true,
manualChunks: undefined,
// Optimize output format
format: 'iife',
// Remove unnecessary comments in production
banner: isDev ? undefined : '',
footer: isDev ? undefined : '',
},
// Prevent any external dependencies
external: [],
// Tree-shaking optimizations
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
unknownGlobalSideEffects: false,
}, },
}, },
sourcemap: isDev ? 'inline' : false, sourcemap: isDev ? "inline" : false,
minify: isDev ? false : 'terser', minify: isDev ? false : 'terser',
// Enhanced Terser options for maximum compression
terserOptions: isDev
? undefined
: {
compress: {
drop_console: false, // Keep console for UserScript debugging
drop_debugger: true,
pure_funcs: ['console.debug'],
passes: 2,
unsafe: true,
unsafe_arrows: true,
unsafe_comps: true,
unsafe_math: true,
unsafe_methods: true,
unsafe_proto: true,
unsafe_regexp: true,
unsafe_undefined: true,
hoist_funs: true,
hoist_props: true,
hoist_vars: false,
if_return: true,
join_vars: true,
sequences: true,
side_effects: true,
switches: true,
typeofs: true,
booleans: true,
collapse_vars: true,
comparisons: true,
computed_props: true,
conditionals: true,
dead_code: true,
directives: true,
evaluate: true,
expression: false,
global_defs: {},
keep_fargs: false,
keep_infinity: false,
loops: true,
negate_iife: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
},
mangle: {
toplevel: true,
safari10: false,
properties: {
regex: /^_/,
},
},
format: {
comments: false,
beautify: false,
},
ecma: 2020,
toplevel: true,
safari10: false,
ie8: false,
},
// Ensure all assets are inlined
assetsInlineLimit: Number.MAX_SAFE_INTEGER,
// Disable CSS code splitting
cssCodeSplit: false,
// Target modern browsers for better optimization
target: ['es2020', 'chrome80', 'firefox78', 'safari14'],
// Report compressed file sizes
reportCompressedSize: true,
// Chunk size warnings
chunkSizeWarningLimit: 500,
}, },
plugins: [tsconfigPaths()], plugins: [tsconfigPaths()],
resolve: { resolve: {
extensions: ['.tsx', '.ts', '.js'], extensions: [".tsx", ".ts", ".js"],
alias: { alias: {
'@': resolve(__dirname, 'src'), '@': resolve(__dirname, 'src'),
}, },
@ -116,31 +28,6 @@ export default defineConfig(({ mode }) => {
define: { define: {
__DEV__: isDev, __DEV__: isDev,
__VERSION__: JSON.stringify(pkgjsn.version), __VERSION__: JSON.stringify(pkgjsn.version),
// Production optimizations
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
// Remove debug code in production
__DEBUG__: isDev,
// UserScript environment flags
__USERSCRIPT__: true,
__BUILD_TIME__: JSON.stringify(new Date().toISOString()),
},
// Optimize dependencies
optimizeDeps: {
include: [],
exclude: [],
},
// Enable esbuild optimizations
esbuild: {
target: 'es2020',
legalComments: 'none',
...(isDev
? {}
: {
drop: ['debugger'],
minifyIdentifiers: true,
minifySyntax: true,
minifyWhitespace: true,
}),
}, },
}; };
}); });