@lightningjs/blits 1.29.3 → 1.29.5

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ _12 jun 2025_
4
+
5
+ ## v1.29.5
6
+
7
+ - Simplified timeout and interval cleanup
8
+ - Added explicit reset of component state upon destruction
9
+ - Fixed `exit` lifecycle hook
10
+
11
+ _06 jun 2025_
12
+
13
+ ## v1.29.4
14
+
15
+ - Removed excessive shader creation for effects
16
+ - Added explicit cleanup of effects in for loop
17
+ - Improved element destruction
18
+
3
19
  _03 jun 2025_
4
20
 
5
21
  ## v1.29.3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "1.29.3",
3
+ "version": "1.29.5",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -47,7 +47,7 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "@lightningjs/msdf-generator": "^1.1.1",
50
- "@lightningjs/renderer": "^2.13.2"
50
+ "@lightningjs/renderer": "^2.13.4"
51
51
  },
52
52
  "repository": {
53
53
  "type": "git",
@@ -66,13 +66,22 @@ export default {
66
66
  value: function () {
67
67
  this.eol = true
68
68
  this.lifecycle.state = 'destroy'
69
+
70
+ for (let key in this[symbols.state]) {
71
+ if (Array.isArray(this[symbols.state][key])) {
72
+ this[symbols.state][key] = []
73
+ }
74
+ }
75
+
69
76
  this.$clearTimeouts()
70
77
  this.$clearIntervals()
71
78
  eventListeners.removeListeners(this)
72
79
  deleteChildren(this[symbols.children])
73
80
  this[symbols.children].length = 0
74
81
  removeGlobalEffects(this[symbols.effects])
82
+
75
83
  this[symbols.state] = {}
84
+
76
85
  this[symbols.props] = {}
77
86
  this[symbols.computed] = null
78
87
  this.lifecycle = {}
@@ -22,9 +22,10 @@ export default {
22
22
  value: function (fn, ms, ...params) {
23
23
  // early exit when component is marked as end of life
24
24
  if (this.eol === true) return
25
+
25
26
  const timeoutId = setTimeout(
26
27
  () => {
27
- this[symbols.timeouts] = this[symbols.timeouts].filter((id) => id !== timeoutId)
28
+ this.$clearTimeout(timeoutId)
28
29
  fn.apply(null, params)
29
30
  },
30
31
  ms,
@@ -39,8 +40,9 @@ export default {
39
40
  },
40
41
  $clearTimeout: {
41
42
  value: function (timeoutId) {
42
- if (this[symbols.timeouts].indexOf(timeoutId) > -1) {
43
- this[symbols.timeouts] = this[symbols.timeouts].filter((id) => id !== timeoutId)
43
+ const index = this[symbols.timeouts].indexOf(timeoutId)
44
+ if (index > -1) {
45
+ this[symbols.timeouts].splice(index, 1)
44
46
  clearTimeout(timeoutId)
45
47
  }
46
48
  },
@@ -73,9 +75,10 @@ export default {
73
75
  },
74
76
  $clearInterval: {
75
77
  value: function (intervalId) {
76
- if (this[symbols.intervals].indexOf(intervalId) > -1) {
77
- this[symbols.intervals] = this[symbols.intervals].filter((id) => id !== intervalId)
78
- clearInterval(intervalId)
78
+ const index = this[symbols.intervals].indexOf(intervalId)
79
+ if (index > -1) {
80
+ this[symbols.intervals].splice(index, 1)
81
+ clearTimeout(intervalId)
79
82
  }
80
83
  },
81
84
  writable: false,
package/src/component.js CHANGED
@@ -195,6 +195,8 @@ const Component = (name = required('name'), config = required('config')) => {
195
195
  // generate a human readable ID for the component instance (i.e. Blits::ComponentName1)
196
196
  this.componentId = createHumanReadableId(name)
197
197
 
198
+ this[symbols.effects] = []
199
+
198
200
  // instantiate a lifecycle object for this instance
199
201
  this.lifecycle = Object.assign(Object.create(Lifecycle), {
200
202
  component: this,
@@ -296,7 +298,7 @@ const Component = (name = required('name'), config = required('config')) => {
296
298
 
297
299
  // outOfViewport event emitting a lifecycle exit event
298
300
  if (config.hooks.exit) {
299
- this[symbols.wrapper].node.on('outOfViewport', () => {
301
+ this[symbols.wrapper].node.on('outOfBounds', () => {
300
302
  this.lifecycle.state = 'exit'
301
303
  })
302
304
  }
@@ -305,7 +307,6 @@ const Component = (name = required('name'), config = required('config')) => {
305
307
  // setup (and execute) all the generated side effects based on the
306
308
  // reactive bindings define in the template
307
309
  const effects = config.code.effects
308
- this[symbols.effects] = []
309
310
  for (let i = 0; i < effects.length; i++) {
310
311
  const eff = () => {
311
312
  effects[i](this, this[symbols.children], config, globalComponents, rootComponent, effect)
@@ -322,8 +322,8 @@ test('Component - Instance should initialize hook events', (assert) => {
322
322
  )
323
323
  assert.equal(
324
324
  nodeCalls[3].args[0],
325
- 'outOfViewport',
326
- '`outOfViewport` event should be registered in the wrapper'
325
+ 'outOfBounds',
326
+ '`outOfBounds` event should be registered in the wrapper'
327
327
  )
328
328
  assert.end()
329
329
  })
@@ -381,34 +381,12 @@ const propsTransformer = {
381
381
  v[i].props.color = colors.normalize(v[i].props.color)
382
382
  }
383
383
  }
384
- const effectNames = {}
385
384
  if (this.element.node === undefined) {
386
- this.element.effectNames = []
387
385
  this.props['shader'] = renderer.createShader('DynamicShader', {
388
386
  effects: v.map((effect) => {
389
- let name = effect.type
390
- if (effectNames[name] !== undefined) {
391
- name += ++effectNames[name]
392
- } else {
393
- effectNames[name] = 1
394
- }
395
- name += this.element.counter
396
- this.element.effectNames.push(name)
397
- // temporary add counter to work around shader caching issues
398
- return renderer.createEffect(effect.type, effect.props, name)
387
+ return renderer.createEffect(effect.type, effect.props)
399
388
  }),
400
389
  })
401
- } else {
402
- for (let i = 0; i < v.length; i++) {
403
- const name = this.element.effectNames[i]
404
- // temporary add counter to work around shader caching issues
405
- const target = this.element.node.shader.props[name]
406
- const props = Object.keys(v[i].props)
407
- if (target == undefined) continue
408
- for (let j = 0; j < props.length; j++) {
409
- target[props[j]] = v[i].props[props[j]]
410
- }
411
- }
412
390
  }
413
391
  },
414
392
  set clipping(v) {
@@ -674,7 +652,7 @@ const Element = {
674
652
  return
675
653
  }
676
654
  // fire transition end callback when animation ends (if specified)
677
- if (transition.end && typeof transition.end === 'function') {
655
+ if (this.node !== undefined && transition.end && typeof transition.end === 'function') {
678
656
  transition.end.call(this.component, this, prop, this.node[prop])
679
657
  }
680
658
  // remove the prop from scheduled transitions
@@ -687,9 +665,7 @@ const Element = {
687
665
  destroy() {
688
666
  if (this.node === null) return
689
667
 
690
- Log.debug('Deleting Node', this.nodeId)
691
- this.node.destroy()
692
-
668
+ Log.debug('Deleting Node', this.nodeId)
693
669
  // Clearing transition end callback functions
694
670
  const transitionProps = Object.keys(this.scheduledTransitions)
695
671
  for (let i = 0; i < transitionProps.length; i++) {
@@ -700,7 +676,32 @@ const Element = {
700
676
  }
701
677
  }
702
678
 
703
- // remove node reference
679
+ // not setting to null and deleting,
680
+ // because transition stopped might still be fired (maybe a renderer fix resolves that)
681
+ this.scheduledTransitions = {}
682
+
683
+ this.component = null
684
+ delete this.component
685
+
686
+ this.config = null
687
+ delete this.config
688
+
689
+ this.counter = null
690
+ delete this.counter
691
+
692
+ this.props.raw = {}
693
+ this.props.element = null
694
+ this.props.props = null
695
+ this.props = {}
696
+ delete this.props
697
+
698
+ this.triggerLayout = null
699
+ delete this.triggerLayout
700
+
701
+ this.forComponent = null
702
+ delete this.forComponent
703
+
704
+ this.node.destroy()
704
705
  this.node = null
705
706
  },
706
707
  get nodeId() {
@@ -738,7 +739,6 @@ export default (config, component) => {
738
739
  scheduledTransitions: {},
739
740
  config,
740
741
  component,
741
- effectNames: [],
742
742
  counter: counter++,
743
743
  })
744
744
  }
@@ -511,6 +511,7 @@ const generateForLoopCode = function (templateObject, parent) {
511
511
  }
512
512
  effect(eff${index}, ${key})
513
513
  effects.push(eff${index})
514
+ component[Symbol.for('effects')].push(eff${index})
514
515
  `)
515
516
  } else {
516
517
  // props shouldn't be wrapped in an effect, but simply passed on
@@ -562,17 +563,21 @@ const generateForLoopCode = function (templateObject, parent) {
562
563
 
563
564
  ctx.renderCode.push(`
564
565
  let forEffects${forStartCounter}
565
- effect(() => {
566
+ const eff${forStartCounter} = () => {
566
567
  component[Symbol.for('removeGlobalEffects')](forEffects${forStartCounter})
567
568
  forEffects${forStartCounter} = null
568
569
  forEffects${forStartCounter} = forloop${forStartCounter}(${cast(
569
570
  result[2],
570
571
  ':for'
571
572
  )}, elms, created${forStartCounter})
572
- }, ['${effectKey}', ${effectKeys.join(',')}] )
573
+ }
574
+
575
+ component[Symbol.for('effects')].push(eff${forStartCounter})
576
+
577
+ effect(eff${forStartCounter}, ['${effectKey}', ${effectKeys.join(',')}] )
573
578
  `)
574
579
 
575
- outerScopeEffects.forEach((effect) => {
580
+ outerScopeEffects.forEach((effect, outerScopeEffectsIndex) => {
576
581
  const matches = [...effect.matchAll(scopeRegex)]
577
582
 
578
583
  let l = matches.length
@@ -589,7 +594,7 @@ const generateForLoopCode = function (templateObject, parent) {
589
594
  }
590
595
 
591
596
  ctx.renderCode.push(`
592
- effect(() => {
597
+ const eff${forStartCounter}_${outerScopeEffectsIndex} = () => {
593
598
  void ${refs.join(', ')}
594
599
  for(let __index = 0; __index < ${interpolate(result[2])}.length; __index++) {
595
600
  if(__index < from${forStartCounter} || __index >= to${forStartCounter}) continue
@@ -602,7 +607,9 @@ const generateForLoopCode = function (templateObject, parent) {
602
607
  ctx.renderCode.push(`
603
608
  ${effect}
604
609
  }
605
- })
610
+ }
611
+ component[Symbol.for('effects')].push(eff${forStartCounter}_${outerScopeEffectsIndex})
612
+ effect(eff${forStartCounter}_${outerScopeEffectsIndex})
606
613
  `)
607
614
  })
608
615