Git Product home page Git Product logo

sekoia's Introduction



Scalable reactive application architecture built on living web standards with a focus on micro-optimized performance, semantic APIs and customElements that don't suck. 🥺 👉👈

All major browsers

Sekoia.js // Vanilla ES6 - All major browsers

🧬 Micro-optimized reactivity engine

Sekoia is powered by an advanced reactivity engine that enhances serializable data with first-class observability, time travel, shape and type consistency and insanely optimized state diffing.

⚡️ Data driven custom elements

Sekoia gives your UI code structure by making native customElements reactive and composable while facilitating architecturally clean access to the DOM.


Router

Pretty advanced hash-based router for SPAs with reactive route actions and route filtering for conditional re-routes. I don't have time to document it rn.

Server

Simple REST API helper with request buffering and indexedDB caching plus cache expiration. Nothing too fancy.

Utils

Common functions that are shared by internal modules and are also useful for implementation code of high-performance web apps.

License

Sekoia.js 
Copyright (C) 2022  Jonathan M. Ochmann 

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see https://www.gnu.org/licenses.

Author

Jonathan M. Ochmann (@monokee)


Made with ♥️ in CGN | (C) Patchflyer GmbH 2014-2049

sekoia's People

Contributors

monokee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

sekoia's Issues

Scoped CSS

Comma separated selectors (BUG)

$ref .selector, $ref .another-selector {
  font-size: 12px;
}

incorrectly rewritten to:

component-name .selector, .another-selector {
  font-size: 12px;
}

(The selector after the comma is not scoped)

Media Queries require !important (ENHANCEMENT)

Rules in media queries that are overriding previously declared rules need to be suffixed with !important or the rules are ignored. This is expected and standard CSS behaviour because stylesheets are parsed top to bottom. Media queries do not introduce higher selector specificity so it would be a nice enhancement if Cue could bundle the media queries internally and append them to the bottom of the stylesheet.

Compile time optimisations (ENHANCEMENT)

Consider compile time parsing -> bundling, auto-prefixing and minification.
Remove the CSS template strings from cue javascript components entirely and write them into a distributable CSS package which can be autoprefixed and minified, further reducing initial page load times because both reduced bundle size and reduced cycles now spent on parsing the CSS on a per-component level.

[Component] Slots in template cause empty markup

When element(s) are defined in component.define('...', { element:

...
})
the element has no innerHTML.

Note that this only happens for elements that are defined via Component.define().
It works as expected for Compnent.extend().

Computed Properties: Dependency resolution bug

Stumbled upon the following case:

Update county -> Changes Tax -> recalculate total
Update quantity -> changes priceBeforeDiscount & tax

  • priceBeforeDiscount -> changes subTotal -> changes total
  • Tax -> changes total

In this case Total is computed from subtotal (computed from priceBeforeDiscount + tax)
and Tax (not computed).
So subtotal needs to be resolved before total. Current implementation is buggy b/c total is recalculated first.

Change attribute handling to work like reactions

"attributes" in Component config object should work just like data object.
Attributes should accept value and reaction parameters to provide default attribute values and utilize the same reaction functionality (with refs access)

Async observers may fire with identical data

This is rarely a problem but it's theoretically possible that observers fire the same state value they fired with their previous invocation because state diffing and observer queueing is synchronous but the invocation of observer handlers happens asynchronously in the next available frame (or in the case of throttled/deferred observers after a user-specified timeout)

Consider the following scenario:

async_state

  1. Observed state changes to a new value.
  2. Sekoia queues the states observers.
  3. The observers are waiting for the next frame or for their defer/throttle timeout to pass.
  4. The state value changes back to the initial value while the observers are waiting.
  5. The observers fire with the same value they fired previously because they have been queued during intermediate state changes.

The naive fix (as currently implemented in ReactiveObject.track()) is to do a deepEqual comparison of values before firing observers during queue flushing.

