v5
Core Changes
- Full TypeScript Rewrite: All APIs now have complete type definitions.
- Dual Module Format Output: Both CJS and ESM formats are supported.
- Node.js Version Upgrade: Minimum requirement is Node.js >= 20.19.0.
- Pino Logging System: More powerful logging capabilities.
- Bundle Registry Mechanism: Faster startup.
- Async Controller Loading: Supports ESM dynamic imports, avoiding sync/async concurrency race conditions.
- Main Process Bundling: Main process code can be bundled like frontend bundles.
- Build Registry Plugin: Replicates runtime property name mapping logic.
- Comprehensive Build Configuration Enhancement: Added numerous fine-grained control options.
- Post-Build Independent Transpilation: Independently transpiles files that cannot be bundled.
- Encryption System Upgrade: More secure.
- Atomic Resource Move: Prevents data loss.
- ee-bin Full Upgrade: Added complete TypeScript type system.
- EventBus Event Isolation: Lifecycle event optimization.
- ESM-Compatible Config Loading: Auto-unwraps
__esModuleformat, supports function/class exports. - Controller Concurrency Safety: Explicitly guarantees no state pollution between concurrent requests.
- Cross Inter-Process Improvements: Optimized.
I. Core Architecture Changes
1. Full TypeScript Rewrite
In v4, ee-core and ee-bin were written entirely in JavaScript (.js). Type definitions were only auto-generated via tsconfig.json with emitDeclarationOnly + allowJs to produce .d.ts files — the source code itself had no type constraints.
v5 performs a full TypeScript rewrite of both core packages. All source files are .ts, with extremely strict compilation settings.
Impact:
- All APIs have complete type definitions; IDE intelligent hints are significantly improved
- Compile-time catches implicit
any, unchecked index access, optional property misuse, and other common errors - ESM source code
importmust include.jsextension (NodeNextspecification)
2. Dual Module Format Output (CJS + ESM)
v4 only outputs CommonJS (require('ee-core')). v5 outputs both CJS and ESM formats:
dist/cjs/ → CommonJS (module: CommonJS)
dist/esm/ → ESM (module: NodeNext)The exports field in package.json provides conditional exports for each subpath:
{
"./app": {
"import": "./dist/esm/app/index.js",
"require": "./dist/cjs/app/index.js"
}
}Impact:
- Developers can directly
import { ElectronEgg } from 'ee-core'in ESM projects - CJS projects continue to use
const { ElectronEgg } = require('ee-core') - The
exportsmapping ofee-coreis auto-generated byscripts/gen-exports.js. After adding new subpath modules, runnpm run gen-exportsto update — no manual editing needed
3. Node.js Version Requirement Upgrade
v5 requires Node.js >= 20.19.0.
II. ee-core Feature Updates
4. Logging System: Pino Replaces egg-logger
v4 uses egg-logger (EggLoggers). Log files append -YYYYMMDD suffixes by day, with lazy initialization via Object.defineProperty.
v5 fully switches to the Pino logging system:
| Feature | v4 (egg-logger) | v5 (Pino) |
|---|---|---|
| Logging library | egg-logger | pino + pino-roll + pino-pretty |
| Rotation policy | Append suffix by day | pino-roll: rotate by day/hour |
| Dev output | Custom format | pino-pretty: configurable color, depth, timestamp |
| Timezone | Fixed UTC | IANA timezone support (e.g. Asia/Shanghai) |
| Log redaction | None | Pino redaction (field masking) |
| Custom levels | Fixed | Configurable custom levels |
| Call style | Standard method call | Proxy wrapper: supports {obj, msg}, printf ('count: %d', 42), concatenation ('msg:', val) styles |
| Safe mode | None | Safe mode prevents serialization crashes |
Impact:
- Log configuration migrates from
config.loggeregg-logger format to pino format coreLogger,logger,errorLoggerthree instances remain, but the underlying implementation is completely different- Developers need to update custom log configuration
5. Bundle Mode: Registry Mechanism
This is v5's most critical architectural addition. v4 loads controllers and configs at runtime via globby filesystem scanning, and bundled apps also depend on filesystem paths.
Impact:
- After bundling, all controllers and configs are registered to global variables, no filesystem scanning needed, faster startup
- Lazy getters avoid initialization order issues — controllers do not execute at the registration phase
- Dev mode (unbundled) automatically falls back to filesystem scanning, consistent with v4 behavior
process.env.EE_BUNDLED = "true"identifies bundle mode
6. Async Controller Loading
v4's ControllerLoader only supports synchronous require() loading. v5 adds an async loading path:
Application.runAsync()→loadControllerAsync()→FileLoader.parseAsync()→import()dynamic loading- Loading process has a
loadingflag to prevent sync/async concurrency race conditions
Impact:
- ESM projects can use
runAsync()to ensure async modules load correctly - In async loading mode, controller files can be in ESM format
7. IPC Dual Model
v5 explicitly defines the IPC Dual Model:
| Model | Renderer Call | Main Process Registration | Characteristics |
|---|---|---|---|
| send/on | webContents.send / ipcRenderer.send | ipcMain.on | Sync, event.returnValue + event.reply |
| invoke/handle | ipcRenderer.invoke | ipcMain.handle | Async, Promise return value, recommended |
Error propagation adds {__EE_ERROR__: true, message} structured marker.
8. HTTP Service: Koa Middleware Chain Standardization
v5 explicitly orders the middleware chain:
errorHandler → preMiddleware → CORS → koa-body → dispatch → postMiddlewareA new koaConfig configuration section is added; developers can independently configure preMiddleware and postMiddleware arrays.
9. Child Process Config Passing: argv Replaces Filesystem
v5 passes eeConfig via process.argv[2] (JSON stringified and injected by JobProcess). Inside the child process, setConfig() parses and caches it — no filesystem read needed.
Impact:
child_process.fork()scenarios in bundled apps are more reliable- Child processes no longer depend on config file paths
10. Port Allocation: Dual-Level Lock Mechanism
v5 introduces an old + young dual-level lock set (15-second rotation) to prevent concurrent processes from grabbing the same port.
It also checks all local network interfaces to avoid assigning already-occupied ports.
11. systemSleep: True Sync Blocking
v5 adds the systemSleep(ms) utility function, using Atomics.wait + SharedArrayBuffer for true synchronous blocking (no CPU occupation), with a busy-wait fallback.
12. Zero lodash Dependency
v5 completely removes the following npm dependencies, replacing them with lightweight in-house implementations:
| v4 Dependency | v5 Replacement | Location |
|---|---|---|
| lodash.merge | extend.ts (in-house deep merge) | ee-core, ee-bin shared |
| chalk | ANSI escape code lightweight implementation | ee-bin lib/helpers.ts |
| is-type-of | is.function() / is.class() | ee-bin lib/helpers.ts |
| fs-extra | copyDirSync() in-house implementation | ee-bin lib/helpers.ts |
| debug | createDebug() environment-driven | ee-bin lib/helpers.ts |
| egg-logger | pino system | ee-core log/ |
| adm-zip | compressing | ee-bin incrUpdater |
Impact:
- Package size and security risks significantly reduced
III. ee-bin Feature Updates
13. Build Registry Plugin (Core Addition)
v4's ee-bin has no esbuild plugin mechanism. Controllers and config files are directly bundled into main.js (or copied verbatim in copy mode).
v5 adds bundle_registry_plugin.ts, a key component of v5's bundling architecture:
- Virtual module
app:controller-registry: scans the controller directory and generates a registry - Virtual module
app:config-registry: scans the config directory and generates a registry - Virtual module
app:bundle-entry: entry point that loads registries + main.js in sequence
The computeProperties() function replicates ee-core's defaultCamelize(caseStyle: 'lower') logic, ensuring build-time and runtime property name mapping consistency.
14. Comprehensive Build Configuration Enhancement
v5's build.electron (BundleConfig type) adds numerous fine-grained control options:
| Config Item | v4 | v5 | Description |
|---|---|---|---|
external | None | ✅ | User-defined external packages |
sourcemap | false (fixed) | false → auto logic | dev→inline, prod→off; can explicitly set inline/external |
minify | None | ✅ | Production minification |
drop | None | ✅ | Remove console/debugger |
keepNames | None | ✅ | Preserve function/class names during minification |
legalComments | None | ✅ | inline/eof/none |
define | None | ✅ | Compile-time constant injection |
copy | None | ✅ | Extra file/directory copying |
format | None | ✅ | cjs/esm; default cjs |
| Framework externals | No explicit list | ✅ | ee-core, ee-bin, electron, better-sqlite3, proxy-agent, pino-roll, pino-pretty |
Impact:
- Production builds can finely control sourcemap, minification, constant injection, etc.
sourcemap: falseis no longer "always off", but "auto-decide by environment"format: 'esm'mode requires all business code (controllers, services, configs) to be ESM-compatible
15. Post-Build Processing: Independent File Transpilation
v5's bundle mode, after bundling, performs independent esbuild transpilation on files that cannot be bundled (preload/bridge.js, jobs/ directory, user copy config items):
- Script files (
.js/.ts) are compiled withbundle: falseinto Node-loadable CJS.js, preserving runtimerequire()calls - Non-script files are copied verbatim
- All transpilation uses
_resolveBaseBuildOptions()shared settings, ensuring format consistency with the main bundle
Impact:
preload/bridge.jsandjobs/files work correctly in bundled environments- No need to manually handle
child_process.fork()path issues
16. Encryption System Upgrade
| Feature | v4 | v5 | |
|---|---|---|---|
entryFiles | None | ✅ | Entry files (e.g. main.js) compiled to .jsc then overwritten .js as bytenode loader shell |
bytecodeOptions | Fixed electron: true | ✅ | Configurable bytenode compile parameters |
| Safety check | None | ✅ | Verifies .jsc exists after compilation before deleting .js; throws error and preserves source file if not |
silent mode | None | ✅ | Hides javascript-obfuscator Pro ad output |
cleanFiles | None | ✅ | Specifies encryption artifacts to clean |
encryptDir | None | ✅ | Custom encryption output directory |
17. Resource Move: Atomic Operation
v5's move.ts switches to atomic operation:
Backup target → .bak → Copy source to target → Delete backupOn copy failure, restores .bak to prevent data loss.
18. Other ee-bin Changes
| Item | v4 | v5 |
|---|---|---|
| esbuild | 0.21.5 | 0.28 |
| commander | 11.0.0 | 14 |
| Compression lib | adm-zip | compressing |
| Test framework | None | Vitest (coverage 90%/85%) |
pargv.js | minimist-style parser | Retained but refactored to TS |
| TypeScript types | None | Complete BinConfig type system |
| Config loading | .js/.cjs/.ts/.json/.json5 | Same + ESM default export unwrapping + function/class config factories |
IV. General Changes
19. EventBus Improvements
v5's EventBus separates lifecycle events and custom events into two independent internal Maps:
- Lifecycle events (
register/emitLifecycle): duplicate registration overwrites with warning, async errors re-thrown - Custom events (
on/emit): async errors caught and logged, no flow interruption
v4's EventBus uses the same mechanism for both event types, with no overwrite warnings.
20. ESM-Compatible Config Loading
v5's loadFile() / loadFileAsync() adds ESM compatibility:
- Auto-unwraps
{__esModule: true, default: fn}format - Auto-calls config files exporting functions (passing
appInfo) - Directly uses config files exporting classes (no call)
- Async version uses
import()for loading
21. Controller Concurrency Safety
v5 explicitly states: each middleware call creates a new controller instance, ensuring no state pollution between concurrent requests. The type system also reinforces this constraint in ControllerLoader.
22. Cross Inter-Process Management Improvements
v5's Cross class adds at run():
- Dynamic port allocation (dual-level lock mechanism)
- Duplicate service names auto-append pid suffix to avoid conflicts
V. Migration Notes
Must Adjust
- Node.js version: Ensure >= 20.19.0
- Log configuration: Migrate from egg-logger format to pino format (
pino-rollrotation,pino-prettyoutput, etc.) - ESM import extension:
importin ee-core source code must include.js(NodeNext specification)
Recommended Adjustments
- Build configuration: Use the new
minify,drop,define,sourcemapauto logic etc. to improve production bundle quality - Encryption configuration: New
entryFiles,bytecodeOptions,silentetc. options allow finer encryption control - Async controllers: ESM projects should use
runAsync()+loadControllerAsync()
No Adjustment Needed
- Dev mode controller/config loading falls back to filesystem scanning, consistent with v4 behavior
ElectronEggentry class,Applicationsingleton, startup flow sequence unchanged- Three-channel communication (Socket.IO, HTTP, IPC) architecture unchanged
- Child process (ChildJob, ChildPoolJob) API unchanged
- SqliteStorage API unchanged
