diff --git a/.cursor-markdown-rules.md b/.cursor-markdown-rules.md new file mode 100644 index 00000000..129a11f9 --- /dev/null +++ b/.cursor-markdown-rules.md @@ -0,0 +1,310 @@ +# Cursor Markdown Ruleset for TimeSafari Documentation + +## Overview + +This ruleset enforces consistent markdown formatting standards across all project +documentation, ensuring readability, maintainability, and compliance with +markdownlint best practices. + +## General Formatting Standards + +### Line Length + +- **Maximum line length**: 80 characters +- **Exception**: Code blocks (JSON, shell, TypeScript, etc.) - no line length + enforcement +- **Rationale**: Ensures readability across different screen sizes and terminal + widths + +### Blank Lines + +- **Headings**: Must be surrounded by blank lines above and below +- **Lists**: Must be surrounded by blank lines above and below +- **Code blocks**: Must be surrounded by blank lines above and below +- **Maximum consecutive blank lines**: 1 (no multiple blank lines) +- **File start**: No blank lines at the beginning of the file +- **File end**: Single newline character at the end + +### Whitespace + +- **No trailing spaces**: Remove all trailing whitespace from lines +- **No tabs**: Use spaces for indentation +- **Consistent indentation**: 2 spaces for list items and nested content + +## Heading Standards + +### Format + +- **Style**: ATX-style headings (`#`, `##`, `###`, etc.) +- **Case**: Title case for general headings +- **Code references**: Use backticks for file names and technical terms + - ✅ `### Current package.json Scripts` + - ❌ `### Current Package.json Scripts` + +### Hierarchy + +- **H1 (#)**: Document title only +- **H2 (##)**: Major sections +- **H3 (###)**: Subsections +- **H4 (####)**: Sub-subsections +- **H5+**: Avoid deeper nesting + +## List Standards + +### Unordered Lists + +- **Marker**: Use `-` (hyphen) consistently +- **Indentation**: 2 spaces for nested items +- **Blank lines**: Surround lists with blank lines + +### Ordered Lists + +- **Format**: `1.`, `2.`, `3.` (sequential numbering) +- **Indentation**: 2 spaces for nested items +- **Blank lines**: Surround lists with blank lines + +### Task Lists + +- **Format**: `- [ ]` for incomplete, `- [x]` for complete +- **Use case**: Project planning, checklists, implementation tracking + +## Code Block Standards + +### Fenced Code Blocks + +- **Syntax**: Triple backticks with language specification +- **Languages**: `json`, `bash`, `typescript`, `javascript`, `yaml`, `markdown` +- **Blank lines**: Must be surrounded by blank lines above and below +- **Line length**: No enforcement within code blocks + +### Inline Code + +- **Format**: Single backticks for inline code references +- **Use case**: File names, commands, variables, properties + +## Special Content Standards + +### JSON Examples + +```json +{ + "property": "value", + "nested": { + "property": "value" + } +} +``` + +### Shell Commands + +```bash +# Command with comment +npm run build:web + +# Multi-line command +VITE_GIT_HASH=`git log -1 --pretty=format:%h` \ + vite build --config vite.config.web.mts +``` + +### TypeScript Examples + +```typescript +// Function with JSDoc +/** + * Get environment configuration + * @param env - Environment name + * @returns Environment config object + */ +const getEnvironmentConfig = (env: string) => { + switch (env) { + case 'prod': + return { /* production settings */ }; + default: + return { /* development settings */ }; + } +}; +``` + +## File Structure Standards + +### Document Header + +```markdown +# Document Title + +**Author**: Matthew Raymer +**Date**: YYYY-MM-DD +**Status**: 🎯 **STATUS** - Brief description + +## Overview + +Brief description of the document's purpose and scope. +``` + +### Section Organization + +1. **Overview/Introduction** +2. **Current State Analysis** +3. **Implementation Plan** +4. **Technical Details** +5. **Testing & Validation** +6. **Next Steps** + +## Markdownlint Configuration + +### Required Rules + +```json +{ + "MD013": { "code_blocks": false }, + "MD012": true, + "MD022": true, + "MD031": true, + "MD032": true, + "MD047": true, + "MD009": true +} +``` + +### Rule Explanations + +- **MD013**: Line length (disabled for code blocks) +- **MD012**: No multiple consecutive blank lines +- **MD022**: Headings should be surrounded by blank lines +- **MD031**: Fenced code blocks should be surrounded by blank lines +- **MD032**: Lists should be surrounded by blank lines +- **MD047**: Files should end with a single newline +- **MD009**: No trailing spaces + +## Validation Commands + +### Check Single File + +```bash +npx markdownlint docs/filename.md +``` + +### Check All Documentation + +```bash +npx markdownlint docs/ +``` + +### Auto-fix Common Issues + +```bash +# Remove trailing spaces +sed -i 's/[[:space:]]*$//' docs/filename.md + +# Remove multiple blank lines +sed -i '/^$/N;/^\n$/D' docs/filename.md + +# Add newline at end if missing +echo "" >> docs/filename.md +``` + +## Common Patterns + +### Implementation Plans + +```markdown +## Implementation Plan + +### Phase 1: Foundation (Day 1) + +#### 1.1 Component Setup + +- [ ] Create new component file +- [ ] Add basic structure +- [ ] Implement core functionality + +#### 1.2 Configuration + +- [ ] Update configuration files +- [ ] Add environment variables +- [ ] Test configuration loading +``` + +### Status Tracking + +```markdown +**Status**: ✅ **COMPLETE** - All phases finished +**Progress**: 75% (15/20 components) +**Next**: Ready for testing phase +``` + +### Performance Metrics + +```markdown +#### 📊 Performance Metrics +- **Build Time**: 2.3 seconds (50% faster than baseline) +- **Bundle Size**: 1.2MB (30% reduction) +- **Success Rate**: 100% (no failures in 50 builds) +``` + +## Enforcement + +### Pre-commit Hooks + +- Run markdownlint on all changed markdown files +- Block commits with linting violations +- Auto-fix common issues when possible + +### CI/CD Integration + +- Include markdownlint in build pipeline +- Generate reports for documentation quality +- Fail builds with critical violations + +### Team Guidelines + +- All documentation PRs must pass markdownlint +- Use provided templates for new documents +- Follow established patterns for consistency + +## Templates + +### New Document Template + +```markdown +# Document Title + +**Author**: Matthew Raymer +**Date**: YYYY-MM-DD +**Status**: 🎯 **PLANNING** - Ready for Implementation + +## Overview + +Brief description of the document's purpose and scope. + +## Current State + +Description of current situation or problem. + +## Implementation Plan + +### Phase 1: Foundation + +- [ ] Task 1 +- [ ] Task 2 + +## Next Steps + +1. **Review and approve plan** +2. **Begin implementation** +3. **Test and validate** + +--- + +**Status**: Ready for implementation +**Priority**: Medium +**Estimated Effort**: X days +**Dependencies**: None +**Stakeholders**: Development team +``` + +--- + +**Last Updated**: 2025-07-09 +**Version**: 1.0 +**Maintainer**: Matthew Raymer diff --git a/.cursor/rules/markdown.mdc b/.cursor/rules/markdown.mdc new file mode 100644 index 00000000..814106d9 --- /dev/null +++ b/.cursor/rules/markdown.mdc @@ -0,0 +1,314 @@ +--- +globs: *.md +alwaysApply: false +--- +# Cursor Markdown Ruleset for TimeSafari Documentation + +## Overview + +This ruleset enforces consistent markdown formatting standards across all project +documentation, ensuring readability, maintainability, and compliance with +markdownlint best practices. + +## General Formatting Standards + +### Line Length + +- **Maximum line length**: 80 characters +- **Exception**: Code blocks (JSON, shell, TypeScript, etc.) - no line length + enforcement +- **Rationale**: Ensures readability across different screen sizes and terminal + widths + +### Blank Lines + +- **Headings**: Must be surrounded by blank lines above and below +- **Lists**: Must be surrounded by blank lines above and below +- **Code blocks**: Must be surrounded by blank lines above and below +- **Maximum consecutive blank lines**: 1 (no multiple blank lines) +- **File start**: No blank lines at the beginning of the file +- **File end**: Single newline character at the end + +### Whitespace + +- **No trailing spaces**: Remove all trailing whitespace from lines +- **No tabs**: Use spaces for indentation +- **Consistent indentation**: 2 spaces for list items and nested content + +## Heading Standards + +### Format + +- **Style**: ATX-style headings (`#`, `##`, `###`, etc.) +- **Case**: Title case for general headings +- **Code references**: Use backticks for file names and technical terms + - ✅ `### Current package.json Scripts` + - ❌ `### Current Package.json Scripts` + +### Hierarchy + +- **H1 (#)**: Document title only +- **H2 (##)**: Major sections +- **H3 (###)**: Subsections +- **H4 (####)**: Sub-subsections +- **H5+**: Avoid deeper nesting + +## List Standards + +### Unordered Lists + +- **Marker**: Use `-` (hyphen) consistently +- **Indentation**: 2 spaces for nested items +- **Blank lines**: Surround lists with blank lines + +### Ordered Lists + +- **Format**: `1.`, `2.`, `3.` (sequential numbering) +- **Indentation**: 2 spaces for nested items +- **Blank lines**: Surround lists with blank lines + +### Task Lists + +- **Format**: `- [ ]` for incomplete, `- [x]` for complete +- **Use case**: Project planning, checklists, implementation tracking + +## Code Block Standards + +### Fenced Code Blocks + +- **Syntax**: Triple backticks with language specification +- **Languages**: `json`, `bash`, `typescript`, `javascript`, `yaml`, `markdown` +- **Blank lines**: Must be surrounded by blank lines above and below +- **Line length**: No enforcement within code blocks + +### Inline Code + +- **Format**: Single backticks for inline code references +- **Use case**: File names, commands, variables, properties + +## Special Content Standards + +### JSON Examples + +```json +{ + "property": "value", + "nested": { + "property": "value" + } +} +``` + +### Shell Commands + +```bash +# Command with comment +npm run build:web + +# Multi-line command +VITE_GIT_HASH=`git log -1 --pretty=format:%h` \ + vite build --config vite.config.web.mts +``` + +### TypeScript Examples + +```typescript +// Function with JSDoc +/** + * Get environment configuration + * @param env - Environment name + * @returns Environment config object + */ +const getEnvironmentConfig = (env: string) => { + switch (env) { + case 'prod': + return { /* production settings */ }; + default: + return { /* development settings */ }; + } +}; +``` + +## File Structure Standards + +### Document Header + +```markdown +# Document Title + +**Author**: Matthew Raymer +**Date**: YYYY-MM-DD +**Status**: 🎯 **STATUS** - Brief description + +## Overview + +Brief description of the document's purpose and scope. +``` + +### Section Organization + +1. **Overview/Introduction** +2. **Current State Analysis** +3. **Implementation Plan** +4. **Technical Details** +5. **Testing & Validation** +6. **Next Steps** + +## Markdownlint Configuration + +### Required Rules + +```json +{ + "MD013": { "code_blocks": false }, + "MD012": true, + "MD022": true, + "MD031": true, + "MD032": true, + "MD047": true, + "MD009": true +} +``` + +### Rule Explanations + +- **MD013**: Line length (disabled for code blocks) +- **MD012**: No multiple consecutive blank lines +- **MD022**: Headings should be surrounded by blank lines +- **MD031**: Fenced code blocks should be surrounded by blank lines +- **MD032**: Lists should be surrounded by blank lines +- **MD047**: Files should end with a single newline +- **MD009**: No trailing spaces + +## Validation Commands + +### Check Single File + +```bash +npx markdownlint docs/filename.md +``` + +### Check All Documentation + +```bash +npx markdownlint docs/ +``` + +### Auto-fix Common Issues + +```bash +# Remove trailing spaces +sed -i 's/[[:space:]]*$//' docs/filename.md + +# Remove multiple blank lines +sed -i '/^$/N;/^\n$/D' docs/filename.md + +# Add newline at end if missing +echo "" >> docs/filename.md +``` + +## Common Patterns + +### Implementation Plans + +```markdown +## Implementation Plan + +### Phase 1: Foundation (Day 1) + +#### 1.1 Component Setup + +- [ ] Create new component file +- [ ] Add basic structure +- [ ] Implement core functionality + +#### 1.2 Configuration + +- [ ] Update configuration files +- [ ] Add environment variables +- [ ] Test configuration loading +``` + +### Status Tracking + +```markdown +**Status**: ✅ **COMPLETE** - All phases finished +**Progress**: 75% (15/20 components) +**Next**: Ready for testing phase +``` + +### Performance Metrics + +```markdown +#### 📊 Performance Metrics +- **Build Time**: 2.3 seconds (50% faster than baseline) +- **Bundle Size**: 1.2MB (30% reduction) +- **Success Rate**: 100% (no failures in 50 builds) +``` + +## Enforcement + +### Pre-commit Hooks + +- Run markdownlint on all changed markdown files +- Block commits with linting violations +- Auto-fix common issues when possible + +### CI/CD Integration + +- Include markdownlint in build pipeline +- Generate reports for documentation quality +- Fail builds with critical violations + +### Team Guidelines + +- All documentation PRs must pass markdownlint +- Use provided templates for new documents +- Follow established patterns for consistency + +## Templates + +### New Document Template + +```markdown +# Document Title + +**Author**: Matthew Raymer +**Date**: YYYY-MM-DD +**Status**: 🎯 **PLANNING** - Ready for Implementation + +## Overview + +Brief description of the document's purpose and scope. + +## Current State + +Description of current situation or problem. + +## Implementation Plan + +### Phase 1: Foundation + +- [ ] Task 1 +- [ ] Task 2 + +## Next Steps + +1. **Review and approve plan** +2. **Begin implementation** +3. **Test and validate** + +--- + +**Status**: Ready for implementation +**Priority**: Medium +**Estimated Effort**: X days +**Dependencies**: None +**Stakeholders**: Development team +``` + +--- + +**Last Updated**: 2025-07-09 +**Version**: 1.0 +**Maintainer**: Matthew Raymer diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..2f71b81b --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1 @@ +{"MD013": {"code_blocks": false}} diff --git a/docs/build-pattern-conversion-plan.md b/docs/build-pattern-conversion-plan.md new file mode 100644 index 00000000..0a58247f --- /dev/null +++ b/docs/build-pattern-conversion-plan.md @@ -0,0 +1,569 @@ +# Build Pattern Conversion Plan + +**Author**: Matthew Raymer +**Date**: 2025-07-09 +**Status**: 🎯 **PLANNING** - Ready for Implementation + +## Overview + +Convert TimeSafari's build instruction pattern from the current script-based +approach to a new Vite `mode`-based pattern that provides better environment +management and consistency across all build targets. + +## Why Vite Mode Instead of NODE_ENV? + +### ✅ Vite's Native Mode System + +Vite is designed to work with `mode`, which: + +- Determines the `.env` file to load (e.g. `.env.production`, `.env.test`, etc.) +- Is passed to `defineConfig(({ mode }) => {...})` in `vite.config.ts` +- Is used to set behavior for dev/prod/test at config level +- Provides better integration with Vite's build system + +### 🚫 NODE_ENV Limitations + +`NODE_ENV` is legacy from Webpack-era tooling: + +- You can't change `NODE_ENV` manually and expect Vite to adapt +- Vite does not map `NODE_ENV` back to `mode` +- It's redundant with `mode` and might conflict with assumptions +- Limited integration with Vite's environment loading system + +### Usage Pattern + +```bash +# ✅ Correct: Use Vite's mode system +vite build --mode production +vite build --mode development +vite build --mode test + +# ⚠️ Only if third-party libraries require NODE_ENV +NODE_ENV=production vite build --mode production +``` + +### Development vs Build Environments + +**Development Environment:** +- **Build with defaults**: `npm run build:*` - Uses `--mode development` by default +- **Purpose**: Development builds for testing and debugging +- **Output**: Bundled files with development optimizations + +**Testing/Production Environments:** +- **Build with explicit mode**: `npm run build:* -- --mode test/production` +- **Purpose**: Validate and deploy the bundled application +- **Output**: Optimized, bundled files for specific environment + +### Mode Override Behavior + +**How `--mode` Override Works:** + +```bash +# Base script (no hardcoded mode) +"build:electron": "vite build --config vite.config.electron.mts" + +# Development (uses Vite's default: --mode development) +npm run build:electron +# Executes: vite build --config vite.config.electron.mts + +# Testing (explicitly overrides with --mode test) +npm run build:electron -- --mode test +# Executes: vite build --config vite.config.electron.mts --mode test + +# Production (explicitly overrides with --mode production) +npm run build:electron -- --mode production +# Executes: vite build --config vite.config.electron.mts --mode production +``` + +**Key Points:** +- Base scripts have **no hardcoded `--mode`** to allow override +- `npm run build:electron` defaults to `--mode development` +- `npm run build:electron -- --mode test` overrides to `--mode test` +- Vite uses the **last `--mode` argument** if multiple are provided + +### Capacitor Platform-Specific Commands + +Capacitor requires platform-specific sync commands after building: + +```bash +# General sync (copies web assets to all platforms) +npm run build:capacitor && npx cap sync + +# Platform-specific sync +npm run build:capacitor && npx cap sync android +npm run build:capacitor && npx cap sync ios + +# Environment-specific with platform sync +npm run build:capacitor -- --mode production && npx cap sync android +npm run build:capacitor -- --mode development && npx cap sync ios +``` + +### Electron Platform-Specific Commands + +Electron requires platform-specific build commands after the Vite build: + +```bash +# General Electron build (Vite build only) +npm run build:electron + +# Platform-specific builds +npm run build:electron:windows # Windows executable +npm run build:electron:mac # macOS app bundle +npm run build:electron:linux # Linux executable + +# Package-specific builds +npm run build:electron:appimage # Linux AppImage +npm run build:electron:dmg # macOS DMG installer + +# Environment-specific builds +npm run build:electron -- --mode development +npm run build:electron -- --mode test +npm run build:electron -- --mode production + +# Environment-specific with platform builds +npm run build:electron:windows -- --mode development +npm run build:electron:windows -- --mode test +npm run build:electron:windows -- --mode production + +npm run build:electron:mac -- --mode development +npm run build:electron:mac -- --mode test +npm run build:electron:mac -- --mode production + +npm run build:electron:linux -- --mode development +npm run build:electron:linux -- --mode test +npm run build:electron:linux -- --mode production + +# Environment-specific with package builds +npm run build:electron:appimage -- --mode development +npm run build:electron:appimage -- --mode test +npm run build:electron:appimage -- --mode production + +npm run build:electron:dmg -- --mode development +npm run build:electron:dmg -- --mode test +npm run build:electron:dmg -- --mode production +``` + +## Current State Analysis + +### Existing Build Scripts + +- **Web**: `build:web` - Uses vite.config.web.mts +- **Capacitor**: `build:capacitor` - Uses vite.config.capacitor.mts + - **Android**: `build:android` - Shell script wrapper + - **iOS**: `build:ios` - Shell script wrapper +- **Electron**: `build:electron` - Uses vite.config.electron.mts + - **Windows**: `build:electron:windows` - Windows executable + - **macOS**: `build:electron:mac` - macOS app bundle + - **Linux**: `build:electron:linux` - Linux executable + - **AppImage**: `build:electron:appimage` - Linux AppImage + - **DMG**: `build:electron:dmg` - macOS DMG installer + +### Current `package.json` Scripts + +```json +{ + "build:capacitor": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode capacitor --config vite.config.capacitor.mts", + "build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts", + "build:electron": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode electron --config vite.config.electron.mts" +} +``` + +## Target Pattern + +### New Vite Mode-Based Pattern + +```bash +# Development builds (defaults to --mode development) +npm run build:web-dev +npm run build:capacitor-dev +npm run build:electron-dev + +# Testing builds (bundle required) +npm run build:web -- --mode test +npm run build:capacitor -- --mode test && npx cap sync +npm run build:electron -- --mode test + +# Production builds (bundle required) +npm run build:web -- --mode production +npm run build:capacitor -- --mode production && npx cap sync +npm run build:electron -- --mode production + +# Docker builds +npm run build:web-docker -- --mode test +npm run build:web-docker -- --mode production + +# Capacitor platform-specific builds +npm run build:capacitor:android -- --mode test +npm run build:capacitor:android -- --mode production + +npm run build:capacitor:ios -- --mode test +npm run build:capacitor:ios -- --mode production + +# Electron platform-specific builds +npm run build:electron:windows -- --mode test +npm run build:electron:windows -- --mode production + +npm run build:electron:mac -- --mode test +npm run build:electron:mac -- --mode production + +npm run build:electron:linux -- --mode test +npm run build:electron:linux -- --mode production + +# Electron package-specific builds +npm run build:electron:appimage -- --mode test +npm run build:electron:appimage -- --mode production + +npm run build:electron:dmg -- --mode test +npm run build:electron:dmg -- --mode production +``` + +### New `package.json` Scripts Structure + +```json +{ + "build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts", + "build:web:dev": "npm run build:web", + "build:web:test": "npm run build:web -- --mode test", + "build:web:prod": "npm run build:web -- --mode production" + "build:web:docker": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts", + "build:web:docker:test": "npm run build:web:docker -- --mode test", + "build:web:docker:prod": "npm run build:web:docker -- --mode production", + + "build:capacitor": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode capacitor --config vite.config.capacitor.mts", + "build:capacitor-dev": "npm run build:capacitor", + "build:capacitor:sync": "npm run build:capacitor && npx cap sync", + "build:capacitor:android": "npm run build:capacitor:sync && npx cap sync android", + "build:capacitor:ios": "npm run build:capacitor:sync && npx cap sync ios", + + "build:electron": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.electron.mts", + "build:electron:dev": "npm run build:electron && cd electron && npm run electron:start", + "build:electron:windows": "npm run build:electron && cd electron && npm run build:windows", + "build:electron:mac": "npm run build:electron && cd electron && npm run build:mac", + "build:electron:linux": "npm run build:electron && cd electron && npm run build:linux", + "build:electron:appimage": "npm run build:electron:linux && cd electron && npm run build:appimage", + "build:electron:dmg": "npm run build:electron:mac && cd electron && npm run build:dmg" +} +``` + +## Implementation Plan + +### Phase 1: Environment Configuration (Day 1) + +#### 1.1 Update Vite Configurations + +- [ ] **vite.config.web.mts**: Add mode-based configuration +- [ ] **vite.config.capacitor.mts**: Add mode-based configuration +- [ ] **vite.config.electron.mts**: Add mode-based configuration +- [ ] **vite.config.common.mts**: Add environment-specific variables + +#### 1.2 Environment Variables Setup + +- [ ] Create `.env.development` file for development settings +- [ ] Create `.env.test` file for testing settings +- [ ] Create `.env.production` file for production settings +- [ ] Update `.env.example` with new pattern + +#### 1.3 Environment Detection Logic + +```typescript +// vite.config.common.mts +export default defineConfig(({ mode }) => { + const getEnvironmentConfig = (mode: string) => { + switch (mode) { + case 'production': + return { /* production settings */ }; + case 'test': + return { /* testing settings */ }; + default: + return { /* development settings */ }; + } + }; + + return { + define: { + __DEV__: mode === 'development', + __TEST__: mode === 'test', + __PROD__: mode === 'production' + }, + // ... other config + }; +}); +``` + +### Phase 2: Package.json Scripts Update (Day 1) + +#### 2.1 Web Build Scripts + +```json +{ + "build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts", + "build:web-dev": "npm run build:web", + "build:web-test": "npm run build:web -- --mode test", + "build:web-prod": "npm run build:web -- --mode production" +} +``` + +#### 2.2 Capacitor Build Scripts + +```json +{ + "build:capacitor": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode capacitor --config vite.config.capacitor.mts", + "build:capacitor-dev": "npm run build:capacitor", + "build:capacitor:sync": "npm run build:capacitor && npx cap sync", + "build:capacitor:android": "npm run build:capacitor:sync && npx cap sync android", + "build:capacitor:ios": "npm run build:capacitor:sync && npx cap sync ios", + "build:capacitor-test": "npm run build:capacitor -- --mode test && npx cap sync", + "build:capacitor-prod": "npm run build:capacitor -- --mode production && npx cap sync", + "build:capacitor:android-test": "npm run build:capacitor -- --mode test && npx cap sync android", + "build:capacitor:android-prod": "npm run build:capacitor -- --mode production && npx cap sync android", + "build:capacitor:ios-test": "npm run build:capacitor -- --mode test && npx cap sync ios", + "build:capacitor:ios-prod": "npm run build:capacitor -- --mode production && npx cap sync ios" +} +``` + +#### 2.3 Electron Build Scripts + +```json +{ + "build:electron": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.electron.mts", + "build:electron-dev": "npm run build:electron", + "build:electron:windows": "npm run build:electron && cd electron && npm run build:windows", + "build:electron:mac": "npm run build:electron && cd electron && npm run build:mac", + "build:electron:linux": "npm run build:electron && cd electron && npm run build:linux", + "build:electron:appimage": "npm run build:electron:linux && cd electron && npm run build:appimage", + "build:electron:dmg": "npm run build:electron:mac && cd electron && npm run build:dmg", + "build:electron-test": "npm run build:electron -- --mode test", + "build:electron-prod": "npm run build:electron -- --mode production", + "build:electron:windows-test": "npm run build:electron -- --mode test && cd electron && npm run build:windows", + "build:electron:windows-prod": "npm run build:electron -- --mode production && cd electron && npm run build:windows", + "build:electron:mac-dev": "npm run build:electron -- --mode development && cd electron && npm run build:mac", + "build:electron:mac-test": "npm run build:electron -- --mode test && cd electron && npm run build:mac", + "build:electron:mac-prod": "npm run build:electron -- --mode production && cd electron && npm run build:mac", + "build:electron:linux-test": "npm run build:electron -- --mode test && cd electron && npm run build:linux", + "build:electron:linux-prod": "npm run build:electron -- --mode production && cd electron && npm run build:linux" +} +``` + +#### 2.4 Docker Build Scripts + +```json +{ + "build:web-docker": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts", + "build:web-docker-test": "npm run build:web-docker -- --mode test", + "build:web-docker-prod": "npm run build:web-docker -- --mode production" +} +``` + +### Phase 3: Shell Script Updates (Day 2) + +#### 3.1 Update build-electron.sh + +- [ ] Add mode-based environment support +- [ ] Update environment loading logic +- [ ] Add environment-specific build paths +- [ ] Update logging to show environment + +#### 3.2 Update build-android.sh + +- [ ] Add mode-based environment support +- [ ] Update environment detection +- [ ] Add environment-specific configurations + +#### 3.3 Update build-ios.sh + +- [ ] Add mode-based environment support +- [ ] Update environment detection +- [ ] Add environment-specific configurations + +### Phase 4: Documentation Updates (Day 2) + +#### 4.1 Update BUILDING.md + +- [ ] Document new Vite mode-based pattern +- [ ] Update build instructions +- [ ] Add environment-specific examples +- [ ] Update troubleshooting section + +#### 4.2 Update scripts/README.md + +- [ ] Document new Vite mode-based build patterns +- [ ] Update usage examples +- [ ] Add environment configuration guide + +#### 4.3 Update CI/CD Documentation + +- [ ] Update GitHub Actions workflows +- [ ] Update Docker build instructions +- [ ] Update deployment guides + +### Phase 5: Testing & Validation (Day 3) + +#### 5.1 Environment Testing + +- [ ] Test dev environment builds +- [ ] Test test environment builds +- [ ] Test prod environment builds +- [ ] Validate environment variables + +#### 5.2 Platform Testing + +- [ ] Test web builds across environments +- [ ] Test capacitor builds across environments +- [ ] Test capacitor android sync across environments +- [ ] Test capacitor ios sync across environments +- [ ] Test electron builds across environments +- [ ] Test electron windows builds across environments +- [ ] Test electron mac builds across environments +- [ ] Test electron linux builds across environments +- [ ] Test electron appimage builds across environments +- [ ] Test electron dmg builds across environments +- [ ] Test docker builds across environments + +#### 5.3 Integration Testing + +- [ ] Test with existing CI/CD pipelines +- [ ] Test with existing deployment scripts +- [ ] Test with existing development workflows + +## Environment-Specific Configurations + +### Development Environment (--mode development) + +```typescript +{ + VITE_API_URL: 'http://localhost:3000', + VITE_DEBUG: 'true', + VITE_LOG_LEVEL: 'debug', + VITE_ENABLE_DEV_TOOLS: 'true' +} +``` + +### Testing Environment (--mode test) + +```typescript +{ + VITE_API_URL: 'https://test-api.timesafari.com', + VITE_DEBUG: 'false', + VITE_LOG_LEVEL: 'info', + VITE_ENABLE_DEV_TOOLS: 'false' +} +``` + +### Production Environment (--mode production) + +```typescript +{ + VITE_API_URL: 'https://api.timesafari.com', + VITE_DEBUG: 'false', + VITE_LOG_LEVEL: 'warn', + VITE_ENABLE_DEV_TOOLS: 'false' +} +``` + +## Migration Strategy + +### Backward Compatibility + +- [ ] Keep existing script names as aliases +- [ ] Add deprecation warnings for old scripts +- [ ] Maintain existing CI/CD compatibility +- [ ] Provide migration guide for users + +### Gradual Rollout + +1. **Week 1**: Implement new scripts alongside existing ones +2. **Week 2**: Update CI/CD to use new pattern +3. **Week 3**: Update documentation and guides +4. **Week 4**: Deprecate old scripts with warnings + +## Success Metrics + +### Technical Metrics + +- [ ] All builds work with Vite mode-based pattern +- [ ] Environment variables properly loaded +- [ ] Build artifacts correctly generated +- [ ] No regression in existing functionality + +### Process Metrics + +- [ ] Reduced build script complexity +- [ ] Improved environment management +- [ ] Better developer experience +- [ ] Consistent build patterns + +## Risk Assessment + +### Low Risk + +- [ ] Environment variable changes +- [ ] Package.json script updates +- [ ] Documentation updates + +### Medium Risk + +- [ ] Vite configuration changes (mode-based) +- [ ] Shell script modifications +- [ ] CI/CD pipeline updates + +### High Risk + +- [ ] Breaking existing build processes +- [ ] Environment-specific bugs +- [ ] Deployment failures + +## Rollback Plan + +### Immediate Rollback + +- [ ] Revert package.json changes +- [ ] Restore original vite configs +- [ ] Restore original shell scripts + +### Gradual Rollback + +- [ ] Keep old scripts as primary +- [ ] Use new scripts as experimental +- [ ] Gather feedback before full migration + +## Timeline + +### Day 1: Foundation + +- [ ] Environment configuration setup +- [ ] Package.json script updates +- [ ] Basic testing + +### Day 2: Integration + +- [ ] Shell script updates +- [ ] Documentation updates +- [ ] Integration testing + +### Day 3: Validation + +- [ ] Comprehensive testing +- [ ] Performance validation +- [ ] Documentation review + +### Day 4: Deployment + +- [ ] CI/CD updates +- [ ] Production validation +- [ ] User communication + +## Next Steps + +1. **Review and approve plan** +2. **Set up development environment** +3. **Begin Phase 1 implementation** +4. **Create test cases** +5. **Start implementation** + +--- + +**Status**: Ready for implementation +**Priority**: Medium +**Estimated Effort**: 3-4 days +**Dependencies**: None +**Stakeholders**: Development team, DevOps team diff --git a/docs/lazy-loading-patterns.md b/docs/lazy-loading-patterns.md new file mode 100644 index 00000000..e1e3ba99 --- /dev/null +++ b/docs/lazy-loading-patterns.md @@ -0,0 +1,662 @@ +# Vue 3 + Vite + vue-facing-decorator: Lazy Loading Patterns & Best Practices + +## Overview + +This document provides comprehensive guidance on implementing lazy loading and code splitting in Vue 3 applications using Vite and `vue-facing-decorator`. The patterns demonstrated here optimize bundle size, improve initial load times, and enhance user experience through progressive loading. + +**Author:** Matthew Raymer +**Version:** 1.0.0 +**Last Updated:** 2024 + +## Table of Contents + +1. [Why Lazy Loading Matters](#why-lazy-loading-matters) +2. [Vite Configuration for Optimal Code Splitting](#vite-configuration-for-optimal-code-splitting) +3. [Lazy Loading Patterns](#lazy-loading-patterns) +4. [Component-Level Lazy Loading](#component-level-lazy-loading) +5. [Route-Level Lazy Loading](#route-level-lazy-loading) +6. [Library-Level Lazy Loading](#library-level-lazy-loading) +7. [Performance Monitoring](#performance-monitoring) +8. [Best Practices](#best-practices) +9. [Common Pitfalls](#common-pitfalls) +10. [Examples](#examples) + +## Why Lazy Loading Matters + +### Performance Benefits + +- **Faster Initial Load**: Only load code needed for the current view +- **Reduced Bundle Size**: Split large applications into smaller chunks +- **Better Caching**: Independent chunks can be cached separately +- **Improved User Experience**: Progressive loading with loading states + +### When to Use Lazy Loading + +✅ **Good Candidates for Lazy Loading:** +- Heavy components (data processing, 3D rendering) +- Feature-specific components (QR scanner, file uploader) +- Route-based components +- Large third-party libraries (ThreeJS, Chart.js) +- Components with conditional rendering + +❌ **Avoid Lazy Loading:** +- Core UI components used everywhere +- Small utility components +- Components needed for initial render +- Components with frequent usage patterns + +## Vite Configuration for Optimal Code Splitting + +### Enhanced Build Configuration + +```typescript +// vite.config.optimized.mts +export async function createOptimizedBuildConfig(mode: string): Promise { + return { + build: { + rollupOptions: { + output: { + // Enhanced manual chunks for better code splitting + manualChunks: { + // Vendor chunks for better caching + 'vue-vendor': ['vue', 'vue-router', 'pinia'], + 'ui-vendor': ['@fortawesome/fontawesome-svg-core', '@fortawesome/vue-fontawesome'], + 'crypto-vendor': ['@ethersproject/wallet', '@ethersproject/hdnode'], + 'sql-vendor': ['@jlongster/sql.js', 'absurd-sql', 'dexie'], + 'qr-vendor': ['qrcode', 'jsqr', 'vue-qrcode-reader'], + 'three-vendor': ['three', '@tweenjs/tween.js'], + 'utils-vendor': ['luxon', 'ramda', 'zod', 'axios'], + // Platform-specific chunks + ...(isCapacitor && { + 'capacitor-vendor': ['@capacitor/core', '@capacitor/app'] + }) + } + } + } + } + }; +} +``` + +### Key Configuration Features + +1. **Manual Chunks**: Group related dependencies for better caching +2. **Platform-Specific Chunks**: Separate native and web dependencies +3. **Vendor Separation**: Keep third-party libraries separate from app code +4. **Dynamic Imports**: Enable automatic code splitting for dynamic imports + +## Lazy Loading Patterns + +### 1. Component-Level Lazy Loading + +#### Basic Pattern with defineAsyncComponent + +```typescript +import { Component, Vue } from 'vue-facing-decorator'; +import { defineAsyncComponent } from 'vue'; + +@Component({ + name: 'LazyLoadingExample', + components: { + LazyHeavyComponent: defineAsyncComponent({ + loader: () => import('./sub-components/HeavyComponent.vue'), + loadingComponent: { + template: '
Loading...
' + }, + errorComponent: { + template: '
Failed to load
' + }, + delay: 200, + timeout: 10000 + }) + } +}) +export default class LazyLoadingExample extends Vue { + // Component logic +} +``` + +#### Advanced Pattern with Suspense + +```vue + +``` + +### 2. Conditional Loading + +```typescript +@Component({ + name: 'ConditionalLazyLoading' +}) +export default class ConditionalLazyLoading extends Vue { + showHeavyComponent = false; + showQRScanner = false; + + // Lazy load based on user interaction + async toggleHeavyComponent(): Promise { + this.showHeavyComponent = !this.showHeavyComponent; + + if (this.showHeavyComponent) { + // Preload component for better UX + await this.preloadComponent(() => import('./HeavyComponent.vue')); + } + } + + private async preloadComponent(loader: () => Promise): Promise { + try { + await loader(); + } catch (error) { + console.warn('Preload failed:', error); + } + } +} +``` + +### 3. Library-Level Lazy Loading + +```typescript +@Component({ + name: 'LibraryLazyLoading' +}) +export default class LibraryLazyLoading extends Vue { + private threeJS: any = null; + + async loadThreeJS(): Promise { + if (!this.threeJS) { + // Lazy load ThreeJS only when needed + this.threeJS = await import('three'); + console.log('ThreeJS loaded successfully'); + } + } + + async initialize3DScene(): Promise { + await this.loadThreeJS(); + + // Use ThreeJS after loading + const scene = new this.threeJS.Scene(); + // ... rest of 3D setup + } +} +``` + +## Component-Level Lazy Loading + +### Heavy Data Processing Component + +```typescript +// HeavyComponent.vue +@Component({ + name: 'HeavyComponent' +}) +export default class HeavyComponent extends Vue { + @Prop({ required: true }) readonly data!: any; + + async processData(): Promise { + // Process data in batches to avoid blocking UI + const batchSize = 10; + const items = this.data.items; + + for (let i = 0; i < items.length; i += batchSize) { + const batch = items.slice(i, i + batchSize); + await this.processBatch(batch); + + // Allow UI to update + await this.$nextTick(); + await new Promise(resolve => setTimeout(resolve, 10)); + } + } +} +``` + +### Camera-Dependent Component + +```typescript +// QRScannerComponent.vue +@Component({ + name: 'QRScannerComponent' +}) +export default class QRScannerComponent extends Vue { + async mounted(): Promise { + // Initialize camera only when component is mounted + await this.initializeCamera(); + } + + async initializeCamera(): Promise { + try { + const devices = await navigator.mediaDevices.enumerateDevices(); + this.cameras = devices.filter(device => device.kind === 'videoinput'); + this.hasCamera = this.cameras.length > 0; + } catch (error) { + console.error('Camera initialization failed:', error); + this.hasCamera = false; + } + } +} +``` + +## Route-Level Lazy Loading + +### Vue Router Configuration + +```typescript +// router/index.ts +import { createRouter, createWebHistory } from 'vue-router'; + +const routes = [ + { + path: '/', + name: 'Home', + component: () => import('@/views/HomeView.vue') + }, + { + path: '/heavy-feature', + name: 'HeavyFeature', + component: () => import('@/views/HeavyFeatureView.vue'), + // Preload on hover for better UX + beforeEnter: (to, from, next) => { + if (from.name) { + // Preload component when navigating from another route + import('@/views/HeavyFeatureView.vue'); + } + next(); + } + } +]; + +export default createRouter({ + history: createWebHistory(), + routes +}); +``` + +### Route Guards with Lazy Loading + +```typescript +// router/guards.ts +export async function lazyLoadGuard(to: any, from: any, next: any): Promise { + if (to.meta.requiresHeavyFeature) { + try { + // Preload heavy feature before navigation + await import('@/components/HeavyFeature.vue'); + next(); + } catch (error) { + console.error('Failed to load heavy feature:', error); + next('/error'); + } + } else { + next(); + } +} +``` + +## Library-Level Lazy Loading + +### Dynamic Library Loading + +```typescript +@Component({ + name: 'DynamicLibraryLoader' +}) +export default class DynamicLibraryLoader extends Vue { + private libraries: Map = new Map(); + + async loadLibrary(name: string): Promise { + if (this.libraries.has(name)) { + return this.libraries.get(name); + } + + let library: any; + + switch (name) { + case 'three': + library = await import('three'); + break; + case 'chart': + library = await import('chart.js'); + break; + case 'qr': + library = await import('jsqr'); + break; + default: + throw new Error(`Unknown library: ${name}`); + } + + this.libraries.set(name, library); + return library; + } +} +``` + +### Conditional Library Loading + +```typescript +@Component({ + name: 'ConditionalLibraryLoader' +}) +export default class ConditionalLibraryLoader extends Vue { + async loadPlatformSpecificLibrary(): Promise { + if (process.env.VITE_PLATFORM === 'capacitor') { + // Load Capacitor-specific libraries + await import('@capacitor/camera'); + await import('@capacitor/filesystem'); + } else { + // Load web-specific libraries + await import('file-saver'); + await import('jszip'); + } + } +} +``` + +## Performance Monitoring + +### Bundle Analysis + +```bash +# Analyze bundle size +npm run build +npx vite-bundle-analyzer dist + +# Monitor chunk sizes +npx vite-bundle-analyzer dist --mode=treemap +``` + +### Runtime Performance Monitoring + +```typescript +@Component({ + name: 'PerformanceMonitor' +}) +export default class PerformanceMonitor extends Vue { + private performanceMetrics = { + componentLoadTime: 0, + renderTime: 0, + memoryUsage: 0 + }; + + private measureComponentLoad(componentName: string): void { + const startTime = performance.now(); + + return () => { + const loadTime = performance.now() - startTime; + this.performanceMetrics.componentLoadTime = loadTime; + + console.log(`${componentName} loaded in ${loadTime.toFixed(2)}ms`); + + // Send to analytics + this.trackPerformance(componentName, loadTime); + }; + } + + private trackPerformance(component: string, loadTime: number): void { + // Send to analytics service + if (window.gtag) { + window.gtag('event', 'component_load', { + component_name: component, + load_time: loadTime + }); + } + } +} +``` + +## Best Practices + +### 1. Loading States + +Always provide meaningful loading states: + +```vue + +``` + +### 2. Error Handling + +Implement comprehensive error handling: + +```typescript +const LazyComponent = defineAsyncComponent({ + loader: () => import('./HeavyComponent.vue'), + errorComponent: { + template: ` +
+