However this should be avoided for regular observers since we would then basically do the same work twice. Once during synchronous state patching and then again when observers are resolved.

I previously had an implementation that deferred patchData() to the next frame but that introduced the much worse issue of stale intermediate state. (State.get(x) === 0 | State.set(x, 1) | State.get(x) === 0) Another problem with this implementation was that the relatively complex resolution of computedProperties, bound properties and ancestor bubbling became unmanageably convoluted.

I think what I need is a smarter alternative to brute-forced deepEqual(). Some information we can extract during the first and last patchData() calls in a given event queue that can be quickly compared before firing handlers but I don't know what that would look like right now...

Store refactor

  • Re-think storage persistence.
  • Store.get() w/o parameter should return entire store object

Bindings can only point to single instances

It's not possible to define dynamic graphs with the current implementation. Bindings are defined per model, not per instance and the binding value can not be overwritten when creating object instances of the model. Every instance of a model points to a single bound instance, forcing many-to-one graphs.

The current implementation is severely limiting and should be enhanced to support dynamic, many-to-many relational graphs.

Adding some demo code to the readme

Hi !
This engine seems really promising but it's hard to see how it works without even a small example of the code.
What about a simple hello world demo sample or a classic counter with two buttons ?

Compile Time Optimizations

CSS Engine

Consider compile time parsing -> bundling, auto-prefixing and minification.
Remove the CSS template strings from cue javascript components entirely and write them into a distributable CSS package which can be autoprefixed and minified, further reducing initial page load times due to reduced bundle size and less cpu cycles spent on parsing/scoping/appending the CSS on a per-component level.

Should this be written as a gulp plugin or as a rollup plugin?

CSS engine needs work

Complex selection is not working as expected.
For example:

self:hover refName {
  color: red;
}

is not converted to

my-component:hover [ref="refName"] {
  color: red;
}

and there are likely more bugs and quirks.

Add support for Components w/o specified element

Check if element exists, else use empty template.

Module.template = document.createRange().createContextualFragment(
    `<cue-template>${element ? element.trim() : ''}</cue-template>`
).firstChild;

This allows for external definition of element markup (HTML, SSR...)

Component.define should return HTML string

To facilitate esm syntax, Component.define should return the tagName of the custom element
embedded into < > html tags so that the return value can be simply added into the markup of a parent component which imports the component.

Computed Properties don't dispatch "data" event

Custom "data" event is currently dispatched in calls to Component.setData(). This means that computations don't fire the event when their value changes.

Proposed solution:
Fire "data" events from within Reactor in the cue loop. This should simplify the event dispatching because we no longer have to distinguish between normal properties, store-bound properties and computed properties.

Decide on synchronous vs asynchronous data handling

The current implementation of the reactor is a brute-force approach to auto-batch incoming change requests to avoid multiple iterations of the same computations or reactions. This batching is done by scheduling the computation until the next available frame via the browsers RAF interface which makes the reactor and all data handling asynchronous.

If this behaviour is how we want to progress in the future Component.set()and ```Store.set````
both have to return a promise object.
If we decide against asynchronous data setting we have to refactor to a non-raf based, synchronous reactor.

Pros of asynchronous reactor
Many subsequent requests to change the same piece of data will only result in a single execution of the data's side effects (computations, reactions). Consider a slider that is being dragged by a user which can easily result in more data change requests than reactions which can be painted onto the screen on a frame by frame basis. By buffering reactions to such inputs to only execute once per available frame we essentially optimize the engine for the purpose of user interface drawing which is good.
This could be a good place to more deeply integrate the (currently rather pointless) Server object or more generally all asynchronous tasks such as network requests. Side effects like computations and even reactions could contain arbitrary async logic.

Cons of asynchronous reactor
Syntax in user implemented code becomes less straight forward as we move away from simple synchronous procedural logic to the asynchronous promise syntax. This could be confusing as the data changes are really synchronous in nature as far as the user can tell because there are no network requests or user implemented timeouts.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.