Skip to content

Commit 23e4fe1

Browse files
committed
Learning content: Application Bootstrap #6853 super early stage
1 parent dda410d commit 23e4fe1

2 files changed

Lines changed: 341 additions & 0 deletions

File tree

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
**Understanding how Neo.mjs applications start, initialize, and come to life**
2+
3+
## Overview
4+
5+
When you run `npm start` and see your Neo.mjs application in the browser, a sophisticated multi-threaded orchestration
6+
happens behind the scenes. This guide explains the complete application bootstrap process, from initial configuration
7+
loading to your first rendered component.
8+
9+
## The Big Picture
10+
11+
Neo.mjs applications don't start like traditional web apps. Instead of running everything on the main browser thread,
12+
Neo.mjs creates a **multi-worker architecture** where your application logic runs in a dedicated **App Worker**,
13+
completely separate from DOM manipulation.
14+
15+
```
16+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Main Thread │ │ App Worker │ │ VDom Worker │ │ │ │ │ │ │ │ • DOM Updates │ │ • Your App Code │ │ • VDom Diffing │ │ • Event Capture │ │ • Components │ │ • Optimization │ │ • Rendering │ │ • Business Logic│ │ • Delta Calc │ └─────────────────┘ └─────────────────┘ └─────────────────┘
17+
```
18+
19+
**Key Insight:** Your application code lives entirely in the **App Worker** - a rich JavaScript environment with full framework access, while DOM operations happen automatically on the Main Thread.
20+
21+
## Bootstrap Sequence
22+
23+
### 1. Configuration Loading
24+
25+
Every Neo.mjs application starts with a `neo-config.json` file that defines how the application should initialize:
26+
```json
27+
{
28+
"appPath" : "../../apps/portal/app.mjs",
29+
"basePath" : "../../",
30+
"environment" : "development",
31+
"mainPath" : "../src/Main.mjs",
32+
"workerBasePath": "../../src/worker/"
33+
}
34+
```
35+
36+
**Key Configuration Properties:**
37+
- **`appPath`** - Points to your application's entry point (app.mjs)
38+
- **`basePath`** - Root path for resolving other paths
39+
- **`environment`** - Controls optimization and debugging features
40+
- **`mainPath`** - Framework's main thread bootstrap file
41+
- **`workerBasePath`** - Location of worker initialization files
42+
43+
### 2. Main Thread Initialization
44+
45+
The main thread starts by loading `src/Main.mjs`, which:
46+
47+
1. **Creates the Worker Manager** - Coordinates all worker threads
48+
2. **Spawns Workers** - App Worker, VDom Worker, Data Worker (if needed)
49+
3. **Establishes Communication** - Sets up message passing between threads
50+
4. **Loads Configuration** - Distributes neo-config.json to all workers
51+
52+
### 3. Worker Spawning and Setup
53+
54+
**App Worker Creation:**
55+
```javascript
56+
// Main Thread creates App Worker
57+
const appWorker = new Worker('src/worker/App.mjs', {type: 'module'});
58+
59+
// App Worker receives configuration and initializes
60+
// worker/App.mjs loads your application entry point
61+
```
62+
63+
**VDom Worker Creation:**
64+
```javascript
65+
// VDom Worker handles virtual DOM operations
66+
const vdomWorker = new Worker('src/worker/VDom.mjs', {type: 'module'});
67+
// Optimizes rendering and calculates DOM deltas
68+
```
69+
70+
### 4. Application Loading Process
71+
72+
Once workers are initialized, the magic begins:
73+
74+
**Step 1: Dynamic Import**
75+
```javascript
76+
// App Worker dynamically imports your app.mjs
77+
const module = await import('../../apps/portal/app.mjs');
78+
// Your entry point gets loaded into the App Worker context
79+
```
80+
81+
**Step 2: Entry Point Execution**
82+
```javascript
83+
// Your app.mjs exports an onStart function export
84+
const onStart = () => Neo.app({ mainView: Viewport, name : 'Portal' });
85+
// Framework calls this function to bootstrap your application
86+
```
87+
88+
**Step 3: Application Controller Creation**
89+
```javascript
90+
// Neo.app() creates an Application controller
91+
const app = Neo.create({ module: Neo.controller.Application, mainView: Viewport, // Your main UI component name: 'Portal', // Application identifier appName: 'Portal' // Used for CSS scoping, routing });
92+
```
93+
94+
### 5. Component Tree Construction
95+
96+
Your `mainView` component (like `Viewport`) gets instantiated:
97+
```
98+
javascript // Your Viewport component class Viewport extends Container { static config = { className: 'Portal.view.Viewport', layout : 'vbox',
99+
items: [
100+
HeaderComponent, // Child components
101+
MainPanel, // All created in App Worker
102+
FooterComponent
103+
]
104+
}
105+
}
106+
```
107+
108+
**Component Instantiation Process:**
109+
1. **Viewport created** in App Worker with rich component APIs
110+
2. **Child components instantiated** recursively
111+
3. **Event listeners attached** via framework's event system
112+
4. **Data bindings established** for reactive updates
113+
114+
### 6. VDom Generation and Initial Render
115+
116+
Once the component tree is built:
117+
118+
1. **VDom Generation** - Each component generates its virtual DOM structure
119+
2. **VDom Tree Assembly** - Framework builds complete virtual DOM tree
120+
3. **Initial DOM Creation** - VDom Worker calculates initial DOM structure
121+
4. **DOM Projection** - Main Thread creates actual DOM elements
122+
5. **CSS Application** - Styling and layout applied
123+
6. **Event Delegation Setup** - Event system activated
124+
125+
## The app.mjs Pattern
126+
127+
Your application entry point follows a simple but powerful pattern:
128+
```
129+
javascript // apps/myapp/app.mjs import Overwrites from './Overwrites.mjs'; // Optional framework extensions import Viewport from './view/Viewport.mjs'; // Your main UI component
130+
export const onStart = () => Neo.app({ mainView: Viewport, // Root component of your application name : 'MyApp' // Application identifier });
131+
```
132+
133+
**Why This Pattern Works:**
134+
- **Minimal Entry Point** - Framework handles complex initialization
135+
- **Component-Centric** - Your app is just a component tree
136+
- **Configuration-Driven** - Declarative approach to app structure
137+
- **Import-Based** - Clean dependency management
138+
139+
## App Worker: Your Development Environment
140+
141+
Once bootstrap completes, your entire application runs in the **App Worker** - a rich JavaScript environment with:
142+
143+
### Full Framework Access
144+
```
145+
javascript // Inside any component in your app: class MyComponent extends Component { someMethod() { // Component management Neo.getComponent('my-button');
146+
// Data access
147+
Neo.data.Store.getById('users');
148+
149+
// Routing
150+
Neo.HashHistory.push({page: 'settings'});
151+
152+
// Utilities
153+
Neo.util.Array.add(myArray, item);
154+
155+
// State management
156+
this.getViewModel().setData({loading: true});
157+
this.getController().loadData();
158+
}
159+
}
160+
```
161+
162+
### Event-Driven Architecture
163+
```
164+
javascript // Components communicate via events class ProductGrid extends Grid { static config = { listeners: { select: 'onProductSelect' } }
165+
onProductSelect(data) {
166+
// Fire custom events that bubble up
167+
this.fire('productSelected', {
168+
product: data.record,
169+
grid : this
170+
});
171+
}
172+
}
173+
```
174+
175+
### Reactive Configuration System
176+
```
177+
javascript // Configs automatically trigger UI updates class UserProfile extends Component { static config = { user_: null, // Reactive config
178+
// UI updates automatically when user changes
179+
bind: {
180+
html: data => `Welcome, ${data.user?.name || 'Guest'}!`
181+
}
182+
}
183+
184+
afterSetUser(value, oldValue) {
185+
// Automatic lifecycle method
186+
console.log('User changed:', value);
187+
}
188+
}
189+
```
190+
191+
## Multi-Application Scenarios
192+
193+
Neo.mjs supports multiple applications in a single browser session:
194+
195+
### Shared Worker Multi-App
196+
```
197+
javascript // Multiple apps can run simultaneously // apps/crm/app.mjs export const onStart = () => Neo.app({ mainView: CrmViewport, name : 'CRM' });
198+
// apps/accounting/app.mjs
199+
export const onStart = () => Neo.app({ mainView: AccountingViewport, name : 'Accounting' });
200+
// Both run in same App Worker, different browser windows
201+
```
202+
203+
### Cross-App Communication
204+
```
205+
javascript // Apps can communicate and share data Neo.apps.CRM.mainView.fire('customerUpdated', { customerId: 123, changes : {status: 'active'} });
206+
// Shared stores, utilities, and state possible
207+
```
208+
209+
## Performance and Optimization
210+
211+
### Automatic Optimizations
212+
213+
The bootstrap process includes built-in optimizations:
214+
215+
- **Worker Thread Isolation** - Main thread never blocks
216+
- **Lazy Loading** - Components load only when needed
217+
- **VDom Diffing** - Minimal DOM updates calculated automatically
218+
- **Event Delegation** - Efficient event handling across component tree
219+
- **Memory Management** - Proper cleanup and garbage collection
220+
221+
### Development vs Production
222+
223+
**Development Mode:**
224+
- Source maps for debugging
225+
- Detailed error messages
226+
- Hot reload support
227+
- Performance monitoring
228+
229+
**Production Mode:**
230+
- Minified bundles
231+
- Optimized worker loading
232+
- Reduced debug overhead
233+
- Enhanced caching
234+
235+
## Configuration Deep Dive
236+
237+
### Common Configuration Options
238+
239+
```json
240+
{
241+
"appPath": "../../apps/myapp/app.mjs",
242+
"basePath": "../../",
243+
"environment": "development",
244+
"useSharedWorkers": false,
245+
"useServiceWorker": false,
246+
"themes": ["neo-theme-light"],
247+
"mainThreadAddons": ["Stylesheet"],
248+
"workerBasePath": "../../src/worker/"
249+
}
250+
```
251+
```
252+
**Configuration Categories:**
253+
- **Path Resolution** - Where to find files and modules
254+
- **Worker Settings** - How workers should be configured
255+
- **Theme Management** - CSS and styling options
256+
- **Addon Loading** - Additional framework features
257+
- **Environment Flags** - Development vs production settings
258+
259+
### Environment-Specific Configs
260+
Different environments can use different configurations:
261+
- **`neo-config.json`** - Default configuration
262+
- **`neo-config-development.json`** - Development overrides
263+
- **`neo-config-production.json`** - Production optimizations
264+
265+
## Debugging and Troubleshooting
266+
### Common Startup Issues
267+
**Configuration Problems:**
268+
```
269+
Error: Failed to resolve module
270+
Solution: Check appPath and basePath in neo-config.json
271+
```
272+
**Worker Loading Failures:**
273+
```
274+
Error: Worker script failed to load
275+
Solution: Verify workerBasePath and main thread configuration
276+
```
277+
**Application Module Issues:**
278+
```
279+
Error: onStart is not a function
280+
Solution: Ensure app.mjs exports onStart function correctly
281+
```
282+
### Debug Tools
283+
**Worker Communication:**
284+
``` javascript
285+
// Enable worker message logging
286+
Neo.config.logLevel = 'debug';
287+
288+
// Monitor worker messages in browser console
289+
```
290+
**Performance Monitoring:**
291+
``` javascript
292+
// Track bootstrap timing
293+
Neo.config.renderCountDeltas = true;
294+
295+
// Monitor component creation
296+
Neo.config.logLevel = 'info';
297+
```
298+
## Best Practices
299+
### Application Structure
300+
```
301+
apps/myapp/
302+
├── app.mjs ← Entry point
303+
├── neo-config.json ← Configuration
304+
├── view/ ← UI components
305+
│ ├── Viewport.mjs ← Main component
306+
│ ├── Header.mjs ← Child components
307+
│ └── MainPanel.mjs
308+
├── store/ ← Data management
309+
├── model/ ← Data models
310+
└── controller/ ← Business logic
311+
```
312+
### Entry Point Guidelines
313+
``` javascript
314+
// Keep app.mjs minimal and focused
315+
import Overwrites from './Overwrites.mjs'; // Optional
316+
import Viewport from './view/Viewport.mjs';
317+
318+
export const onStart = () => Neo.app({
319+
mainView: Viewport, // Always use a meaningful main component
320+
name : 'MyApp' // Use consistent naming
321+
});
322+
323+
// Avoid complex logic in app.mjs - put it in components
324+
```
325+
### Configuration Management
326+
``` json
327+
{
328+
// Use relative paths for portability
329+
"appPath": "../../apps/myapp/app.mjs",
330+
331+
// Keep development-specific settings separate
332+
"environment": "development",
333+
334+
// Document custom configuration
335+
"customSettings": {
336+
"apiEndpoint": "https://api.example.com"
337+
}
338+
}
339+
```
340+
## What's Next?

resources/data/deck/learnneo/tree.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
{"name": "Earthquakes", "parentId": "Tutorials", "id": "tutorials.Earthquakes"},
2626
{"name": "Todo List", "parentId": "Tutorials", "id": "tutorials.TodoList"},
2727
{"name": "Guides", "parentId": null, "isLeaf": false, "id": "InDepth", "collapsed": true},
28+
{"name": "Application Bootstrap", "parentId": "InDepth", "id": "guides.ApplicationBootstrap"},
2829
{"name": "Declarative Component Trees VS Imperative Vdom", "parentId": "InDepth", "id": "guides.DeclarativeComponentTreesVsImperativeVdom"},
2930
{"name": "Working with VDom", "parentId": "InDepth", "id": "guides.WorkingWithVDom"},
3031
{"name": "Instance Lifecycle", "parentId": "InDepth", "id": "guides.InstanceLifecycle", "hidden": true},

0 commit comments

Comments
 (0)