// Platform detection example
const { platform } = require('process');
function getPlatformSpecificConfig() {
switch (platform) {
case 'win32':
return {
configFile: 'config.win.json',
pathSeparator: '\\'
};
case 'darwin':
return {
configFile: 'config.macos.json',
pathSeparator: '/'
};
case 'linux':
return {
configFile: 'config.linux.json',
pathSeparator: '/'
};
default:
throw new Error(`Unsupported platform: ${platform}`);
}
}
// Conditional compilation example (via webpack.DefinePlugin)
// webpack.config.js
new webpack.DefinePlugin({
IS_WINDOWS: JSON.stringify(process.platform === 'win32'),
IS_MAC: JSON.stringify(process.platform === 'darwin')
});
// Usage example
if (IS_WINDOWS) {
// Windows-specific logic
} else if (IS_MAC) {
// macOS-specific logic
}
Path Handling Best Practices
const path = require('path');
// Use path.join instead of string concatenation
const configPath = path.join(__dirname, 'config', getPlatformSpecificConfig().configFile);
// Handle user directory
const userDataPath = app.getPath('userData');
const dbPath = path.join(userDataPath, 'database.sqlite');
Precompiled Binary Management
// package.json configuration example
{
"name": "native-addon",
"binary": {
"module_name": "nativeAddon",
"module_path": "./lib/binding/{node_abi}-{platform}-{arch}",
"host": "https://github.com/username/native-addon/releases/download",
"remote_path": "./{version}",
"package_name": "{node_abi}-{platform}-{arch}.tar.gz"
}
}
// native-addon.cc
#include <node_api.h>
#ifdef _WIN32
#include <windows.h>
#elif __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#elif __linux__
#include <unistd.h>
#endif
napi_value GetPlatformInfo(napi_env env, napi_callback_info info) {
napi_value result;
char platformInfo[50];
#ifdef _WIN32
snprintf(platformInfo, sizeof(platformInfo), "Windows %d", GetVersion());
#elif __APPLE__
snprintf(platformInfo, sizeof(platformInfo), "macOS %s", "10.15");
#elif __linux__
snprintf(platformInfo, sizeof(platformInfo), "Linux %s", "5.4.0");
#endif
napi_create_string_utf8(env, platformInfo, NAPI_AUTO_LENGTH, &result);
return result;
}
NAPI_MODULE_INIT() {
napi_value fn;
napi_create_function(env, NULL, 0, GetPlatformInfo, NULL, &fn);
napi_set_named_property(env, exports, "getPlatformInfo", fn);
return exports;
}
Library Selection Principles
- Prefer Pure JavaScript Libraries
- Check os/cpu Fields in package.json
- Verify Native Module Support for Target Platforms
Solutions for Common Issues
// Handle file system differences
const fs = require('fs');
const os = require('os');
function getSafeConfigPath() {
let configDir;
switch (process.platform) {
case 'win32':
configDir = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
break;
case 'darwin':
configDir = path.join(os.homedir(), 'Library', 'Application Support');
break;
case 'linux':
configDir = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
break;
}
return path.join(configDir, 'myapp', 'config.json');
}
// Handle path separator differences
function normalizePath(filePath) {
return filePath.replace(/[\\/]+/g, path.sep);
}
Testing Matrix Design
| Test Type | Windows | macOS | Linux |
|---|
| Unit Tests | ✓ | ✓ | ✓ |
| Integration Tests | ✓ | ✓ | ✓ |
| E2E Tests | ✓ | ✓ | ✓ |
| Performance Tests | ✓ | ✓ | ✓ |
| Installation Package Tests | ✓ | ✓ | ✓ |
Automated Testing Configuration
# GitHub Actions cross-platform testing configuration
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16.x]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
- name: Run E2E tests
uses: cypress-io/github-action@v2
with:
start: npm start
wait-on: 'http://localhost:3000'
// Adjust rendering strategy based on platform
function getRenderConfig() {
const config = {
webPreferences: {
nodeIntegration: false,
contextIsolation: true
}
};
if (process.platform === 'win32') {
// Windows-specific optimization
config.webPreferences.offscreen = true; // Offscreen rendering
} else if (process.platform === 'darwin') {
// macOS-specific optimization
config.webPreferences.backgroundThrottling = false; // Disable background throttling
}
return config;
}
// Create optimized window
const win = new BrowserWindow(getRenderConfig());
Real-Time Application Development
WebSocket and Real-Time Data Updates
WebSocket Integration Solution
// Main process WebSocket management
const { ipcMain } = require('electron');
const WebSocket = require('ws');
let wsClient = null;
ipcMain.handle('ws:connect', (event, url) => {
wsClient = new WebSocket(url);
wsClient.on('message', (data) => {
// Broadcast to all renderer processes
mainWindow.webContents.send('ws:message', data);
});
});
ipcMain.handle('ws:send', (event, message) => {
if (wsClient && wsClient.readyState === WebSocket.OPEN) {
wsClient.send(JSON.stringify(message));
}
});
// Renderer process usage
window.electronAPI.onWSMessage((event, data) => {
console.log('Received WebSocket message:', data);
});
function sendWSMessage(message) {
window.electronAPI.sendWSMessage(message);
}
GraphQL Integration with Electron
Apollo Client Integration
// src/renderer/apolloClient.js
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { split } from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
const httpLink = new HttpLink({
uri: 'http://localhost:4000/graphql',
});
const wsLink = new WebSocketLink({
uri: `ws://localhost:4000/graphql`,
options: {
reconnect: true
}
});
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink
);
export const apolloClient = new ApolloClient({
link: splitLink,
cache: new InMemoryCache()
});
Real-Time Collaborative Editing Implementation
CRDT Algorithm Integration
// Implementing CRDT collaboration with Yjs
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';
// Create shared document
const ydoc = new Y.Doc();
const provider = new WebsocketProvider(
'ws://localhost:1234',
'room-name',
ydoc
);
// Get shared type
const ytext = ydoc.getText('document');
// Monitor local changes
ytext.observe(event => {
console.log('Local modification:', event);
});
// Monitor remote changes
provider.on('sync', (isSynced) => {
if (isSynced) {
console.log('Document synchronized');
}
});
// Usage in React component
function CollaborativeEditor() {
const [content, setContent] = useState('');
useEffect(() => {
// Sync Yjs document to local state
const updateContent = () => {
setContent(ytext.toString());
};
ytext.observe(updateContent);
return () => ytext.unobserve(updateContent);
}, []);
const handleChange = (e) => {
const newText = e.target.value;
ytext.delete(0, ytext.length);
ytext.insert(0, newText);
};
return <textarea value={content} onChange={handleChange} />;
}
Message Compression and Batching
// Message batching implementation
class MessageBatcher {
constructor(sendFn, delay = 50) {
this.batch = [];
this.sendFn = sendFn;
this.timer = null;
this.delay = delay;
}
add(message) {
this.batch.push(message);
if (!this.timer) {
this.timer = setTimeout(() => this.flush(), this.delay);
}
}
flush() {
if (this.batch.length === 0) return;
// Compress messages
const compressed = this.compressMessages(this.batch);
this.sendFn(compressed);
this.batch = [];
this.timer = null;
}
compressMessages(messages) {
// Simple implementation: JSON.stringify
// Real projects may use more efficient compression algorithms
return JSON.stringify(messages);
}
}
// Usage example
const batcher = new MessageBatcher((data) => {
wsClient.send(data);
});
// Add message
batcher.add({ type: 'cursor', userId: '123', position: { x: 10, y: 20 } });
Real-Time Application Security and Permissions
Authentication and Authorization Implementation
// WebSocket authentication middleware
const jwt = require('jsonwebtoken');
function authenticateWS(socket, next) {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authentication error'));
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
socket.user = decoded;
next();
} catch (err) {
next(new Error('Invalid token'));
}
}
// Create secure WebSocket server
const wss = new WebSocket.Server({
port: 1234,
verifyClient: (info, callback) => {
// Verification during HTTP upgrade request
const token = info.req.headers['sec-websocket-protocol'];
// ...verification logic
}
});
wss.on('connection', authenticateWS, (ws) => {
// Authenticated connection
ws.on('message', (message) => {
// Handle messages...
});
});
Enterprise-Grade Application Development
Complex State Management
Redux Saga Implementation
// src/renderer/store/sagas.js
import { call, put, takeEvery } from 'redux-saga/effects';
import { fetchDataSuccess, fetchDataFailure } from './actions';
import api from '../api';
function* fetchDataSaga(action) {
try {
const data = yield call(api.fetchData, action.payload);
yield put(fetchDataSuccess(data));
} catch (error) {
yield put(fetchDataFailure(error.message));
}
}
export default function* rootSaga() {
yield takeEvery('FETCH_DATA_REQUEST', fetchDataSaga);
}
// Redux Observable implementation
import { ofType } from 'redux-observable';
import { mergeMap, map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
import api from '../api';
const fetchDataEpic = (action$) =>
action$.pipe(
ofType('FETCH_DATA_REQUEST'),
mergeMap((action) =>
api.fetchData(action.payload).pipe(
map((response) => fetchDataSuccess(response.data)),
catchError((error) => of(fetchDataFailure(error.message)))
)
)
);
Data Synchronization and Conflict Resolution
Eventual Consistency Strategy
// Data synchronization manager
class DataSyncManager {
constructor() {
this.localData = {};
this.remoteData = {};
this.pendingChanges = [];
}
// Local update
localUpdate(key, value) {
this.localData[key] = value;
this.pendingChanges.push({ key, value, timestamp: Date.now() });
this.trySync();
}
// Remote update
remoteUpdate(key, value, timestamp) {
if (!this.localData[key] || this.localData[key].timestamp < timestamp) {
this.remoteData[key] = { value, timestamp };
this.applyUpdate(key, value);
} else {
// Conflict detection
this.handleConflict(key, value, timestamp);
}
}
// Attempt synchronization
trySync() {
if (navigator.onLine && this.pendingChanges.length > 0) {
const changes = [...this.pendingChanges];
this.pendingChanges = [];
api.syncChanges(changes).then((response) => {
response.conflicts.forEach((conflict) => {
this.handleConflict(conflict.key, conflict.serverValue, conflict.serverTimestamp);
});
}).catch(() => {
// Sync failure, re-queue changes
this.pendingChanges.unshift(...changes);
});
}
}
// Handle conflict
handleConflict(key, serverValue, serverTimestamp) {
// Simple strategy: Last write wins
if (serverTimestamp > this.localData[key].timestamp) {
this.applyUpdate(key, serverValue);
}
// Can be extended for more complex merge strategies
}
// Apply update
applyUpdate(key, value) {
this.localData[key] = { value, timestamp: Date.now() };
// Notify UI update
window.dispatchEvent(new CustomEvent('data-updated', { detail: { key, value } }));
}
}
Offline Support and Data Persistence
Offline-First Strategy
// Offline manager implementation
class OfflineManager {
constructor() {
this.isOnline = navigator.onLine;
this.queue = [];
window.addEventListener('online', () => this.handleOnline());
window.addEventListener('offline', () => this.handleOffline());
}
// Execute operation (automatically handles offline queue)
async executeOperation(operation) {
if (this.isOnline) {
try {
return await operation.execute();
} catch (error) {
if (error.isNetworkError) {
return this.queueOperation(operation);
}
throw error;
}
} else {
return this.queueOperation(operation);
}
}
// Queue operation
queueOperation(operation) {
return new Promise((resolve, reject) => {
this.queue.push({
operation,
resolve,
reject
});
});
}
// Handle network recovery
async handleOnline() {
this.isOnline = true;
while (this.queue.length > 0) {
const { operation, resolve, reject } = this.queue.shift();
try {
const result = await operation.execute();
resolve(result);
} catch (error) {
reject(error);
}
}
}
// Handle offline state
handleOffline() {
this.isOnline = false;
}
}
// Data persistence strategy
class DataPersistence {
constructor() {
this.db = new Dexie('AppDatabase');
this.initDB();
}
initDB() {
this.db.version(1).stores({
documents: '++id, title, content, updatedAt',
settings: 'key'
});
}
// Save document
async saveDocument(doc) {
await this.db.documents.put(doc);
// Sync to server if online
if (navigator.onLine) {
await api.saveDocument(doc);
}
}
// Get document
async getDocument(id) {
// Get from local first
let doc = await this.db.documents.get(id);
// If not found locally and online, fetch from server
if (!doc && navigator.onLine) {
doc = await api.getDocument(id);
if (doc) {
await this.db.documents.put(doc);
}
}
return doc;
}
}
Security and Permission Control
Enterprise-Grade Authentication Solution
// JWT authentication integration
import jwtDecode from 'jwt-decode';
class AuthService {
constructor() {
this.token = localStorage.getItem('token');
this.user = this.token ? jwtDecode(this.token) : null;
}
// Login
async login(credentials) {
const response = await api.login(credentials);
this.setToken(response.token);
return response;
}
// Set token
setToken(token) {
this.token = token;
this.user = jwtDecode(token);
localStorage.setItem('token', token);
// Set default authorization header for Axios
api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
}
// Logout
logout() {
this.token = null;
this.user = null;
localStorage.removeItem('token');
delete api.defaults.headers.common['Authorization'];
}
// Check permission
hasPermission(requiredPermission) {
if (!this.user) return false;
return this.user.permissions.includes(requiredPermission);
}
}
// OAuth integration
class OAuthService {
constructor(provider) {
this.provider = provider;
this.redirectUri = `${window.location.origin}/oauth/callback`;
}
// Start OAuth flow
startLogin() {
const authUrl = `https://${this.provider}.com/oauth/authorize?` +
`client_id=${process.env.OAUTH_CLIENT_ID}&` +
`redirect_uri=${encodeURIComponent(this.redirectUri)}&` +
`response_type=code&` +
`scope=openid profile email`;
window.location.href = authUrl;
}
// Handle callback
async handleCallback(code) {
const tokenResponse = await api.exchangeCodeForToken(code);
this.setToken(tokenResponse.access_token);
// Get user info
const userInfo = await api.getUserInfo();
return userInfo;
}
}
Enterprise-Grade Application Architecture Design
Modular Architecture Example
src/
├── core/ # Core infrastructure
│ ├── auth/ # Authentication and authorization
│ ├── ipc/ # Inter-process communication
│ ├── network/ # Network communication
│ └── storage/ # Data storage
├── modules/ # Business modules
│ ├── document/ # Document management module
│ ├── collaboration/ # Collaboration module
│ └── admin/ # Admin module
├── shared/ # Shared code
│ ├── components/ # Global UI components
│ ├── hooks/ # Custom hooks
│ └── utils/ # Utility functions
├── App.tsx # Application entry point
└── main.ts # Main process entry point
Micro-Frontend Integration Solution
// Main app integrating sub-apps
import { loadMicroApp } from 'qiankun';
// Define sub-apps
const subApps = [
{
name: 'document-module',
entry: '//localhost:7100',
container: '#document-container',
activeRule: '/documents'
},
{
name: 'collaboration-module',
entry: '//localhost:7200',
container: '#collaboration-container',
activeRule: '/collaborate'
}
];
// Start micro-frontend
subApps.forEach(app => {
loadMicroApp(app);
});
// Routing configuration in renderer process
<BrowserRouter>
<Routes>
<Route path="/documents/*" element={<DocumentModule />} />
<Route path="/collaborate/*" element={<CollaborationModule />} />
</Routes>
</BrowserRouter>