diff --git a/CHANGELOG.md b/CHANGELOG.md index 76e48a02..6f9fae6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog + +## v1.5.1 + +_7 oct 2024_ + +- Added export of symbols +- Various small performance improvements related to component creation + ## v1.5.0 _1 oct 2024_ diff --git a/package-lock.json b/package-lock.json index 85481d41..c9e7a571 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@lightningjs/blits", - "version": "1.5.0", + "version": "1.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@lightningjs/blits", - "version": "1.5.0", + "version": "1.5.1", "license": "Apache-2.0", "dependencies": { "@lightningjs/msdf-generator": "^1.0.2", diff --git a/package.json b/package.json index 63b5f90e..565dd418 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lightningjs/blits", - "version": "1.5.0", + "version": "1.5.1", "description": "Blits: The Lightning 3 App Development Framework", "bin": "bin/index.js", "exports": { @@ -8,7 +8,8 @@ "./vite": "./vite/index.js", "./transitions": "./src/router/transitions/index.js", "./precompiler": "./src/lib/precompiler/precompiler.js", - "./plugins": "./src/plugins/index.js" + "./plugins": "./src/plugins/index.js", + "./symbols": "./src/lib/symbols.js" }, "scripts": { "test": "c8 npm run test:run", diff --git a/src/component.js b/src/component.js index 40ddfeb2..bfe16595 100644 --- a/src/component.js +++ b/src/component.js @@ -51,7 +51,7 @@ const required = (name) => { * */ const Component = (name = required('name'), config = required('config')) => { - let base + let base = undefined const component = function (opts, parentEl, parentComponent, rootComponent) { // generate a human readable ID for the component instance (i.e. Blits::ComponentName1) @@ -89,11 +89,10 @@ const Component = (name = required('name'), config = required('config')) => { // apply the state function (passing in the this reference to utilize configured props) // and store a reference to this original state - // hasFocus key is sprinkled in - this[symbols.originalState] = { - ...((config.state && typeof config.state === 'function' && config.state.apply(this)) || {}), - ...{ hasFocus: false }, - } + this[symbols.originalState] = + (config.state && typeof config.state === 'function' && config.state.apply(this)) || {} + // add hasFocus key in + this[symbols.originalState]['hasFocus'] = false // generate a reactive state (using the result of previously execute state function) // and store it @@ -162,7 +161,6 @@ const Component = (name = required('name'), config = required('config')) => { // reactive bindings define in the template const effects = config.code.effects for (let i = 0; i < effects.length; i++) { - // console.log(config.code.effects[i].toString()) effect(() => { effects[i](this, this[symbols.children], config, globalComponents, rootComponent, effect) }) @@ -170,12 +168,14 @@ const Component = (name = required('name'), config = required('config')) => { // setup watchers if the components has watchers specified if (this[symbols.watchers]) { - Object.keys(this[symbols.watchers]).forEach((watchKey) => { + const watcherkeys = Object.keys(this[symbols.watchers]) + const watcherkeysLength = watcherkeys.length + for (let i = 0; i < watcherkeysLength; i++) { let target = this - let key = watchKey + let key = watcherkeys[i] // when dot notation used, find the nested target - if (watchKey.indexOf('.') > -1) { - const keys = watchKey.split('.') + if (key.indexOf('.') > -1) { + const keys = key.split('.') key = keys.pop() for (let i = 0; i < keys.length; i++) { target = target[keys[i]] @@ -187,23 +187,13 @@ const Component = (name = required('name'), config = required('config')) => { effect((force = false) => { const newValue = target[key] if (old !== newValue || force === true) { - this[symbols.watchers][watchKey].apply(this, [newValue, old]) + this[symbols.watchers][key].apply(this, [newValue, old]) old = newValue } }) - }) + } } - // set all symbol based properties to non-enumerable and non-configurable - Object.getOwnPropertySymbols(this).forEach((property) => { - Object.defineProperties(this, { - [property]: { - enumerable: false, - configurable: false, - }, - }) - }) - // finaly set the lifecycle state to ready (in the next tick) setTimeout(() => (this.lifecycle.state = 'ready')) @@ -214,7 +204,10 @@ const Component = (name = required('name'), config = required('config')) => { const factory = (options = {}, parentEl, parentComponent, rootComponent) => { if (Base[symbols['launched']] === false) { // Register user defined plugins once on the Base object (after launch) - Object.keys(plugins).forEach((pluginName) => { + const pluginKeys = Object.keys(plugins) + const pluginKeysLength = pluginKeys.length + for (let i = 0; i < pluginKeysLength; i++) { + const pluginName = pluginKeys[i] const prefixedPluginName = `$${pluginName}` if (prefixedPluginName in Base) { Log.warn( @@ -231,7 +224,7 @@ const Component = (name = required('name'), config = required('config')) => { enumerable: true, configurable: false, }) - }) + } // register global components once globalComponents = components() @@ -241,13 +234,13 @@ const Component = (name = required('name'), config = required('config')) => { } // setup the component once per component type, using Base as the prototype - if (!base) { + if (base === undefined) { Log.debug(`Setting up ${name} component`) base = setupComponent(Object.create(Base), config) } // one time code generation (only if precompilation is turned off) - if (!config.code) { + if (config.code === undefined) { Log.debug(`Generating code for ${name} component`) config.code = codegenerator.call(config, parser(config.template, name)) } diff --git a/src/component/setup/props.js b/src/component/setup/props.js index 25134dba..63b0123f 100644 --- a/src/component/setup/props.js +++ b/src/component/setup/props.js @@ -29,20 +29,23 @@ export default (component, props = []) => { props.push('ref') } component[symbols.propKeys] = [] - props.forEach((prop) => { - prop = { ...baseProp, ...(typeof prop === 'object' ? prop : { key: prop }) } + + const propsLength = props.length + + for (let i = 0; i < propsLength; i++) { + const prop = { ...baseProp, ...(typeof props[i] === 'object' ? props[i] : { key: props[i] }) } component[symbols.propKeys].push(prop.key) Object.defineProperty(component, prop.key, { get() { const value = prop.cast( - this[symbols.props] && prop.key in this[symbols.props] + this[symbols.props] !== undefined && prop.key in this[symbols.props] ? this[symbols.props][prop.key] : 'default' in prop ? prop.default : undefined ) - if (prop.required && value === undefined) { + if (prop.required === true && value === undefined) { Log.warn(`${prop.key} is required`) } @@ -53,5 +56,5 @@ export default (component, props = []) => { this[symbols.props][prop.key] = v }, }) - }) + } } diff --git a/src/component/setup/state.js b/src/component/setup/state.js index c7c98c4c..3f0face4 100644 --- a/src/component/setup/state.js +++ b/src/component/setup/state.js @@ -27,13 +27,23 @@ export default (component, state = () => {}) => { writable: false, }) - const stateKeys = Object.keys(state.apply(component) || {}).concat(['hasFocus']) + const stateKeys = Object.keys(state.apply(component) || {}) + // add built-in hasFocus key + stateKeys.push(['hasFocus']) + const stateKeysLength = stateKeys.length - stateKeys.forEach((key) => { - if (component[symbols.propKeys] && component[symbols.propKeys].indexOf(key) > -1) { + for (let i = 0; i < stateKeysLength; i++) { + const key = stateKeys[i] + if ( + component[symbols.propKeys] !== undefined && + component[symbols.propKeys].indexOf(key) > -1 + ) { Log.error(`State ${key} already exists as a prop`) } - if (component[symbols.methodKeys] && component[symbols.methodKeys].indexOf(key) > -1) { + if ( + component[symbols.methodKeys] !== undefined && + component[symbols.methodKeys].indexOf(key) > -1 + ) { Log.error(`State ${key} already exists as a method`) } component[symbols.stateKeys].push(key) @@ -44,7 +54,6 @@ export default (component, state = () => {}) => { set(v) { this[symbols.state][key] = v }, - // enumerable: true, }) - }) + } }