lego-dom 1.3.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -1
- package/main.js +48 -17
- package/main.min.js +2 -2
- package/package.json +1 -1
- package/parse-lego.js +2 -2
- package/vite-plugin.js +0 -14
- package/.github/workflows/deploy-docs.yml +0 -56
- package/.legodom +0 -87
- package/docs/.vitepress/config.js +0 -161
- package/docs/api/config.md +0 -95
- package/docs/api/define.md +0 -58
- package/docs/api/directives.md +0 -50
- package/docs/api/globals.md +0 -29
- package/docs/api/index.md +0 -30
- package/docs/api/lifecycle.md +0 -40
- package/docs/api/route.md +0 -37
- package/docs/api/vite-plugin.md +0 -58
- package/docs/contributing/01-welcome.md +0 -38
- package/docs/contributing/02-registry.md +0 -133
- package/docs/contributing/03-batcher.md +0 -110
- package/docs/contributing/04-reactivity.md +0 -87
- package/docs/contributing/05-caching.md +0 -59
- package/docs/contributing/06-init.md +0 -136
- package/docs/contributing/07-observer.md +0 -72
- package/docs/contributing/08-snap.md +0 -140
- package/docs/contributing/09-diffing.md +0 -69
- package/docs/contributing/10-studs.md +0 -78
- package/docs/contributing/11-scanner.md +0 -117
- package/docs/contributing/12-render.md +0 -138
- package/docs/contributing/13-directives.md +0 -243
- package/docs/contributing/14-events.md +0 -57
- package/docs/contributing/15-router.md +0 -57
- package/docs/contributing/16-state.md +0 -47
- package/docs/contributing/17-legodom.md +0 -48
- package/docs/contributing/index.md +0 -24
- package/docs/examples/form.md +0 -42
- package/docs/examples/index.md +0 -104
- package/docs/examples/routing.md +0 -409
- package/docs/examples/sfc-showcase.md +0 -34
- package/docs/examples/todo-app.md +0 -383
- package/docs/guide/cdn-usage.md +0 -354
- package/docs/guide/components.md +0 -418
- package/docs/guide/directives.md +0 -539
- package/docs/guide/directory-structure.md +0 -248
- package/docs/guide/faq.md +0 -210
- package/docs/guide/getting-started.md +0 -262
- package/docs/guide/index.md +0 -88
- package/docs/guide/lifecycle.md +0 -525
- package/docs/guide/quick-start.md +0 -49
- package/docs/guide/reactivity.md +0 -415
- package/docs/guide/routing.md +0 -334
- package/docs/guide/server-side.md +0 -134
- package/docs/guide/sfc.md +0 -464
- package/docs/guide/templating.md +0 -388
- package/docs/index.md +0 -160
- package/docs/public/logo.svg +0 -17
- package/docs/router/basic-routing.md +0 -103
- package/docs/router/cold-entry.md +0 -91
- package/docs/router/history.md +0 -69
- package/docs/router/index.md +0 -73
- package/docs/router/resolver.md +0 -74
- package/docs/router/surgical-swaps.md +0 -134
- package/docs/tutorial/01-project-setup.md +0 -152
- package/docs/tutorial/02-your-first-component.md +0 -226
- package/docs/tutorial/03-adding-routes.md +0 -279
- package/docs/tutorial/04-multi-page-app.md +0 -329
- package/docs/tutorial/05-state-and-globals.md +0 -285
- package/docs/tutorial/index.md +0 -40
- package/examples/vite-app/README.md +0 -71
- package/examples/vite-app/index.html +0 -42
- package/examples/vite-app/package.json +0 -18
- package/examples/vite-app/src/app.css +0 -3
- package/examples/vite-app/src/app.js +0 -29
- package/examples/vite-app/src/components/app-navbar.lego +0 -34
- package/examples/vite-app/src/components/customers/customer-details.lego +0 -24
- package/examples/vite-app/src/components/customers/customer-orders.lego +0 -21
- package/examples/vite-app/src/components/customers/order-list.lego +0 -55
- package/examples/vite-app/src/components/greeting-card.lego +0 -41
- package/examples/vite-app/src/components/sample-component.lego +0 -75
- package/examples/vite-app/src/components/shells/customers-shell.lego +0 -21
- package/examples/vite-app/src/components/side-menu.lego +0 -46
- package/examples/vite-app/src/components/todo-list.lego +0 -239
- package/examples/vite-app/src/components/widgets/user-card.lego +0 -27
- package/examples/vite-app/vite.config.js +0 -22
- package/tests/error.test.js +0 -74
- package/tests/main.test.js +0 -103
- package/tests/memory.test.js +0 -68
- package/tests/monitoring.test.js +0 -74
- package/tests/naming.test.js +0 -74
- package/tests/parse-lego.test.js +0 -65
- package/tests/security.test.js +0 -67
- package/tests/server.test.js +0 -114
- package/tests/syntax.test.js +0 -67
package/docs/guide/index.md
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# What is Lego?
|
|
2
|
-
|
|
3
|
-
LegoDOM is a tiny, zero-dependency JavaScript library for building reactive Web Components directly in the browser.
|
|
4
|
-
|
|
5
|
-
## The Philosophy
|
|
6
|
-
|
|
7
|
-
LegoDOM is built on a simple belief: **the DOM is not your enemy**.
|
|
8
|
-
|
|
9
|
-
Modern frameworks introduced virtual DOMs and compilation steps to solve problems that arose from trying to make the DOM do things it wasn't designed for. Lego takes a different approach—it embraces the DOM and Web Components as they were intended to be used.
|
|
10
|
-
|
|
11
|
-
## Key Principles
|
|
12
|
-
|
|
13
|
-
### 1. Mental Model Simplicity
|
|
14
|
-
|
|
15
|
-
There are no new concepts to learn. If you know:
|
|
16
|
-
- HTML
|
|
17
|
-
- JavaScript objects
|
|
18
|
-
- Basic DOM events
|
|
19
|
-
|
|
20
|
-
You already know Lego.
|
|
21
|
-
|
|
22
|
-
### 2. No Build Step Required
|
|
23
|
-
|
|
24
|
-
Drop a `<script>` tag in your HTML and you're ready to go. Build tools are optional, not mandatory.
|
|
25
|
-
|
|
26
|
-
### 3. True Reactivity
|
|
27
|
-
|
|
28
|
-
Change an object → the DOM updates. That's it. No `setState`, no `dispatch`, no `computed properties` to configure.
|
|
29
|
-
|
|
30
|
-
```js
|
|
31
|
-
// This just works
|
|
32
|
-
component._studs.count++;
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### 4. Web Standards First
|
|
36
|
-
|
|
37
|
-
Lego uses:
|
|
38
|
-
- **Web Components** - Standard custom elements
|
|
39
|
-
- **Shadow DOM** - Native encapsulation
|
|
40
|
-
- **ES6 Proxies** - For reactivity
|
|
41
|
-
- **Template literals** - For templating
|
|
42
|
-
|
|
43
|
-
No proprietary APIs. Everything is built on web standards.
|
|
44
|
-
|
|
45
|
-
## When to Use Lego
|
|
46
|
-
|
|
47
|
-
### ✅ Lego is Great For:
|
|
48
|
-
|
|
49
|
-
- **Small to medium applications** where framework overhead isn't worth it
|
|
50
|
-
- **Embedded widgets** that need to work anywhere
|
|
51
|
-
- **Progressive enhancement** of existing sites
|
|
52
|
-
- **Learning** how reactive systems work under the hood
|
|
53
|
-
- **Projects** where you want full control and no dependencies
|
|
54
|
-
|
|
55
|
-
### ⚠️ Consider Alternatives If:
|
|
56
|
-
|
|
57
|
-
- You need a massive ecosystem of pre-built components
|
|
58
|
-
- Your team is already invested in React/Vue/Angular
|
|
59
|
-
- You need SSR (Server-Side Rendering) out of the box
|
|
60
|
-
- You're building something extremely complex with hundreds of components
|
|
61
|
-
|
|
62
|
-
## How Small Is It?
|
|
63
|
-
|
|
64
|
-
The core library (`main.js`) is **under 500 lines** of well-commented JavaScript.
|
|
65
|
-
|
|
66
|
-
- **No dependencies** - Zero `node_modules` bloat
|
|
67
|
-
- **~22KB** - Unminified, human-readable code
|
|
68
|
-
- **~7KB** - Minified and gzipped
|
|
69
|
-
|
|
70
|
-
Compare that to:
|
|
71
|
-
- Vue 3: ~33KB (minified + gzipped)
|
|
72
|
-
- React + ReactDOM: ~40KB (minified + gzipped)
|
|
73
|
-
- Angular: ~100KB+ (minified + gzipped)
|
|
74
|
-
|
|
75
|
-
## What Makes It Different?
|
|
76
|
-
|
|
77
|
-
| Aspect | Lego | Traditional Frameworks |
|
|
78
|
-
|--------|--------|----------------------|
|
|
79
|
-
| **Reactivity** | Direct object mutation | setState / dispatch / ref() |
|
|
80
|
-
| **Templates** | HTML with <code v-pre>[[ ]]</code> | JSX / template syntax |
|
|
81
|
-
| **Styles** | Shadow DOM (native) | CSS-in-JS / scoped CSS |
|
|
82
|
-
| **Build** | Optional | Required |
|
|
83
|
-
| **Learning Curve** | Hours | Days/Weeks |
|
|
84
|
-
|**Philosophy** | Embrace the platform | Abstract the platform |
|
|
85
|
-
|
|
86
|
-
## Next Steps
|
|
87
|
-
|
|
88
|
-
Ready to dive in? Head to the [Getting Started](/guide/getting-started) guide to build your first component in under 5 minutes.
|
package/docs/guide/lifecycle.md
DELETED
|
@@ -1,525 +0,0 @@
|
|
|
1
|
-
# Lifecycle Hooks
|
|
2
|
-
|
|
3
|
-
Learn about component lifecycle hooks in Lego.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Components have three lifecycle hooks:
|
|
8
|
-
|
|
9
|
-
- `mounted()` - Called after component is added to DOM
|
|
10
|
-
- `updated()` - Called after state changes and re-render
|
|
11
|
-
- `unmounted()` - Called when component is removed from DOM
|
|
12
|
-
|
|
13
|
-
## mounted()
|
|
14
|
-
|
|
15
|
-
Called once when the component is first attached to the DOM.
|
|
16
|
-
|
|
17
|
-
### Usage
|
|
18
|
-
|
|
19
|
-
```js
|
|
20
|
-
{
|
|
21
|
-
data: null,
|
|
22
|
-
|
|
23
|
-
mounted() {
|
|
24
|
-
console.log('Component is now in the DOM');
|
|
25
|
-
this.fetchData();
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
async fetchData() {
|
|
29
|
-
this.data = await fetch('/api/data').then(r => r.json());
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Common Use Cases
|
|
35
|
-
|
|
36
|
-
**Fetch Data:**
|
|
37
|
-
```js
|
|
38
|
-
{
|
|
39
|
-
mounted() {
|
|
40
|
-
this.loadUserData();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**Start Timers:**
|
|
46
|
-
```js
|
|
47
|
-
{
|
|
48
|
-
timer: null,
|
|
49
|
-
|
|
50
|
-
mounted() {
|
|
51
|
-
this.timer = setInterval(() => {
|
|
52
|
-
this.tick();
|
|
53
|
-
}, 1000);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**Add Event Listeners:**
|
|
59
|
-
```js
|
|
60
|
-
{
|
|
61
|
-
mounted() {
|
|
62
|
-
window.addEventListener('resize', this.handleResize.bind(this));
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Initialize Third-Party Libraries:**
|
|
68
|
-
```js
|
|
69
|
-
{
|
|
70
|
-
mounted() {
|
|
71
|
-
this.chart = new Chart(this.$element.shadowRoot.querySelector('canvas'), {
|
|
72
|
-
type: 'bar',
|
|
73
|
-
data: this.chartData
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## updated()
|
|
80
|
-
|
|
81
|
-
Called after every state change and re-render.
|
|
82
|
-
|
|
83
|
-
### Usage
|
|
84
|
-
|
|
85
|
-
```js
|
|
86
|
-
{
|
|
87
|
-
count: 0,
|
|
88
|
-
|
|
89
|
-
updated() {
|
|
90
|
-
console.log('Component re-rendered, count is:', this.count);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Common Use Cases
|
|
96
|
-
|
|
97
|
-
**Track Changes:**
|
|
98
|
-
```js
|
|
99
|
-
{
|
|
100
|
-
previousValue: null,
|
|
101
|
-
value: 0,
|
|
102
|
-
|
|
103
|
-
updated() {
|
|
104
|
-
if (this.value !== this.previousValue) {
|
|
105
|
-
console.log('Value changed from', this.previousValue, 'to', this.value);
|
|
106
|
-
this.previousValue = this.value;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Update Third-Party Libraries:**
|
|
113
|
-
```js
|
|
114
|
-
{
|
|
115
|
-
chartData: [],
|
|
116
|
-
|
|
117
|
-
updated() {
|
|
118
|
-
if (this.chart) {
|
|
119
|
-
this.chart.data = this.chartData;
|
|
120
|
-
this.chart.update();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
**Analytics:**
|
|
127
|
-
```js
|
|
128
|
-
{
|
|
129
|
-
updated() {
|
|
130
|
-
if (window.gtag) {
|
|
131
|
-
gtag('event', 'state_change', {
|
|
132
|
-
component: 'my-component',
|
|
133
|
-
count: this.count
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
::: warning Performance
|
|
141
|
-
`updated()` runs on every state change. Keep it lightweight!
|
|
142
|
-
:::
|
|
143
|
-
|
|
144
|
-
## unmounted()
|
|
145
|
-
|
|
146
|
-
Called when the component is removed from the DOM.
|
|
147
|
-
|
|
148
|
-
### Usage
|
|
149
|
-
|
|
150
|
-
```js
|
|
151
|
-
{
|
|
152
|
-
unmounted() {
|
|
153
|
-
console.log('Component is being removed');
|
|
154
|
-
this.cleanup();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Common Use Cases
|
|
160
|
-
|
|
161
|
-
**Clear Timers:**
|
|
162
|
-
```js
|
|
163
|
-
{
|
|
164
|
-
timer: null,
|
|
165
|
-
|
|
166
|
-
mounted() {
|
|
167
|
-
this.timer = setInterval(() => this.tick(), 1000);
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
unmounted() {
|
|
171
|
-
clearInterval(this.timer);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Remove Event Listeners:**
|
|
177
|
-
```js
|
|
178
|
-
{
|
|
179
|
-
handleResize: null,
|
|
180
|
-
|
|
181
|
-
mounted() {
|
|
182
|
-
this.handleResize = () => {
|
|
183
|
-
this.width = window.innerWidth;
|
|
184
|
-
};
|
|
185
|
-
window.addEventListener('resize', this.handleResize);
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
unmounted() {
|
|
189
|
-
window.removeEventListener('resize', this.handleResize);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**Destroy Third-Party Instances:**
|
|
195
|
-
```js
|
|
196
|
-
{
|
|
197
|
-
chart: null,
|
|
198
|
-
|
|
199
|
-
mounted() {
|
|
200
|
-
this.chart = new Chart(...);
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
unmounted() {
|
|
204
|
-
if (this.chart) {
|
|
205
|
-
this.chart.destroy();
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**Cancel Pending Requests:**
|
|
212
|
-
```js
|
|
213
|
-
{
|
|
214
|
-
controller: null,
|
|
215
|
-
|
|
216
|
-
async fetchData() {
|
|
217
|
-
this.controller = new AbortController();
|
|
218
|
-
try {
|
|
219
|
-
const data = await fetch('/api/data', {
|
|
220
|
-
signal: this.controller.signal
|
|
221
|
-
}).then(r => r.json());
|
|
222
|
-
this.data = data;
|
|
223
|
-
} catch (err) {
|
|
224
|
-
if (err.name === 'AbortError') {
|
|
225
|
-
console.log('Fetch aborted');
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
|
|
230
|
-
unmounted() {
|
|
231
|
-
if (this.controller) {
|
|
232
|
-
this.controller.abort();
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Performance Hooks (Metrics)
|
|
241
|
-
|
|
242
|
-
For advanced monitoring, LegoDOM provides global hooks in `Lego.config.metrics`. These run for **every** component.
|
|
243
|
-
|
|
244
|
-
### `onRenderStart` & `onRenderEnd`
|
|
245
|
-
|
|
246
|
-
Useful for tracking how long renders take, which helps identify slow components.
|
|
247
|
-
|
|
248
|
-
```javascript
|
|
249
|
-
Lego.config.metrics = {
|
|
250
|
-
onRenderStart(el) {
|
|
251
|
-
console.time(`render-${el.tagName}`);
|
|
252
|
-
},
|
|
253
|
-
onRenderEnd(el) {
|
|
254
|
-
console.timeEnd(`render-${el.tagName}`);
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### `onAllSettled` (New in v2.0)
|
|
260
|
-
|
|
261
|
-
Called when the entire component tree (including Shadow DOM children) has finished its initial render pass. This is perfect for removing loading spinners or measuring "Time to Interactive".
|
|
262
|
-
|
|
263
|
-
```javascript
|
|
264
|
-
/* main.js */
|
|
265
|
-
Lego.init(document.body).then(() => {
|
|
266
|
-
document.getElementById('global-loader').remove();
|
|
267
|
-
});
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## Lifecycle Flow
|
|
271
|
-
|
|
272
|
-
```
|
|
273
|
-
1. Component created (HTML element instantiated)
|
|
274
|
-
2. Shadow DOM attached
|
|
275
|
-
3. Template rendered
|
|
276
|
-
4. mounted() hook called → Component is interactive
|
|
277
|
-
5. User interaction / state change
|
|
278
|
-
6. Component re-rendered
|
|
279
|
-
7. updated() hook called
|
|
280
|
-
8. (repeat steps 5-7 as needed)
|
|
281
|
-
9. Component removed from DOM
|
|
282
|
-
10. unmounted() hook called → Cleanup
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
## Complete Example
|
|
286
|
-
|
|
287
|
-
```js
|
|
288
|
-
{
|
|
289
|
-
// State
|
|
290
|
-
count: 0,
|
|
291
|
-
timer: null,
|
|
292
|
-
data: null,
|
|
293
|
-
|
|
294
|
-
// Lifecycle: Component mounted
|
|
295
|
-
mounted() {
|
|
296
|
-
console.log('[mounted] Component added to DOM');
|
|
297
|
-
|
|
298
|
-
// Fetch initial data
|
|
299
|
-
this.fetchData();
|
|
300
|
-
|
|
301
|
-
// Start interval
|
|
302
|
-
this.timer = setInterval(() => {
|
|
303
|
-
this.count++;
|
|
304
|
-
}, 1000);
|
|
305
|
-
|
|
306
|
-
// Add event listener
|
|
307
|
-
this.handleKeyPress = (e) => {
|
|
308
|
-
if (e.key === 'Escape') {
|
|
309
|
-
this.reset();
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
document.addEventListener('keydown', this.handleKeyPress);
|
|
313
|
-
},
|
|
314
|
-
|
|
315
|
-
// Lifecycle: Component updated
|
|
316
|
-
updated() {
|
|
317
|
-
console.log('[updated] Component re-rendered, count:', this.count);
|
|
318
|
-
|
|
319
|
-
// Log when count reaches milestone
|
|
320
|
-
if (this.count % 10 === 0) {
|
|
321
|
-
console.log('Milestone:', this.count);
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
|
|
325
|
-
// Lifecycle: Component unmounted
|
|
326
|
-
unmounted() {
|
|
327
|
-
console.log('[unmounted] Component removed from DOM');
|
|
328
|
-
|
|
329
|
-
// Clear interval
|
|
330
|
-
if (this.timer) {
|
|
331
|
-
clearInterval(this.timer);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Remove event listener
|
|
335
|
-
document.removeEventListener('keydown', this.handleKeyPress);
|
|
336
|
-
},
|
|
337
|
-
|
|
338
|
-
// Methods
|
|
339
|
-
async fetchData() {
|
|
340
|
-
this.data = await fetch('/api/data').then(r => r.json());
|
|
341
|
-
},
|
|
342
|
-
|
|
343
|
-
reset() {
|
|
344
|
-
this.count = 0;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
## Best Practices
|
|
350
|
-
|
|
351
|
-
### 1. Initialize in mounted()
|
|
352
|
-
|
|
353
|
-
Don't fetch data or start timers in the state object:
|
|
354
|
-
|
|
355
|
-
```js
|
|
356
|
-
// ❌ Bad
|
|
357
|
-
{
|
|
358
|
-
data: fetch('/api/data').then(r => r.json()), // Executes immediately
|
|
359
|
-
timer: setInterval(() => {}, 1000) // Starts before component exists
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// ✅ Good
|
|
363
|
-
{
|
|
364
|
-
data: null,
|
|
365
|
-
timer: null,
|
|
366
|
-
mounted() {
|
|
367
|
-
this.fetchData();
|
|
368
|
-
this.timer = setInterval(() => {}, 1000);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### 2. Always Clean Up
|
|
374
|
-
|
|
375
|
-
If you start something in `mounted()`, stop it in `unmounted()`:
|
|
376
|
-
|
|
377
|
-
```js
|
|
378
|
-
{
|
|
379
|
-
mounted() {
|
|
380
|
-
this.timer = setInterval(...);
|
|
381
|
-
window.addEventListener('resize', this.handleResize);
|
|
382
|
-
},
|
|
383
|
-
|
|
384
|
-
unmounted() {
|
|
385
|
-
clearInterval(this.timer); // ✅
|
|
386
|
-
window.removeEventListener('resize', this.handleResize); // ✅
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
### 3. Keep updated() Light
|
|
392
|
-
|
|
393
|
-
`updated()` runs frequently—avoid heavy operations:
|
|
394
|
-
|
|
395
|
-
```js
|
|
396
|
-
// ❌ Bad
|
|
397
|
-
{
|
|
398
|
-
updated() {
|
|
399
|
-
this.expensiveCalculation(); // Runs on every change!
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// ✅ Good
|
|
404
|
-
{
|
|
405
|
-
updated() {
|
|
406
|
-
// Only log or track
|
|
407
|
-
console.log('State changed');
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
### 4. Guard Against Errors
|
|
413
|
-
|
|
414
|
-
```js
|
|
415
|
-
{
|
|
416
|
-
unmounted() {
|
|
417
|
-
// Check before clearing
|
|
418
|
-
if (this.timer) {
|
|
419
|
-
clearInterval(this.timer);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Check before destroying
|
|
423
|
-
if (this.chart) {
|
|
424
|
-
this.chart.destroy();
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
## Common Patterns
|
|
431
|
-
|
|
432
|
-
### Loading State
|
|
433
|
-
|
|
434
|
-
```js
|
|
435
|
-
{
|
|
436
|
-
loading: true,
|
|
437
|
-
data: null,
|
|
438
|
-
|
|
439
|
-
async mounted() {
|
|
440
|
-
try {
|
|
441
|
-
this.data = await fetch('/api/data').then(r => r.json());
|
|
442
|
-
} finally {
|
|
443
|
-
this.loading = false;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### Polling
|
|
450
|
-
|
|
451
|
-
```js
|
|
452
|
-
{
|
|
453
|
-
pollInterval: null,
|
|
454
|
-
|
|
455
|
-
mounted() {
|
|
456
|
-
this.poll();
|
|
457
|
-
this.pollInterval = setInterval(() => this.poll(), 5000);
|
|
458
|
-
},
|
|
459
|
-
|
|
460
|
-
async poll() {
|
|
461
|
-
this.data = await fetch('/api/status').then(r => r.json());
|
|
462
|
-
},
|
|
463
|
-
|
|
464
|
-
unmounted() {
|
|
465
|
-
clearInterval(this.pollInterval);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
### Scroll Position
|
|
471
|
-
|
|
472
|
-
```js
|
|
473
|
-
{
|
|
474
|
-
scrollY: 0,
|
|
475
|
-
handleScroll: null,
|
|
476
|
-
|
|
477
|
-
mounted() {
|
|
478
|
-
this.handleScroll = () => {
|
|
479
|
-
this.scrollY = window.scrollY;
|
|
480
|
-
};
|
|
481
|
-
window.addEventListener('scroll', this.handleScroll);
|
|
482
|
-
},
|
|
483
|
-
|
|
484
|
-
unmounted() {
|
|
485
|
-
window.removeEventListener('scroll', this.handleScroll);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### Animation
|
|
491
|
-
|
|
492
|
-
```js
|
|
493
|
-
{
|
|
494
|
-
mounted() {
|
|
495
|
-
const el = this.$element.shadowRoot.querySelector('.animated');
|
|
496
|
-
el.classList.add('fade-in');
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
## Debugging Lifecycle
|
|
502
|
-
|
|
503
|
-
Log lifecycle events to understand component behavior:
|
|
504
|
-
|
|
505
|
-
```js
|
|
506
|
-
{
|
|
507
|
-
mounted() {
|
|
508
|
-
console.log('[LIFECYCLE] mounted');
|
|
509
|
-
},
|
|
510
|
-
|
|
511
|
-
updated() {
|
|
512
|
-
console.log('[LIFECYCLE] updated');
|
|
513
|
-
},
|
|
514
|
-
|
|
515
|
-
unmounted() {
|
|
516
|
-
console.log('[LIFECYCLE] unmounted');
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
## Next Steps
|
|
522
|
-
|
|
523
|
-
- See [lifecycle examples](/examples/)
|
|
524
|
-
- Learn about [component patterns](/guide/components)
|
|
525
|
-
- Explore [state management](/guide/reactivity)
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Quick Start
|
|
2
|
-
|
|
3
|
-
The fastest way to get started with Lego is using the CDN. No build tools required!
|
|
4
|
-
|
|
5
|
-
## 1. Create an HTML file
|
|
6
|
-
|
|
7
|
-
```html
|
|
8
|
-
<!DOCTYPE html>
|
|
9
|
-
<html lang="en">
|
|
10
|
-
<head>
|
|
11
|
-
<meta charset="UTF-8">
|
|
12
|
-
<title>Lego Quick Start</title>
|
|
13
|
-
</head>
|
|
14
|
-
<body>
|
|
15
|
-
<!-- Interpolation works here too -->
|
|
16
|
-
<hello-world name="Lego"></hello-world>
|
|
17
|
-
|
|
18
|
-
<!-- 3. Define the template -->
|
|
19
|
-
<template b-id="hello-world">
|
|
20
|
-
<style>
|
|
21
|
-
h1 { color: #646cff; }
|
|
22
|
-
</style>
|
|
23
|
-
<h1>Hello [[ name ]]!</h1>
|
|
24
|
-
<button @click="count++">Count is [[ count ]]</button>
|
|
25
|
-
</template>
|
|
26
|
-
|
|
27
|
-
<!-- 4. Load Lego -->
|
|
28
|
-
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
29
|
-
|
|
30
|
-
<!-- 5. Define logic & Init -->
|
|
31
|
-
<script>
|
|
32
|
-
document.querySelector('hello-world').state = {
|
|
33
|
-
name: 'World',
|
|
34
|
-
toggle() {
|
|
35
|
-
this.name = this.name === 'World' ? 'Lego' : 'World';
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Start the engine
|
|
40
|
-
Lego.init();
|
|
41
|
-
</script>
|
|
42
|
-
</body>
|
|
43
|
-
</html>
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Next Steps
|
|
47
|
-
|
|
48
|
-
- Explore [Core Concepts](/guide/components)
|
|
49
|
-
- Check out the [API Reference](/api/)
|