Coder Social home page Coder Social logo

cycle-time-travel's Introduction

Cycle.js

logo
A functional and reactive JavaScript framework for predictable code

Welcome

Question Answer
"I want to learn Cycle.js" Read the official documentation
"I have a question" Create a StackOverflow question
Or
Join the chat
Or
Open an issue
Please note all discussion-like issues are labeled discussion and immediately closed. This doesn't mean we unconsidered your discussion. We only leave actual issues open.
"I found a bug" Open an issue
"I want to help build Cycle.js" Read the Contributing guides
Then
Choose an issue marked "help wanted"

Packages

Cycle.js is comprised of many specialized packages. This repository contains all these packages, e.g., the npm package @cycle/run lives in the directory run. Below you will find a summary of each package.

Package Version Dependencies DevDependencies
@cycle/dom npm (scoped) Dependency Status devDependency Status
@cycle/history npm (scoped) Dependency Status devDependency Status
@cycle/html npm (scoped) Dependency Status devDependency Status
@cycle/http npm (scoped) Dependency Status devDependency Status
@cycle/isolate npm (scoped) Dependency Status devDependency Status
@cycle/most-run npm (scoped) Dependency Status devDependency Status
@cycle/run npm (scoped) Dependency Status devDependency Status
@cycle/rxjs-run npm (scoped) Dependency Status devDependency Status

Globally: Build Status devDependency Status

Stream libraries

The following packages are not under Cycle.js, but are important dependencies, so we display their latest versions for convenience.

Package Version
most npm version
rxjs npm version
xstream npm version

Support OpenCollective OpenCollective

Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]

Backers

Support us with a monthly donation and help us continue our activities. [Become a backer]

Thanks

Browserstack

Browserstack for providing access to their great cross-browser testing tools.

LICENSE

The MIT License


JS.ORG ComVer

cycle-time-travel's People

Contributors

greenkeeperio-bot avatar widdershin 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  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  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  avatar  avatar  avatar  avatar

Watchers

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

cycle-time-travel's Issues

Set up Travis CI

Hi @staltz,

I want to set up travis, but I don't have permission to enable it for this repo. Could you do it for me please?

😄

Major breaking change suggestion

@Widdershin I think I just came up with a (hopefully) brilliant idea to make time travelling more automatic, with less customizations to do inside application code.

So far we have been tracking streams inside main. What if we would track only source streams, and all of them? By source I mean responses here:

function main(responses) {
  // ...
}

In other words, everything that drivers output. The time travelling panel would then show only these response observables, making it agnostic to main's internals. In a way the information it would display would be only "what went into the application". This will mostly represent the user's actions, but it can also represent HTTP responses, or anything coming from drivers.

The inspiration to this came when I was thinking about Flux/Redux's actions and how time travelling is all about rewinding/replaying actions. I started thinking about what actions represent, and in Cycle.js the main's semantics are clear: input are events from the outside world represented by drivers (user + server + etc) and output is the program's behavior. To implement global time travel we just need to replay driver responses.


On a more technical level, to do this, we would need to wrap drivers, for example:

Cycle.run(main, {
  DOM: wrapWithTimeTraveling(makeDOMDriver('.app')),
});

wrapWithTimeTraveling intercepts output Observables, and stores their events in a list. Then, to rewind, we need to somehow restart the program (maybe call Cycle.run again?) and make the wrapped output Observable emit events stored in the history. The reason why we need to restart the program is that this approach doesn't touch the app's internal state, so we need to reset it. Probably not super fast approach, but definitely solves the problem. The wrapped output Observable is probably most easily implemented internally as a subject, although there might be a nice way of making it just an Observable.

Then there is the problem of how to actually intercept the output Observable from drivers. If the driver is a simple function (input: Observable): Observable, then it's dumb easy. But the DOM driver isn't, it's function (vtree$: Observable): SelectableCollection, where SelectableCollection has .select(). Somehow wrapWithTimeTraveling would need to be aware that the DOM driver returns SelectableCollection and not a plain Observable, and then mimic that SelectableCollection.

On the other hand, we could think of pushing this responsability to drivers, so a driver should provide an implementation of its time traveled variant. This could be a convention for drivers. If they support it, then they would work, if they don't support it, then their outputs simply wouldn't appear in the time traveling panel and it wouldn't be used. This way we can mark some drivers as "Time Traveling Ready™".

Maybe one way of trivially doing this is giving an option to the driver:

var timeTraveler = renderTimeTravelingDebuggerAt('#container');

makeDOMDriver('#app', {timeTravel: timeTraveler});
// pretend that object isn't anymore for custom elements

I am pretty happy with this approach, also for testing and debugging. It's actually not hard at all to intercept a driver's output and log all events from its output observables to console.log or even some remote service like with websockets. In Flux world this is common to use actions as the full log of "what happened" in the app. In Cycle.js it would be similar, but the log has more low-level data, and doesn't leave anything out.

What do you think?

Allow scoping the time travel vtree$ or something else

Currently the implementation does DOM.get('.stream', 'mousemove') which is dangerous in case the application has elements with classname stream. To avoid this global problem, you can use namespaced nested dialogues. Read here http://staltz.com/unidirectional-user-interface-architectures.html and see this example: https://github.com/cyclejs/todomvc-cycle/blob/master/src/components/todo-item.js#L5-L7

That would require adding another parameter name to makeTimeTravel, but should suffice.

PS: it really looks like makeTimeTravel is just another nested dialogue. Meaning it's a Cycle.js component. I prefer the name timeTravel instead of makeTimeTravel (the former is a dialogue function, the latter sounds like a factory, reminds me of driver factories). I'm also more and more considering to use an uppercase naming convention for dialogues (TimeTravel, MagicButton, MyFavoriteComponent, etc), I know this convention is normally used for OOP in JavaScript, but Cycle.js isn't anyway OOP. Well, I'm going too far with this PS.

Support Cycle.js Diversity

Add support for the next version of Cycle.js which is stream agnostic. Possibly porting to xstream (as the other core drivers are doing) or possibly in a stream agnostic fashion like the history driver.

Suggestion to make API simpler

Instead of this:

let {DOM: timeTravelBar$, timeTravel} = makeTimeTravel(DOM, [
    {stream: count$, label: 'count$'},          
    {stream: action$, label: 'action$'}      
  ]);

How about this?

let {DOM: timeTravelBar$, timeTravel} = makeTimeTravel(DOM, {
  count$,
  action$
});

You can loop over the properties of an object and get its key. That above was sugar for ES5:

let {DOM: timeTravelBar$, timeTravel} = makeTimeTravel(DOM, {
  count$: count$,
  action$: action$
});

Meaning you will have both the key as a string and the value. Gladly ES6 makes it easy to avoid this repetition.

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.