Project Architecture Design
Modular and Component-Based Design Principles
Modular Architecture Design
src /
├── modules / # Feature modules directory
│ ├── auth / # Authentication module
│ │ ├── actions.ts # Redux actions
│ │ ├── reducer.ts # Redux reducer
│ │ ├── api.ts # API encapsulation
│ │ └── components / # Module components
│ ├── settings / # Settings module
│ └── ... # Other modules
├── core / # Core functionality
│ ├── ipc / # IPC communication encapsulation
│ ├── window / # Window management
│ └── utils / # Utility functions
└── shared / # Shared code
├── components / # Global components
├── hooks / # Custom hooks
└── styles / # Global styles
Component-Based Design Specifications
UI Component Categories :
Container Components: Connect state and UI
Presentational Components: Pure UI rendering
Layout Components: Page structure components
Component Design Principles :
Single Responsibility Principle
Controlled Component Pattern
Explicitly Defined Props Interfaces
Default Props and Type Checking
Separation of Responsibilities Between Main and Renderer Processes
Responsibility Matrix
Functional Area Main Process Responsibilities Renderer Process Responsibilities Application Lifecycle Manage app startup/shutdown Handle UI events Window Management Create/destroy windows UI interactions within windows System Integration File system access, native API calls Display system status Data Persistence Database operations, file read/write Form data collection Network Communication WebSocket connection management Initiate API requests Security Control Sensitive operation validation Collect user input
Communication Protocol Design
// ipcProtocol.ts - Communication protocol definition
export interface IPCProtocol {
// Main process → Renderer process
' notification:show ' : ( payload : { title : string ; body : string }) => void ;
// Renderer process → Main process
' file:open ' : ( payload : { path : string }) => Promise <{ content : string }>;
// Bidirectional communication
' data:sync ' : {
request : ( payload : { version : number }) => void ;
response : ( payload : { data : any ; version : number }) => void ;
};
}
State Management Architecture Design
Redux Integration Solution
// store/configureStore.ts
import { configureStore } from ' @reduxjs/toolkit ' ;
import { setupListeners } from ' @reduxjs/toolkit/query ' ;
import authReducer from ' ../modules/authSlice ' ;
import api from ' ../services/api ' ;
export const store = configureStore ({
reducer : {
auth : authReducer,
[api.reducerPath] : api.reducer
},
middleware : ( getDefaultMiddleware ) =>
getDefaultMiddleware (). concat (api.middleware)
});
setupListeners (store.dispatch);
// Typed hooks
export type RootState = ReturnType < typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
MobX Integration Solution
// stores/AuthStore.ts
import { makeAutoObservable } from ' mobx ' ;
class AuthStore {
user = null ;
token = '' ;
constructor () {
makeAutoObservable ( this );
}
login ( credentials : { username : string ; password : string }) {
// Async login logic
}
logout () {
this .user = null ;
this .token = '' ;
}
}
export const authStore = new AuthStore ();
Routing Architecture Design
Frontend Routing Configuration
// routers/AppRouter.tsx
import { BrowserRouter, Routes, Route } from ' react-router-dom ' ;
import MainLayout from ' ../layouts/MainLayout ' ;
import Home from ' ../pages/Home ' ;
import Settings from ' ../pages/Settings ' ;
import AuthGuard from ' ../guards/AuthGuard ' ;
export default function AppRouter () {
return (
< BrowserRouter >
< Routes >
< Route path = " / " element ={ < MainLayout /> } >
< Route index element ={ < Home /> } />
< Route
path = " settings "
element ={
< AuthGuard >
< Settings />
</ AuthGuard >
}
/>
</ Route >
</ Routes >
</ BrowserRouter >
);
}
Route Guard Implementation
// guards/AuthGuard.tsx
import { Navigate, Outlet } from ' react-router-dom ' ;
import { useAuth } from ' ../stores/useAuth ' ;
export default function AuthGuard () {
const { isAuthenticated } = useAuth ();
if ( ! isAuthenticated) {
return < Navigate to = " /login " replace />;
}
return < Outlet />;
}
Project Directory Structure and Specifications
Recommended Directory Structure
electron - app /
├── .github / # CI / CD configuration
│ └── workflows / # GitHub Actions
├── src / # Source code
│ ├── main / # Main process code
│ │ ├── index.ts # Main entry point
│ │ └── window / # Window management
│ ├── preload / # Preload scripts
│ ├── renderer / # Renderer process code
│ │ ├── assets / # Static assets
│ │ ├── components / # Components
│ │ ├── pages / # Pages
│ │ └── App.tsx # Renderer entry point
│ └── shared / # Shared code
├── tests / # Test code
├── .eslintrc.js # ESLint configuration
├── .prettierrc # Prettier configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Project configuration
Code Specification Key Points
Naming Conventions :
Variables/Functions: camelCase
Classes/Types: PascalCase
Constants: UPPER_CASE
Filenames: kebab-case
Code Organization :
Organize by feature, not type
Group related functionality together
Group third-party libraries separately
Electron CLI Advanced Configuration
Custom Script Configuration
// package.json
{
" scripts " : {
" start " : " electron . " ,
" dev " : " concurrently \" npm run start-renderer \" \" npm run start-main \" " ,
" start-main " : " electron --inspect=5858 . " ,
" start-renderer " : " webpack serve --config webpack.renderer.config.js " ,
" build " : " npm run build-main && npm run build-renderer " ,
" build-main " : " tsc -p tsconfig.main.json " ,
" build-renderer " : " webpack --config webpack.renderer.config.js " ,
" package " : " electron-builder --win --mac --linux "
}
}
Environment Variable Management
// config/env.ts
type Env = ' development ' | ' production ' | ' test ' ;
const getEnv = () : Env => {
return process.env. NODE_ENV as Env || ' development ' ;
};
export const config = {
apiBaseUrl : process.env. API_BASE_URL ||
( getEnv () === ' production ' ? ' https://api.prod.com ' : ' http://localhost:3000 ' ),
isDev : getEnv () === ' development ' ,
// Other configurations...
};
Webpack Advanced Configuration
Multi-Process Build Configuration
// webpack.renderer.config.js
const TerserPlugin = require ( ' terser-webpack-plugin ' );
const CssMinimizerPlugin = require ( ' css-minimizer-webpack-plugin ' );
const { BundleAnalyzerPlugin } = require ( ' webpack-bundle-analyzer ' );
module . exports = {
// ...
optimization : {
minimizer : [
new TerserPlugin ({
parallel : true , // Enable multi-process compression
terserOptions : {
compress : { drop_console : true }
}
}),
new CssMinimizerPlugin ()
],
splitChunks : {
chunks : ' all ' ,
cacheGroups : {
vendors : {
test : / [ \\/ ] node_modules [ \\/ ] / ,
priority : - 10
},
common : {
minChunks : 2 ,
priority : - 20
}
}
}
},
plugins : [
new BundleAnalyzerPlugin ({
analyzerMode : process.env. ANALYZE ? ' server ' : ' disabled '
})
]
};
Code Splitting Strategy
// Dynamic import example
const SettingsModal = React. lazy (() => import ( ' ../components/SettingsModal ' ));
function App () {
return (
< Suspense fallback ={ < Spinner /> } >
< SettingsModal />
</ Suspense >
);
}
// Webpack magic comments
const HeavyComponent = React. lazy (() => import (
/* webpackChunkName: "heavy-component" */
/* webpackPrefetch: true */
' ../components/HeavyComponent '
));
TypeScript Integration
Type-Safe Configuration
// tsconfig.json
{
" compilerOptions " : {
" target " : " ES2020 " ,
" module " : " ESNext " ,
" lib " : [ " DOM " , " ES2020 " ],
" strict " : true ,
" esModuleInterop " : true ,
" skipLibCheck " : true ,
" forceConsistentCasingInFileNames " : true ,
" moduleResolution " : " node " ,
" resolveJsonModule " : true ,
" isolatedModules " : true ,
" noEmit " : true , // Handled by Babel
" jsx " : " react-jsx "
},
" include " : [ " src/**/* " ],
" exclude " : [ " node_modules " ]
}
// tsconfig.main.json (Main process specific)
{
" extends " : " ./tsconfig.json " ,
" compilerOptions " : {
" target " : " ES2019 " ,
" module " : " CommonJS " ,
" outDir " : " dist/main "
},
" include " : [ " src/main/**/* " ]
}
Type Definition Extensions
// types/electron.d.ts
declare namespace NodeJS {
interface Global {
ipcRenderer : Electron . IpcRenderer ;
}
}
// Extend Window interface
interface Window {
electronAPI : {
readFile : ( path : string ) => Promise < string >;
writeFile : ( path : string , content : string ) => Promise < void >;
};
}
ESLint Configuration
// .eslintrc.js
module . exports = {
root : true ,
env : {
browser : true ,
node : true ,
es2020 : true
},
extends : [
' eslint:recommended ' ,
' plugin:react/recommended ' ,
' plugin:react-hooks/recommended ' ,
' plugin:@typescript-eslint/recommended ' ,
' prettier ' // Must be last
],
parser : ' @typescript-eslint/parser ' ,
plugins : [ ' @typescript-eslint ' , ' import ' ],
rules : {
' react/react-in-jsx-scope ' : ' off ' , // Not needed in React 17+
' @typescript-eslint/explicit-module-boundary-types ' : ' off ' ,
' import/order ' : [
' error ' ,
{
groups : [ ' builtin ' , ' external ' , ' internal ' , ' parent ' , ' sibling ' , ' index ' ],
' newlines-between ' : ' always '
}
]
},
settings : {
react : {
version : ' detect '
}
}
};
Prettier Configuration
// .prettierrc
{
" printWidth " : 100 ,
" tabWidth " : 2 ,
" useTabs " : false ,
" semi " : true ,
" singleQuote " : true ,
" quoteProps " : " as-needed " ,
" jsxSingleQuote " : false ,
" trailingComma " : " all " ,
" bracketSpacing " : true ,
" bracketSameLine " : false ,
" arrowParens " : " always " ,
" endOfLine " : " lf "
}
Automated Testing Framework
Jest Configuration
// jest.config.js
module . exports = {
preset : ' ts-jest ' ,
testEnvironment : ' jsdom ' ,
moduleNameMapper : {
' \\ .(css|less|scss|sass)$ ' : ' identity-obj-proxy ' ,
' ^@/(.*)$ ' : ' <rootDir>/src/$1 '
},
setupFilesAfterEnv : [ ' <rootDir>/jest.setup.ts ' ],
transform : {
' ^.+ \\ .(ts|tsx)$ ' : ' ts-jest '
},
globals : {
' ts-jest ' : {
tsconfig : ' tsconfig.test.json '
}
}
};
Spectron Testing Example
// tests/app.test.ts
import { Application } from ' spectron ' ;
import electronPath from ' electron ' ;
import path from ' path ' ;
describe ( ' Application launch ' , () => {
let app : Application ;
beforeEach ( async () => {
app = new Application ({
path : electronPath,
args : [path. join (__dirname, ' .. ' )]
});
await app. start ();
});
afterEach ( async () => {
if (app && app. isRunning ()) {
await app. stop ();
}
});
it ( ' shows an initial window ' , async () => {
const count = await app.client. getWindowCount ();
expect (count). toEqual ( 1 );
const title = await app.client. getTitle ();
expect (title). toContain ( ' My App ' );
});
});
Code Splitting and Lazy Loading
Dynamic Import Strategy
// Route-level code splitting
const Home = React. lazy (() => import ( ' ../pages/Home ' ));
const Settings = React. lazy (() => import ( ' ../pages/Settings ' ));
// Component-level lazy loading
const HeavyChart = React. lazy (() => import ( ' ../components/HeavyChart ' ));
// API request splitting
const fetchUserData = () => import ( ' ../api/user ' ). then ( mod => mod.fetchUser);
Preloading Critical Resources
<!-- Preload critical resources in HTML -->
< link rel = " preload " href = " /critical.css " as = " style " >
< link rel = " preload " href = " /main.js " as = " script " >
< link rel = " prefetch " href = " /settings.js " as = " script " >
Resource Compression and Caching
Webpack Resource Optimization
// webpack.config.js
module . exports = {
// ...
module : {
rules : [
{
test : / \. ( png | jpe ? g | gif | webp ) $ / i ,
use : [
{
loader : ' image-webpack-loader ' ,
options : {
mozjpeg : { progressive : true , quality : 65 },
optipng : { enabled : false },
pngquant : { quality : [ 0.65 , 0.9 ], speed : 4 },
gifsicle : { interlaced : false }
}
}
]
}
]
},
plugins : [
new CompressionPlugin ({
algorithm : ' gzip ' ,
test : / \. ( js | css | html | svg ) $ / ,
threshold : 10240 // Compress files larger than 10KB
})
]
};
Caching Strategy Configuration
// Service Worker caching strategy
self. addEventListener ( ' fetch ' , ( event ) => {
event. respondWith (
caches. match (event.request)
. then ( response => {
// Cache hit
if (response) return response;
// Network request
return fetch (event.request)
. then ( networkResponse => {
// Dynamic caching strategy
if (event.request.url. match ( / \. ( js | css | png | jpg | json ) $ / )) {
const clone = networkResponse. clone ();
caches. open ( ' dynamic-cache ' )
. then ( cache => cache. put (event.request, clone));
}
return networkResponse;
});
})
);
});
Application Packaging and Release
Auto-Update Configuration
// main.js - Auto-update implementation
const { autoUpdater } = require ( ' electron ' );
const server = ' https://update.example.com ' ;
const feed = ` ${ server } /update/ ${ process.platform } / ${ app. getVersion () } ` ;
autoUpdater. setFeedURL ({ feed });
autoUpdater. on ( ' checking-for-update ' , () => {
sendStatusToWindow ( ' Checking for update... ' );
});
autoUpdater. on ( ' update-available ' , ( info ) => {
sendStatusToWindow ( ' Update available ' );
});
autoUpdater. on ( ' update-downloaded ' , ( info ) => {
sendStatusToWindow ( ' Update downloaded ' );
autoUpdater. quitAndInstall ();
});
// Check for updates every hour
setInterval (() => autoUpdater. checkForUpdatesAndNotify (), 3600000 );
Version Management Strategy
// package.json
{
" version " : " 1.0.0 " ,
" build " : {
" appId " : " com.example.app " ,
" version " : " 1.0.0 " ,
" directories " : {
" output " : " dist "
},
" win " : {
" target " : " nsis " ,
" artifactName " : " ${productName}-${version}-${platform}-${arch}.${ext} "
},
" mac " : {
" target " : " dmg " ,
" artifactName " : " ${productName}-${version}-${platform}-${arch}.${ext} "
}
}
}
Sentry Integration
// main.js - Error monitoring
const Sentry = require ( ' @sentry/electron ' );
Sentry. init ({
dsn : ' https://examplePublicKey@o0.ingest.sentry.io/0 ' ,
release : app. getVersion (),
environment : process.env. NODE_ENV
});
// Capture unhandled exceptions
process. on ( ' uncaughtException ' , ( error ) => {
Sentry. captureException (error);
});
// Renderer process error monitoring
window. addEventListener ( ' error ' , ( event ) => {
Sentry. captureException (event.error);
});
// Performance measurement example
const { performance, PerformanceObserver } = require ( ' perf_hooks ' );
// Create performance observer
const obs = new PerformanceObserver (( items ) => {
items. getEntries (). forEach (( entry ) => {
console. log ( ` ${ entry.name } : ${ entry.duration } ms` );
});
});
obs. observe ({ entryTypes : [ ' measure ' ] });
// Mark performance critical points
performance. mark ( ' start-render ' );
// ...rendering logic...
performance. mark ( ' end-render ' );
performance. measure ( ' render-time ' , ' start-render ' , ' end-render ' );
GitHub Actions Configuration
# .github/workflows/build.yml
name: Build and Release
on:
push:
tags: [ ' v* ' ]
jobs :
build:
strategy:
matrix:
platform: [macos-latest, windows-latest, ubuntu-latest]
runs-on: ${{ matrix . platform } }
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: ' 16 '
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Package
run: npm run package
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: release- ${{ matrix . platform } }
path: dist/
Automated Release Process
# Release script example
#!/bin/bash
# 1. Run tests
npm test
# 2. Build application
npm run build
# 3. Generate changelog
standard-version
# 4. Push to GitHub
git push --follow-tags
# 5. Trigger GitHub Actions for auto-release