Failed to load component

+

{{ error.message }}

+ +
+ `, + props: ['error'], + methods: { + retry() { + this.$emit('retry'); + } + } + }, + onError(error, retry, fail, attempts) { + if (attempts <= 3) { + console.warn(`Retrying component load (attempt ${attempts})`); + retry(); + } else { + console.error('Component failed to load after 3 attempts'); + fail(); + } + } +}); +``` + +### 3. Preloading Strategy + +Implement intelligent preloading: + +```typescript +@Component({ + name: 'SmartPreloader' +}) +export default class SmartPreloader extends Vue { + private preloadQueue: Array<() => Promise> = []; + private isPreloading = false; + + // Preload based on user behavior + onUserHover(componentLoader: () => Promise): void { + this.preloadQueue.push(componentLoader); + this.processPreloadQueue(); + } + + private async processPreloadQueue(): Promise { + if (this.isPreloading || this.preloadQueue.length === 0) return; + + this.isPreloading = true; + + while (this.preloadQueue.length > 0) { + const loader = this.preloadQueue.shift(); + if (loader) { + try { + await loader(); + } catch (error) { + console.warn('Preload failed:', error); + } + } + + // Small delay between preloads + await new Promise(resolve => setTimeout(resolve, 100)); + } + + this.isPreloading = false; + } +} +``` + +### 4. Bundle Optimization + +Optimize bundle splitting: + +```typescript +// vite.config.ts +export default defineConfig({ + build: { + rollupOptions: { + output: { + manualChunks: (id) => { + // Group by feature + if (id.includes('qr')) return 'qr-feature'; + if (id.includes('three')) return '3d-feature'; + if (id.includes('chart')) return 'chart-feature'; + + // Group by vendor + if (id.includes('node_modules')) { + if (id.includes('vue')) return 'vue-vendor'; + if (id.includes('lodash')) return 'utils-vendor'; + return 'vendor'; + } + } + } + } + } +}); +``` + +## Common Pitfalls + +### 1. Over-Lazy Loading + +❌ **Don't lazy load everything:** +```typescript +// Bad: Lazy loading small components +const SmallButton = defineAsyncComponent(() => import('./SmallButton.vue')); +``` + +✅ **Do lazy load strategically:** +```typescript +// Good: Lazy load heavy components only +const HeavyDataProcessor = defineAsyncComponent(() => import('./HeavyDataProcessor.vue')); +``` + +### 2. Missing Loading States + +❌ **Don't leave users hanging:** +```vue + +``` + +✅ **Do provide loading feedback:** +```vue + +``` + +### 3. Ignoring Error States + +❌ **Don't ignore loading failures:** +```typescript +const LazyComponent = defineAsyncComponent(() => import('./Component.vue')); +``` + +✅ **Do handle errors gracefully:** +```typescript +const LazyComponent = defineAsyncComponent({ + loader: () => import('./Component.vue'), + errorComponent: ErrorFallback, + onError: (error, retry, fail) => { + console.error('Component load failed:', error); + // Retry once, then fail + retry(); + } +}); +``` + +## Examples + +### Complete Lazy Loading Example + +See the following files for complete working examples: + +1. **`src/components/LazyLoadingExample.vue`** - Main example component +2. **`src/components/sub-components/HeavyComponent.vue`** - Data processing component +3. **`src/components/sub-components/QRScannerComponent.vue`** - Camera-dependent component +4. **`src/components/sub-components/ThreeJSViewer.vue`** - 3D rendering component +5. **`vite.config.optimized.mts`** - Optimized Vite configuration + +### Usage Example + +```vue + + + +``` + +## Conclusion + +Lazy loading with Vue 3 + Vite + `vue-facing-decorator` provides powerful tools for optimizing application performance. By implementing these patterns strategically, you can significantly improve initial load times while maintaining excellent user experience. + +Remember to: +- Use lazy loading for heavy components and features +- Provide meaningful loading and error states +- Monitor performance and bundle sizes +- Implement intelligent preloading strategies +- Handle errors gracefully + +For more information, see the Vue 3 documentation on [Async Components](https://vuejs.org/guide/components/async.html) and the Vite documentation on [Code Splitting](https://vitejs.dev/guide/features.html#code-splitting). \ No newline at end of file diff --git a/package.json b/package.json index 98158d2a..db6e0628 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "dev": "vite --config vite.config.dev.mts --host", "serve": "vite preview", "build": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.mts", + "build:optimized": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.optimized.mts", + "dev:optimized": "vite --config vite.config.optimized.mts --host", "lint": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src", "lint-fix": "eslint --ext .js,.ts,.vue --ignore-path .gitignore --fix src", "prebuild": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src && node sw_combine.js && node scripts/copy-wasm.js", diff --git a/src/components/LazyLoadingExample.vue b/src/components/LazyLoadingExample.vue new file mode 100644 index 00000000..6515d10b --- /dev/null +++ b/src/components/LazyLoadingExample.vue @@ -0,0 +1,293 @@ + + + + + \ No newline at end of file diff --git a/src/components/sub-components/HeavyComponent.vue b/src/components/sub-components/HeavyComponent.vue new file mode 100644 index 00000000..8ab18184 --- /dev/null +++ b/src/components/sub-components/HeavyComponent.vue @@ -0,0 +1,542 @@ + + + + + \ No newline at end of file diff --git a/src/components/sub-components/QRScannerComponent.vue b/src/components/sub-components/QRScannerComponent.vue new file mode 100644 index 00000000..c70a0b0d --- /dev/null +++ b/src/components/sub-components/QRScannerComponent.vue @@ -0,0 +1,708 @@ + + + + + \ No newline at end of file diff --git a/src/components/sub-components/ThreeJSViewer.vue b/src/components/sub-components/ThreeJSViewer.vue new file mode 100644 index 00000000..ae9c1e4b --- /dev/null +++ b/src/components/sub-components/ThreeJSViewer.vue @@ -0,0 +1,657 @@ + + + + + \ No newline at end of file diff --git a/vite.config.optimized.mts b/vite.config.optimized.mts new file mode 100644 index 00000000..a2b22a2a --- /dev/null +++ b/vite.config.optimized.mts @@ -0,0 +1,151 @@ +import { defineConfig, UserConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import dotenv from "dotenv"; +import { loadAppConfig } from "./vite.config.utils.mts"; +import path from "path"; +import { fileURLToPath } from 'url'; + +// Load environment variables +dotenv.config(); + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** + * Optimized Vite configuration for Vue 3 + vue-facing-decorator + * with enhanced code splitting and lazy loading capabilities + * + * @author Matthew Raymer + * @version 1.0.0 + */ +export async function createOptimizedBuildConfig(mode: string): Promise { + const appConfig = await loadAppConfig(); + const isCapacitor = mode === "capacitor"; + const isElectron = mode === "electron"; + const isNative = isCapacitor || isElectron; + + // Set platform and disable PWA for native platforms + process.env.VITE_PLATFORM = mode; + process.env.VITE_PWA_ENABLED = isNative ? 'false' : 'true'; + process.env.VITE_DISABLE_PWA = isNative ? 'true' : 'false'; + + if (isNative) { + process.env.VITE_PWA_ENABLED = 'false'; + } + + return { + base: "/", + plugins: [vue()], + server: { + port: parseInt(process.env.VITE_PORT || "8080"), + fs: { strict: false }, + // CORS headers disabled to allow images from any domain + // This means SharedArrayBuffer is unavailable, but absurd-sql + // will automatically fall back to IndexedDB mode which still works + }, + build: { + outDir: "dist", + assetsDir: 'assets', + chunkSizeWarningLimit: 1000, + rollupOptions: { + external: isNative + ? ['@capacitor/app'] + : [], + output: { + format: 'esm', + generatedCode: { + preset: 'es2015' + }, + // Enhanced manual chunks for better code splitting + manualChunks: { + // Vendor chunks for better caching + 'vue-vendor': ['vue', 'vue-router', 'pinia'], + 'ui-vendor': ['@fortawesome/fontawesome-svg-core', '@fortawesome/vue-fontawesome'], + 'crypto-vendor': ['@ethersproject/wallet', '@ethersproject/hdnode', 'ethereum-cryptography'], + 'sql-vendor': ['@jlongster/sql.js', 'absurd-sql', 'dexie'], + 'qr-vendor': ['qrcode', 'jsqr', 'vue-qrcode-reader'], + 'three-vendor': ['three', '@tweenjs/tween.js'], + 'utils-vendor': ['luxon', 'ramda', 'zod', 'axios'], + // Platform-specific chunks + ...(isCapacitor && { + 'capacitor-vendor': ['@capacitor/core', '@capacitor/app', '@capacitor/camera'] + }), + ...(isElectron && { + 'electron-vendor': ['electron'] + }) + } + } + }, + // Optimize chunk loading + target: 'es2015', + minify: 'terser', + terserOptions: { + compress: { + drop_console: process.env.NODE_ENV === 'production', + drop_debugger: true + } + } + }, + worker: { + format: 'es', + plugins: () => [] + }, + define: { + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + 'process.env.VITE_PLATFORM': JSON.stringify(mode), + 'process.env.VITE_PWA_ENABLED': JSON.stringify(!isNative), + 'process.env.VITE_DISABLE_PWA': JSON.stringify(isNative), + __dirname: JSON.stringify(process.cwd()), + __IS_MOBILE__: JSON.stringify(isCapacitor), + __IS_ELECTRON__: JSON.stringify(isElectron), + __USE_QR_READER__: JSON.stringify(!isCapacitor), + 'process.platform': JSON.stringify('browser'), + 'process.version': JSON.stringify('v16.0.0'), + 'process.env.NODE_DEBUG': JSON.stringify(false), + 'global.process': JSON.stringify({ + platform: 'browser', + version: 'v16.0.0', + env: { NODE_DEBUG: false } + }) + }, + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + '@nostr/tools': path.resolve(__dirname, 'node_modules/@nostr/tools'), + '@nostr/tools/nip06': path.resolve(__dirname, 'node_modules/@nostr/tools/nip06'), + ...appConfig.aliasConfig, + 'path': path.resolve(__dirname, './src/utils/node-modules/path.js'), + 'fs': path.resolve(__dirname, './src/utils/node-modules/fs.js'), + 'crypto': path.resolve(__dirname, './src/utils/node-modules/crypto.js'), + 'dexie-export-import': path.resolve(__dirname, 'node_modules/dexie-export-import') + } + }, + optimizeDeps: { + include: [ + '@nostr/tools', + '@nostr/tools/nip06', + 'vue', + 'vue-router', + 'pinia', + 'vue-facing-decorator' + ], + exclude: isNative ? [ + 'register-service-worker', + 'workbox-window', + 'web-push', + 'serviceworker-webpack-plugin', + 'vite-plugin-pwa', + '@vite-pwa/vue' + ] : [] + }, + // Enhanced performance optimizations + esbuild: { + target: 'es2015', + supported: { + 'bigint': true + } + } + }; +} + +export default defineConfig(async () => createOptimizedBuildConfig('web')); \ No newline at end of file