Octech2722 57c155ea3f docs: add architecture and migration pattern documentation
Architecture Documentation:
- System component overview (logging, theme, build)
- Content processing pipeline details
- File structure and organization
- Message flow diagrams
- Storage strategy (local vs sync)
- MV3 constraints and solutions

Migration Patterns:
- 8 common MV2 → MV3 migration patterns
- TypeScript examples with proper error handling
- Chrome API usage examples
- Best practices for each scenario

Serves as reference to avoid re-explaining systems repeatedly.
2025-10-18 12:17:38 -05:00

7.0 KiB

Architecture Overview - Trilium Web Clipper MV3

System Components

Core Systems (Already Implemented)

1. Centralized Logging System

Location: src/shared/utils.ts

The extension uses a centralized logging system that aggregates logs from all contexts (background, content, popup, options).

Key Features:

  • Persistent storage in Chrome local storage
  • Maintains up to 1,000 log entries
  • Survives service worker restarts
  • Unified viewer at src/logs/

Usage Pattern:

import { Logger } from '@/shared/utils';
const logger = Logger.create('ComponentName', 'background'); // or 'content', 'popup', 'options'

logger.debug('Debug info', { data });
logger.info('Operation completed');
logger.warn('Potential issue');
logger.error('Error occurred', error);

Why It Matters: MV3 service workers terminate frequently, so console.log doesn't persist. This system ensures all debugging info is available in one place.

2. Comprehensive Theme System

Location: src/shared/theme.ts + src/shared/theme.css

Professional light/dark/system theme system with full persistence.

Features:

  • Three modes: Light, Dark, System (follows OS)
  • Persists via chrome.storage.sync
  • CSS custom properties for all colors
  • Real-time updates on OS theme change

Usage Pattern:

import { ThemeManager } from '@/shared/theme';

// Initialize (call once per context)
await ThemeManager.initialize();

// Toggle: System → Light → Dark → System
await ThemeManager.toggleTheme();

// Get current config
const config = await ThemeManager.getThemeConfig();

CSS Integration:

@import url('../shared/theme.css');

.my-component {
  background: var(--color-surface);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border);
}

Available CSS Variables:

  • --color-text-primary, --color-text-secondary, --color-text-muted
  • --color-surface, --color-surface-elevated
  • --color-border, --color-border-subtle
  • --color-primary, --color-primary-hover
  • --color-success, --color-error, --color-warning

3. Content Processing Pipeline

The extension processes web content through a three-phase pipeline:

Raw HTML from page
    ↓
Phase 1: Readability
    - Extracts article content
    - Removes ads, navigation, footers
    - Identifies main content area
    ↓
Phase 2: DOMPurify
    - Security sanitization
    - Removes dangerous elements/attributes
    - XSS protection
    ↓
Phase 3: Cheerio
    - Final cleanup and polish
    - Fixes relative URLs
    - Removes empty elements
    ↓
Clean HTML → Trilium

Libraries Used:

  • @mozilla/readability - Content extraction
  • dompurify + jsdom - Security sanitization
  • cheerio - HTML manipulation

File Structure

src/
├── background/
│   └── index.ts              # Service worker (event-driven)
├── content/
│   ├── index.ts              # Content script entry
│   ├── screenshot.ts         # Screenshot selection UI
│   └── toast.ts              # In-page notifications
├── popup/
│   ├── index.ts              # Popup logic
│   ├── popup.html            # Popup UI
│   └── popup.css             # Popup styles
├── options/
│   ├── index.ts              # Settings logic
│   ├── options.html          # Settings UI
│   └── options.css           # Settings styles
├── logs/
│   ├── logs.ts               # Log viewer logic
│   ├── logs.html             # Log viewer UI
│   └── logs.css              # Log viewer styles
└── shared/
    ├── utils.ts              # Logger + utilities
    ├── theme.ts              # Theme management
    ├── theme.css             # CSS variables
    └── types.ts              # TypeScript definitions

Message Flow

┌─────────────────┐
│  Content Script │
│   (Tab context) │
└────────┬────────┘
         │ chrome.runtime.sendMessage()
         ↓
┌─────────────────┐
│ Service Worker  │
│  (Background)   │
└────────┬────────┘
         │ Fetch API
         ↓
┌─────────────────┐
│ Trilium Server  │
│  or Desktop App │
└─────────────────┘

Key Points:

  • Content scripts can access DOM but not Trilium API
  • Service worker handles all network requests
  • Messages must be serializable (no functions/DOM nodes)
  • Always return true in listener for async sendResponse

Storage Strategy

chrome.storage.local

Used for:

  • Extension state and data
  • Centralized logs
  • Connection settings
  • Cached data
await chrome.storage.local.set({ key: value });
const { key } = await chrome.storage.local.get(['key']);

chrome.storage.sync

Used for:

  • User preferences (theme, save format)
  • Settings that should sync across devices
  • Limited to 8KB per item, 100KB total
await chrome.storage.sync.set({ preference: value });

Never Use localStorage

Not available in service workers and will cause errors.

Build System

Tool: esbuild via build.mjs
Output Format: IIFE (Immediately Invoked Function Expression)
TypeScript: Compiled to ES2020

Build Process:

  1. TypeScript files compiled to JavaScript
  2. Bundled with esbuild (no code splitting in IIFE)
  3. HTML files transformed (script refs updated)
  4. CSS and assets copied to dist/
  5. manifest.json validated and copied

Development vs Production:

  • Development (npm run dev): Source maps, watch mode, fast rebuilds
  • Production (npm run build): Minification, optimization, no source maps

Security Model

Content Security Policy

  • No inline scripts or eval()
  • No remote script loading (except CDNs in manifest)
  • All code must be bundled in extension

Input Sanitization

  • All user input passed through DOMPurify
  • HTML content sanitized before display
  • URL validation for Trilium connections

Permissions

Requested only as needed:

  • storage - For chrome.storage API
  • activeTab - Current tab access
  • scripting - Inject content scripts
  • contextMenus - Right-click menu items
  • tabs - Tab information
  • Host permissions - Trilium server URLs

MV3 Constraints

Service Worker Lifecycle

  • Terminates after 30 seconds of inactivity
  • State must be persisted, not kept in memory
  • Use chrome.alarms for scheduled tasks

No Blocking APIs

  • Cannot use synchronous XMLHttpRequest
  • Cannot block webRequest
  • Must use async/await patterns

Content Script Injection

  • Must declare in manifest OR inject programmatically
  • Cannot execute code strings (must be files)

Resource Access

  • Content scripts can't directly access extension pages
  • Must use chrome.runtime.getURL() for resources

When developing: Reference this doc for system design questions. Don't re-explain these systems in every task—just use them correctly.