How Inkdown achieves true cross-platform compatibility through the bridge pattern and platform adapters
Inkdown is architected from the ground up to be truly cross-platform, capable of running on Desktop (via Tauri), Web browsers, and React Native mobile applications with a single shared codebase for business logic and plugins.
Inkdown uses the Bridge Pattern to decouple platform-agnostic core logic from platform-specific implementations. This allows the same code to run on different platforms by swapping out the implementation at runtime.
The bridge acts as a singleton that holds a reference to the platform-specific implementation. Core code calls methods on the bridge, which delegates to the registered implementation.
import { native } from '@inkdown/core';// Platform implementations register themselves at startupnative.registerModule('fs', new TauriFileSystem());native.registerModule('dialog', new TauriDialog());native.registerModule('clipboard', new TauriClipboard());// Core code uses the bridge without knowing the platformconst content = await native.fs.readFile('/path/to/file.md');
Not all platforms support all features. Use feature detection:
// Check if a module is availableif (native.supportsModule('dialog')) { await native.dialog?.showSaveDialog(options);} else { // Fallback behavior showCustomDialog(options);}// Check if a platform feature is supportedif (native.supports('nativeDialog')) { // Use native dialog} else if (native.supports('fileSystemAccess')) { // Use browser file system API} else { // Use fallback}
Always check for optional modules and features before using them to ensure graceful degradation across platforms.
import { IndexedDBStorage } from '@inkdown/storage-tauri';// Uses IndexedDB for structured storageStorageBridge.getInstance().registerStorageProviders( new IndexedDBKVStorage(), new IndexedDBDocumentStorage());
Each platform registers its implementations at startup:
import { App } from '@inkdown/core';import { native } from '@inkdown/core';import { StorageBridge } from '@inkdown/core';import { TauriFileSystem, TauriDialog, TauriClipboard, TauriPlatform, TauriConfig, TauriExport} from '@inkdown/native-tauri';import { IndexedDBKVStorage, IndexedDBDocumentStorage} from '@inkdown/storage-tauri';// Register native modulesnative.registerAll({ fs: new TauriFileSystem(), dialog: new TauriDialog(), clipboard: new TauriClipboard(), platform: new TauriPlatform(), config: new TauriConfig(), export: new TauriExport()});// Register storageStorageBridge.getInstance().registerStorageProviders( new IndexedDBKVStorage(), new IndexedDBDocumentStorage());// Create and initialize appconst app = new App(builtInPlugins);await app.init();
import type { IFileSystem } from '@inkdown/core';export class MyPlatformFileSystem implements IFileSystem { async readFile(path: string): Promise<string> { // Platform-specific implementation } async writeFile(path: string, content: string): Promise<void> { // Platform-specific implementation } // ... implement other methods}
3
Create App Entry Point
Create a platform-specific app that registers implementations:
import { App, native, StorageBridge } from '@inkdown/core';import { MyPlatformFileSystem } from './MyPlatformFileSystem';native.registerAll({ fs: new MyPlatformFileSystem(), // ... other modules});const app = new App(builtInPlugins);await app.init();
4
Test and Deploy
Test that existing plugins work without modification:
// All existing plugins should work immediatelyconst content = await native.fs.readFile('test.md');