mirror of
https://github.com/colanode/colanode.git
synced 2026-07-10 04:19:19 +02:00
Mobile duplicated useLiveQuery, useQuery, useMutation, and buildQueryClient from packages/ui with the only difference being the executor mechanism (appService.mediator vs window.colanode). This consolidates them by: - Adding a DOM-free core-api module to packages/ui with getColanode() and getEventBus() helpers that access globalThis, avoiding Window/DOM types - Updating shared hooks and buildQueryClient to use these helpers instead of window.colanode/window.eventBus directly - Installing a globalThis.colanode bridge in mobile's _layout.tsx that delegates to appService.mediator (matching the web/desktop pattern) - Migrating all 41 mobile files to import hooks from @colanode/ui - Deleting 4 duplicate mobile files (3 hooks + query-client) - Adding Metro resolver override to force react/react-native resolution from the mobile app's node_modules (packages/ui ships a separate web-only React 19.2.4 that conflicts with mobile's RN-compatible 19.1.0) Also standardizes useQuery to use buildQueryKey instead of inline sha256. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
81 lines
2.5 KiB
JavaScript
81 lines
2.5 KiB
JavaScript
const { getDefaultConfig } = require('expo/metro-config');
|
|
const path = require('path');
|
|
|
|
const config = getDefaultConfig(__dirname);
|
|
|
|
// Allow .db and .html files to be imported as assets
|
|
config.resolver.assetExts = [...config.resolver.assetExts, 'db', 'html'];
|
|
|
|
// Modules that are never used at runtime on mobile — mock with empty export.
|
|
const EMPTY_MOCK_MODULES = [
|
|
'@tiptap/core',
|
|
'@tiptap/pm',
|
|
];
|
|
|
|
// Modules that need a functional mock (used by yjs/lib0 at runtime).
|
|
const CUSTOM_MOCKS = {
|
|
'isomorphic-webcrypto': path.resolve(
|
|
__dirname,
|
|
'src/mocks/isomorphic-webcrypto.js'
|
|
),
|
|
};
|
|
|
|
const emptyModule = path.resolve(__dirname, 'src/mocks/empty-module.js');
|
|
|
|
const originalResolveRequest = config.resolver.resolveRequest;
|
|
|
|
// Files containing syntax Hermes cannot compile (e.g. dynamic import with
|
|
// webpack magic comments). Matched against the resolved file path.
|
|
const BLOCKED_FILE_PATTERNS = [
|
|
/kysely[/\\]dist[/\\].*file-migration-provider/,
|
|
];
|
|
|
|
config.resolver.resolveRequest = (context, moduleName, platform) => {
|
|
// packages/ui ships its own web-only React (different version). Force react
|
|
// and react-native to always resolve from the mobile app's node_modules so
|
|
// there is exactly one React instance in the bundle.
|
|
if (moduleName === 'react' || moduleName.startsWith('react/') ||
|
|
moduleName === 'react-native' || moduleName.startsWith('react-native/')) {
|
|
const resolved = require.resolve(moduleName, { paths: [__dirname] });
|
|
return { filePath: resolved, type: 'sourceFile' };
|
|
}
|
|
|
|
// Empty mocks for browser-only modules
|
|
if (
|
|
EMPTY_MOCK_MODULES.some(
|
|
(m) => moduleName === m || moduleName.startsWith(m + '/')
|
|
)
|
|
) {
|
|
return {
|
|
filePath: emptyModule,
|
|
type: 'sourceFile',
|
|
};
|
|
}
|
|
|
|
// Custom mocks for modules that need partial functionality
|
|
for (const [prefix, mockPath] of Object.entries(CUSTOM_MOCKS)) {
|
|
if (moduleName === prefix || moduleName.startsWith(prefix + '/')) {
|
|
return {
|
|
filePath: mockPath,
|
|
type: 'sourceFile',
|
|
};
|
|
}
|
|
}
|
|
|
|
// Resolve normally first, then check if the result should be blocked
|
|
const resolution = originalResolveRequest
|
|
? originalResolveRequest(context, moduleName, platform)
|
|
: context.resolveRequest(context, moduleName, platform);
|
|
|
|
if (
|
|
resolution?.type === 'sourceFile' &&
|
|
BLOCKED_FILE_PATTERNS.some((re) => re.test(resolution.filePath))
|
|
) {
|
|
return { filePath: emptyModule, type: 'sourceFile' };
|
|
}
|
|
|
|
return resolution;
|
|
};
|
|
|
|
module.exports = config;
|