The tiny framework for building hypertext applications.

Overview

Hyperapp

The tiny framework for building hypertext applications.

  • Do more with less—We have minimized the concepts you need to learn to get stuff done. Views, actions, effects, and subscriptions are all pretty easy to get to grips with and work together seamlessly.
  • Write what, not how—With a declarative API that's easy to read and fun to write, Hyperapp is the best way to build purely functional, feature-rich, browser-based apps in JavaScript.
  • Smaller than a favicon—1 kB, give or take. Hyperapp is an ultra-lightweight Virtual DOM, highly-optimized diff algorithm, and state management library obsessed with minimalism.

Here's the first example to get you started—look ma' no bundlers! Try it in your browser.

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module">
      import { h, text, app } from "https://unpkg.com/hyperapp"

      const AddTodo = (state) => ({
        ...state,
        value: "",
        todos: state.todos.concat(state.value),
      })

      const NewValue = (state, event) => ({
        ...state,
        value: event.target.value,
      })

      app({
        init: { todos: [], value: "" },
        view: ({ todos, value }) =>
          h("main", {}, [
            h("h1", {}, text("To do list")),
            h("input", { type: "text", oninput: NewValue, value }),
            h("ul", {},
              todos.map((todo) => h("li", {}, text(todo)))
            ),
            h("button", { onclick: AddTodo }, text("New!")),
          ]),
        node: document.getElementById("app"),
      })
    </script>
  </head>
  <body>
    <main id="app"></main>
  </body>
</html>

Now that you have poked around the code a bit, you may have some questions. What is init and view, and how do they fit together? The app starts off with init, where we set the initial state. The view returns a plain object that represents how we want the DOM to look (the virtual DOM) and Hyperapp takes care of modifying the actual DOM to match this specification whenever the state changes. That's really all there is to it.

Ready to dive in? Learn the basics in the tutorial or visit the API reference for more documentation. If you prefer to learn by studying real-world examples, you can browse our awesome list of resources too.

Installation

Install Hyperapp with npm or Yarn:

npm i hyperapp

Then with a module bundler like Rollup or Webpack import it in your application and get right down to business.

import { h, text, app } from "hyperapp"

Don't want to set up a build step? Import Hyperapp in a <script> tag as a module. Don't worry; modules are supported in all evergreen, self-updating desktop, and mobile browsers.

<script type="module">
  import { h, text, app } from "https://unpkg.com/hyperapp"
</script>

Packages

Official packages provide access to The Web Platform, and ensure that the APIs are exposed in a way that makes sense for Hyperapp, and the underlying code is stable. We already cover a decent amount of features, but you can always create your own effects and subscriptions if something is not available yet.

Package Status About
@hyperapp/dom npm Inspect the DOM, focus and blur.
@hyperapp/svg npm Draw SVG with plain functions.
@hyperapp/html npm Write HTML with plain functions.
@hyperapp/time npm Subscribe to intervals, get the time now.
@hyperapp/http npm Talk to servers, make HTTP requests.
@hyperapp/events npm Subscribe to mouse, keyboard, window, and frame events.
@hyperapp/random npm Declarative random numbers and values.
@hyperapp/navigation npm Subscribe and manage the browser URL history.

Help, I'm stuck!

Don't panic! If you've hit a stumbling block, hop on our Discord server to get help, and if you don't receive an answer, or if you remain stuck, please file an issue, and we'll figure it out together.

Contributing

Hyperapp is free and open source software. If you love Hyperapp, becoming a contributor or sponsoring is the best way to give back. Thank you to everyone who already contributed to Hyperapp!

License

MIT

Comments
  • Components

    Components

    Let's discuss how components could look like in a future version of HyperApp.

    Submitted Proposals

    • https://gist.github.com/zaceno/83286dfd2a18ebbd3b4f1d7cb5810a0c via @zaceno
    • https://gist.github.com/Swizz/8437df6ac5ec4985e72e648d242f6a9f via @Swizz

    Example

    counter.js

    const Counter = (props, children) => ({
      state: {
        value: props.value
      },
      view: ({ value }, { inc, dec }) =>
        <div>
          <h1>{state.value}</h1>
          <button onclick={inc}>+</button>
          <button onclick={dec}>-</button>
        </div>,
      actions: {
        inc: state => state + 1,
        dec: state => state - 1
      }
    })
    

    index.js

    app({
      state: {
        title: "Hello."
      },
      view: (state, actions) =>
        <main>
          <h1>{state.title}</h1>
          <Counter value={1} />
        </main>
    })
    

    Credits

    All credit goes to @MatejMazur:

    • https://github.com/MatejMazur/hyperapp
    • https://github.com/MatejMazur/hyperapp-component-experiment

    Related

    • #147
    • #219
    discussion 
    opened by jorgebucaran 171
  • RFC: Hyperapp 2.0

    RFC: Hyperapp 2.0

    Note: This is not an April Fool's Day prank! 😄

    Background

    After a lot of debate and enduring weeks of inner turmoil, I've decided to move forward with a series of drastic changes that will be eventually released as Hyperapp 2.0.

    Predictable as it may be, my plan was to leave things the way they are here and create a new JavaScript framework. A direct competitor to Hyperapp, but pretty much the same under the hood. I am calling that off and going to focus on making a better Hyperapp instead!

    Breaking changes again? I am afraid so. I'm unsatisfied with how some things work in Hyperapp and want to fix them to the bone, not start a brand new project. I don't think I will be able to fairly concentrate on two projects that have exactly the same goal when what differentiates them are just some subtle (but important) API differences.

    What will change?

    With 2.0 I intend to fix several pain points I've experienced with Hyperapp due to its extreme DIY-ness. In the words of @okwolf:

    Hyperapp holds firm on the functional programming front when managing your state, but takes a pragmatic approach to allowing for side effects, asynchronous actions, and DOM manipulations.

    Hyperapp is minimal and pragmatic and I don't want to change it but in order to improve, we need to do more for the user. So, this is what I am going to focus on:

    • Easy to test — By making actions and effects pure, testing will be a piece of cake.
    • All Things Dynamic — First class support for code splitting and dynamically loading actions and views using import(), e.g., dynamic(import("./future-component")). Fix https://github.com/hyperapp/hyperapp/issues/533.
    • Cleaner Action API — Eliminate the confusing concept of "wired actions". The new actions will be regular, unwired & untapped JavaScript functions.
    • Subscriptions — Introduce a subscriptions API inspired by Elm.
    • Make Hyperapp more suitable for multi-app design (running multiple apps on a single page).
    • Types — Make Hyperapp typing simpler and easier to get right.

    Show me the money!

    The Simple Counter

    Let's begin with a simple counter and kick it up a notch afterward.

    import { h, app } from "hyperapp"
    
    const down = state => ({ count: state.count - 1 })
    const up = state => ({ count: state.count + 1 })
    
    app({
      init: { count: 0 },
      view: state => (
        <div>
          <h1>{state.count}</h1>
          <button onclick={down}>-1</button>
          <button onclick={up}>+1</button>
        </div>
      ),
      container: document.body
    })
    

    The biggest surprise here is that you no longer need to pass the actions to the app() call, wait for them to be wired to state changes and receive them inside the view or any of that wacky stuff. It just works.

    How to pass data into the action? ~~Just use JavaScript.~~

    You can create a closure that receives the data and returns a function that HA expects num => state => ({ count: state.count + num }) or use the tuple syntax (preferable) as shown below.

    const downBy = (state, num) => ({ count: state.count - num })
    
    const view = state => (
      <div>
        <h1>{state.count}</h1>
        <button onclick={down}>-</button>
        <button onclick={up}>+1</button>
        <button onclick={[downBy, 10]}>-10</button>
      </div>
    )
    

    This looks very similar to 1.0, the difference is that the curried function is completely justified now — not built-in or forced upon you.

    Here's an interesting way you will be able to reset the count.

    const view = state => (
      <div>
        <h1>{state.count}</h1>
        <button onclick={{ count: 0 }}>Reset</button>
        <button onclick={down}>-1</button>
        <button onclick={up}>+1</button>
      </div>
    )
    

    Yes, you just put the value { count: 0 } there and you're done.

    Side Effects

    Ok, time to cut to the chase. How are going to do async stuff now?

    import { h, app } from "hyperapp"
    import { delay } from "@hyperapp/fx"
    
    const up = state => ({ count: state.count + 1 })
    
    // This is how we define an effect (Elm calls it commands).
    const delayedUp = delay(1000, up)
    
    app({
      init: { count: 0 },
      view: state => (
        <div>
          <h1>{state.count}</h1>
          <button onclick={up}>+1</button>
          <button onclick={delayedUp}>+1 with delay</button>
        </div>
      ),
      container: document.body
    })
    

    What if I want to set the state to something and cause a side effect to happen at the same time? I have you covered (almost). In Elm, they have tuples, but in JavaScript we only have arrays. So, let's use them.

    const down = state => ({ count: state.count - 1 })
    const up = state => ({ count: state.count + 1 })
    const delayedUp = delay(1000, up)
    const eventuallyDidNothing = state => [down(state), delayedUp]
    

    Notice that creating a function for actions and effects is A Good Practice, but nothing prevents you from doing this:

    const eventuallyDidNothing = state => [
      { count: state.count - 1 },
      delay(1000, state => ({
        count: state.count + 1
      }))
    ]
    

    What about a full example that fetches some information on initialization? The following example is ported from Hyperapp + Hyperapp FX here.

    import { h, app } from "hyperapp"
    import { http } from "@hyperapp/fx"
    import { url } from "./utils"
    
    const quoteFetched = (state, [{ content }]) => ({ quote: content })
    const getNewQuote = http(url, quoteFetched)
    
    app({
      init: () => [{ quote: "Loading..." }, getNewQuote],
      view: state => <h1 onclick={getNewQuote} innerHTML={state.quote} />,
      container: document.body
    })
    

    Handling data from DOM events?

    DOM events, like effects, produce a result or have data associated with them (http fetch response, DOM event, etc).

    const textChanged = (state, event) => ({ text: event.target.value })
    
    app({
      init: { text: "Hello!" },
      view: state => (
        <main>
          <h1>{state.text}</h1>
          <input value={state.text} oninput={textChanged} />
        </main>
      )
    })
    

    Interoperability

    Absolutely. The app function will now return a dispatch function (instead of "wired actions") so you can execute actions or effects at will.

    const { dispatch } = app(...)
    
    // And then later from another app or program...
    
    dispatch(action)
    // or
    dispatch(effect) // Time.out, Http.fetch, etc.
    

    Dynamic Imports

    What about dynamic imported components out of the box?

    import { h, app, dynamic } from "hyperapp"
    
    const Hello = dynamic({
      loader: () => import("./Hello.js"),
      loading: <h1>Loading...</h1>
    })
    
    app({
      init: { name: "Bender" },
      view: state => <Hello name={state.name} />,
      container: document.body
    })
    

    Subscriptions

    There's one more important new feature: Subscriptions. Aptly ripped off Elm's subscriptions, this is how we are going to listen for external input now.

    import { h, app } from "hyperapp"
    import { Mouse } from "@hyperapp/subscriptions" // I am open to a shorter name.
    
    const positionChanged = (state, mouse) => ({ x: mouse.x, y: mouse.y })
    
    const main = app({
      init: {
        x: 0,
        y: 0
      },
      view: state => `${state.x}, ${state.y}`,
      subscriptions: state => [Mouse.move(positionChanged)],
      container: document.body
    })
    

    What's breaking?

    • Slices will be gone. There will be other mechanism to easily update props deeply nested, but other than that bye bye slices.
    • Obviously, actions that cause side effects will need to be upgraded to use managed FX, which should be a joy — you'll love FX. I don't believe this will be a particular difficult feat, but we'll see. For 1.0 migration help and support I've created a #1to2 channel in Slack, please join! 🎉

    Other

    • Middleware

    • Some things are still undecided. Should Hyperapp export all side effects? Perhaps we can reuse @hyperapp/fx for that?

    • I am going to remove slices! But now that actions are decoupled from the state update mechanism, we should be able to come up with similar patterns doing something similar to Redux's combineReducers.

    • Actions return a new state (not a partial state), so you need to merge the current state with whatever you return, similar to redux.

    • Lifecycle events? I am still not sure how to handle these. For now, I'll keep them the way they are.

    • Bundle size? All the core stuff is, in fact, less than current Hyperapp, but adding effects to that will makes us closer to 2 kB.

    • My interests have shifted to care more code readability and less about code golfing. A tiny code base is still a big priority for me, but not at the expense of making the code unreadable.

    • Server side rendering? I'm torn on this one. Should it be available out of the box or should we continue using @hyperapp/render? I am going to need @frenzzy to chime on this one.

    • JSX, @hyperapp/html, hyperx, h. Nothing is changing about here.

    • The router will continue to be an external module.

    • I'm still working hard to improve the performance and 2.0 will not affect https://github.com/hyperapp/hyperapp/issues/499 or https://github.com/hyperapp/hyperapp/pull/663. I suspect 2.0 will have slightly better performance out of the box because of how DOM events are going to be handled now.

    When is this going to be available?

    Very soon. I'll be pushing all the stuff to the fringe branch and publish as [email protected] as soon as I can so we all can start playing with this.

    Related

    • https://github.com/jorgebucaran/ultradom/issues/108
    • https://github.com/hyperapp/hyperapp/issues/641
    discussion outdated 
    opened by jorgebucaran 160
  • Dynamic actions: How to add new actions at runtime?

    Dynamic actions: How to add new actions at runtime?

    Summary

    There is currently no way to add actions dynamically.

    • Why do I want the ability to add actions at runtime? (Code splitting, etc.)
    • Why do I want code splitting?
      • But why do you even need code splitting? Why not instead consider making a simpler app? If you've reached this extreme situation, why not creating multiple apps? Those should definitely be "code-splittable" without intervention from the core.
      • Why not be aware that an SPA is no different from an actual app you'd download like from an "app store". What about implementing a one-time install screen?
    • What about route-based code splitting? I think this is what Elm plans to do for 0.19.
    • What would be the simplest, non-breaking way to add this functionality? How would it look like on a simple app?

    Related

    https://github.com/hyperapp/hyperapp/issues/439

    enhancement discussion outdated 
    opened by jorgebucaran 124
  • Modules in V2

    Modules in V2

    💁‍♂ Check out the current proposal here.


    Consider this minimal example of a modular Elm app (copied from here):

    Button.elm
    module Button exposing (Model, Msg(..), init, update, view)
    
    import Html exposing (Html, button, div, h1, text)
    import Html.Events exposing (onClick)
    
    
    
    -- MODEL
    
    
    type alias Model =
        Int
    
    
    init : Model
    init =
        0
    
    
    
    -- UPDATE
    
    
    type Msg
        = Increment
        | Decrement
    
    
    update : Msg -> Model -> Model
    update msg model =
        case Debug.log "Button.update msg: " msg of
            Increment ->
                model + 1
    
            Decrement ->
                model - 1
    
    
    view : Model -> Html Msg
    view model =
        div []
            [ button [ onClick Decrement ] [ text "-" ]
            , div [] [ text (String.fromInt model) ]
            , button [ onClick Increment ] [ text "+" ]
            ]
    
    Main.elm
    type alias Model =
        { button : Button.Model }
    
    
    init : Model
    init =
        { button = Button.init
        }
    
    
    
    -- UPDATE
    
    
    type Msg
        = ButtonMsg Button.Msg
    
    
    update : Msg -> Model -> Model
    update msg model =
        case Debug.log "update msg" msg of
            ButtonMsg buttonMsg ->
                { model | button = Button.update buttonMsg model.button }
    
    
    
    -- VIEW
    
    
    view : Model -> Html Msg
    view model =
        div []
            [ h1 [] [ text "elm button example" ]
            , map ButtonMsg (Button.view model.button)
            ]
    
    

    Notice two things:

    A) Increment and Decrement are completely unaware of the shape of the global app state. Their definitions are completely self contained.

    B) Main.elm never once explicitly references Increment or Decrement.

    As far as I've been able to tell, this is not possible to achieve using Hyperapp 2. You can have A or B but not both. This has frightening implications for large scale apps.

    I would like to see a convention, add-on library or core change -- or some combination of all three -- which enabled us to replicate the example above in Hyperapp v2.

    That essentially means being able to use a module which defines its actions in a self-contained, app-agnostic way, without being required to export them. They should not need to be explicitly referenced anywhere else.

    Additionally, whatever we come up with, I would also want it to work in a recursive fashion, that is to say: a module can use a module which uses modules ...

    EDIT: Also, of course, this shouldn't just apply to actions dispatched from views. It should be the same for actions dispatched from Effects (whatever action initiated the effect), and subscriptions.

    discussion 
    opened by zaceno 117
  • Combine the concept of state and actions into models 🤯

    Combine the concept of state and actions into models 🤯

    EDIT: @Alber70g suggested an even more extreme simplification:

    Instead of app({ model, view }, root)app(model, view, root), but we can discuss that on another issue.

    We did it once and here we go again. Like everything, there are trade-offs involved, not to mention the pain that comes with the churn. There's also "done is better than perfect", but Hyperapp is not done yet, and we still have some time before 1.0. I need your help to evaluate if this idea holds or not, and identify possible drawbacks or disadvantages.

    The proposal (via @Alber70g) is to combine the concepts of state and actions into a new abstraction: models. A model is a regular object that holds your state props and actions.

    The typical counter would look like this:

    app({
      model: {
        count: 0,
        down: () => model => ({ count: model.count - 1 }),
        up: () => model => ({ count: model.count + 1 })
      },
      view: model => (
        <main>
          <h1>{model.count}</h1>
          <button onclick={model.down}>–</button>
          <button onclick={model.up}>+</button>
        </main>
      )
    })
    

    An application that is wired to state and actions from multiple sources, could look like this:

    app({
      model: {
        A,
        B,
        C,
        D
      }
    })
    

    Instead of the current:

    app({
      state: {
        A: state.A,
        B: state.B,
        C: state.C,
        D: state.D
      },
      actions: {
        A: actions.A,
        B: actions.B,
        C: actions.C,
        D: actions.D
      }
    })
    

    And an app that subscribes to external events.

    const { tick } = app({
      model: {
        time: Date.now(),
        tick: () => ({ time: Date.now() })
      },
      view: model => <Clock time={model.time} />
    })
    
    setInterval(tick, 1000)
    

    You can see that the app() now returns the wired model, so you can access not only actions, but also state props.

    Now, you can think of models like a "module" that contains your state and actions under the same namespace.

    // A counter model
    const counter = {
      count: 0,
      add: n => model => ({ count: model.count + n })
    }
    
    app({
      model: { counter },
      view: ({ counter }) => (
        <main>
          <h1>{counter.count}</h1>
          <button onclick={e => counter.add(1)}>Add</button>
        </main>
      )
    })
    

    Notice how usage of the model inside the view function mirrors how you define the model above.

    Pros

    • Simplify your code (save bytes!)
    • Simplify core (save bytes!)

    Cons

    • Breaking change
    • Complicate saving the state to local storage, as you will have to exclude actions from the model before you save:
    saveToStorage(withoutActions(model))
    

    Notes

    • No impact on how slices work.
    discussion wontfix 
    opened by jorgebucaran 66
  • Road to 1.0

    Road to 1.0

    • [x] ~~Components #238~~ (See https://github.com/hyperapp/hyperapp/issues/238#issuecomment-312455621)
    • [x] Use requestAnimationFrame to throttle render/patch #90
    • [x] Add SSR DOM hydration
    • [x] Improve documentation
      • [x] Explain what types are allowed in the state prop
    • [x] Homepage #146 @lukejacksonn
    • [x] DTD by @Swizz
    • ~~[ ] Flow by @andyrj? #323 #311~~
    • ~~[ ] Optimize patch?~~ Post-1.0
    discussion 
    opened by jorgebucaran 66
  • Add connected components

    Add connected components

    Connected Components

    Why?

    Currently all components are dumb components. Given a component hierarchy A->B->C->D->E. If Component E needed access to state.name then components A, B, C, and D would each need to be updated to pass along state.name. This causes components to become tightly coupled, or written generically so that all state and actions are handed down to every child component, because of the "you never know when you'll need it" mentality.

    The Solution

    Natively support both dumb components and connected components.

    Normal dumb component signature:

    const Component = (props, children) => (
      <div>Hello</div>
    );
    

    Connected component signature:

    const ConnectedComponent = (props, children) => (state, actions) => (
      <div>Hello, {state.name}</div>
    );
    

    This solution does not require use of either a Higher Order App or a Higher Order Component.

    How does it work?

    In hyperapp's render function, whenever the view is processed, the resulting object tree is traversed. Any child node that is a function is called with the globalState and wiredActions.

    This change raised the gzip size by ~30 bytes.

    enhancement discussion 
    opened by etalisoft 65
  • What documentation would you like to see here?

    What documentation would you like to see here?

    The goal of this issue is to collect feedback about what stuff should be covered in the official documentation.

    • What do you think about the current documentation?
    • What's missing in the documentation?
      • What topics would you like to see covered?
    • If it was up to you, how would you structure/layout the documentation?
    • What makes great documentation?
    • How can we keep the documentation minimal and still useful?
    docs 
    opened by jorgebucaran 61
  • Hyperapp V2

    Hyperapp V2

    Summary

    👋 V2 is the pet name for the next version (2.0.0) of Hyperapp. Be sure to subscribe to this PR if you want to be informed of the progress towards the release. I'm still open to feedback and ideas, so share your feedback freely!

    To learn more about the upcoming architecture changes check the issue list below.

    Status Progress

    • [ ] Docs (65%) 🌶
    • [ ] Tests
    • [x] Core
      • [x] Implement Action API #750 #751
      • [x] Implement the Effect API #750
        • [x] Add built-in batching for effects
      • [x] Implement Subscriptions API #752
      • [x] Optimize defer function (setTimeout to use faster Promise.resolve)
    • [x] VDOM
      • [x] Improve performance #499
      • [x] Lazy lists #721
      • [ ] ~~Dynamic components #760~~
      • [x] Add built-in classcat-like support for className attribute
    • [ ] ~~Typings~~

    Try it!

    npm i hyperapp@beta
    
    enhancement breaking 
    opened by jorgebucaran 59
  • Lazy components

    Lazy components

    • Lazy execute components at runtime, probably it may save computation in some cases
    • It will be possible to easily extend component with connect proposal, ref #604
    • It will be possible to compile JSX right into virtual node objects avoiding h function with components support, ref #564
    enhancement discussion 
    opened by frenzzy 58
  • What about setState?

    What about setState?

    Recently effects and reducers got merged into actions. Now the way to set the state is by just retuning an object.

    What about exposing a actions.setState function which can be called from everywhere where actions are available instead? This way an effect could still return whatever it wants when called by a different action (I actually used that a lot) and code like this becomes easier to do:

    function example () {
    	actions.room.set(room) // reducer
    	actions.room.socket.join() // effect
    	// the key here is that socket.join depends on model.room
    }
    
    function example () {
    	actions.setState({room})
    	actions.room.socket.join()
    }
    

    This would also fix use-cases where big actions need to be split into multiple actions, but need to return data that is not a promise. Hard to describe, but I actually also used that for WebRTC SDP patching. I worked around this, but overall I think that this might make hyperapp easier to use for more advanced apps.

    And yes, I'm aware that setState() would basically be implemented as setState: (_, data) => data.

    discussion 
    opened by FlorianWendelborn 51
  • @hyperapp/html: use a Proxy?

    @hyperapp/html: use a Proxy?

    In modern browsers, can we use a Proxy instead of hard coding all the element types?

    I'm using this right now:

        import { h } from "./lib/hyperapp.js";
    
        const { main, h1, input, ul, li, button } = new Proxy(h, {
          get(h, type) { return (props, children) => h(type, props, children) }
        });
    

    One more line of code, and you have support for custom elements:

        const { hyperApp } = new Proxy(h, {
          get(h, type) {
            const name = type.replace(/([A-Z])/g, c => "-" + c.toLowerCase());
            return (props, children) => h(name, props, children)
          }
        });
    
        console.log(hyperApp({foo:"bar"}, ["baz"])); // type: "hyper-app"
    

    Thoughts? :-)

    enhancement 
    opened by mindplay-dk 9
  • hyperapp version

    hyperapp version

    Newbie here, two questions regarding versions:

    • the releases page (https://github.com/jorgebucaran/hyperapp/releases) tags 1.2.9 as "latest", does that mean 2.x is not production ready ? are there still breaking changes planned ?
    • the same page shows the latest available as 2.0.0 but npm has 2.0.20, is there a changelog somewhere ?

    Basically what version should a new project go for and where is that documented

    Thanks!

    opened by kofifus 3
  • The dispatch initializer ends in an endless loop on init when dispatching any action

    The dispatch initializer ends in an endless loop on init when dispatching any action

    I'm trying to use the the dispatch initializer as it is in the example with a log effect

    const middleware = (dispatch) => 
      (action, payload) => {
        // Dispatch anonymous action which triggers logging effect.
        dispatch((state) => [state, log(state)]) 
        
        // Afterwards, carry on normally.
        dispatch(action, payload)
      }
    
    app({
      // ...
      dispatch: middleware
    })
    

    but it ends in an endless loop. no matter what my log effect does. even if I just do dispatch(state => state) it gets in the loop.

    opened by rucsi 4
  • Usage with TypeScript

    Usage with TypeScript

    Hi, I'm running into some issues when using hyperapp (^2.0.13) with typescript (^4.2.3).

    I remember trying things about about 6 months ago and had similar experiences but thought maybe the definitions were not really ready yet.

    I'm not sure if there are any guidelines into usage with ts, but I kind of feel the generics aren't always passed down properly. I wrote down some issues below.


    No problems yet.

    import { app, h, text, View } from "hyperapp";
    import { state, State } from "./state";
    
    const Canvas: View<State> = () => {
      return h("div", {}, [text("ok")]);
    };
    
    app<State>({
      init: state,
      view: Canvas,
      node: document.getElementById("app")!,
    });
    

    Introducing .map(toShape) suddenly causes a conflict.

    // Type '(state: State) => VDOM<unknown>' is not assignable to type 'View<State>'.
    // Type 'VDOM<unknown>' is not assignable to type 'VDOM<State>'.
    const Canvas: View<State> = (state) => {
      return h("div", {}, state.shapes.map(toShape));
    };
    
    const toShape = (shape: ShapeType) => {
      return h("h3", {}, [text(shape.type)]);
    };
    
    app<State>({
      init: state,
      view: Canvas,
      node: document.getElementById("app")!,
    });
    

    Removing View<State> and just using (state: State) moves the error up to the app call.

    import { app, h, text, View } from "hyperapp";
    import { ShapeType, state, State } from "./state";
    
    const Canvas = (state: State) => {
      return h("div", {}, state.shapes.map(toShape));
    };
    
    const toShape = (shape: ShapeType) => {
      return h("h3", {}, [text(shape.type)]);
    };
    
    app<State>({
      init: state,
    
      // Type '(state: State) => VDOM<unknown>' is not assignable to type 'View<State>'.
      // Call signature return types 'VDOM<unknown>' and 'VDOM<State>' are incompatible.
      view: Canvas,
    
      node: document.getElementById("app")!,
    });
    

    Passing State to every call to h seems to work, but I really don't want to do that.

    import { app, h, text, View } from "hyperapp";
    import { ShapeType, state, State } from "./state";
    
    const Canvas = (state: State) => {
      return h<State>("div", {}, state.shapes.map(toShape));
    };
    
    const toShape = (shape: ShapeType) => {
      return h<State>("h3", {}, [text(shape.type)]);
    };
    
    app<State>({
      init: state,
      view: Canvas,
      node: document.getElementById("app")!,
    });
    

    The only thing that seems to work ok is wrapping the h call itself and just hardcode S to State but since I just started looking into this I'm not sure if this won't cause other issues later on.

    import { PropList, MaybeVDOM, VDOM, h as ha } from "hyperapp";
    import { State } from "./state";
    
    type H = <T extends string = string>(
      tag: T extends "" ? never : T,
      props: PropList<State>,
      children?: MaybeVDOM<State> | readonly MaybeVDOM<State>[]
    ) => VDOM<State>;
    
    export const h: H = (tag, props, children) => ha(tag, props, children);
    

    Any ideas on how to use hyperapp properly when using typescript?

    question types 
    opened by stewartrule 15
  • Use node.append(child) instead of node.appendChild(child)

    Use node.append(child) instead of node.appendChild(child)

    Hi Jorge,

    similar to PR 1036 I suggest replacing node.appendChild(child) with node.append(child). Difference explained here: https://dev.to/ibn_abubakre/append-vs-appendchild-a4m.

    Benefit: 5 characters/bytes of code less.

    Regards, Sven

    enhancement 
    opened by skanne 7
Releases(2.0.0)
  • 2.0.0(Jul 26, 2019)

  • 1.2.9(Sep 7, 2018)

    Patch version packing few but solid improvements, including more consistent DOM attribute behavior, and improvements to the diffing algorithm! 🎉

    Summary

    • 18bfb9b34a98c02faf4c67041b8d7e91ad32c306 Support both object and string as value for style attribute. #756 @JorgeBucaran
    • aa2ce463e57b03f4617e5db7b0c7ddf167b0345c More consistent behavior between client and server rendering for reserved DOM attributes such as spellcheck, draggable, translate, etc. #629 @frenzzy
    • f16f7fca385cab00224013e8431cca487ce41773 Improve keyed algorithm performance. Results in fewer "insertBefore" calls when a keyed item is removed but other items are in the same order. #663 @SkaterDad
    • 4638e396c2d2416f94c39b2a74c218d1c34149dd Minor improvements to the documentaion. Because grammar matters.
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Mar 18, 2018)

    Thanks

    Thank you, everyone, for your ongoing support and interest in the project. Special thanks go to @frenzzy for contributing several new features and his work on @hyperapp/render. Also, thank you @okwolf for @hyperapp/fx and @zaceno for @hyperapp/transitions! 🎉

    I'm also excited to report that Hyperapp has been the 3rd trendiest UI framework on GitHub at a rate of 52 stars a day since the beginning of this year! Wow! ⭐️

    Summary

    This release packs some juicy new features I can't wait for you to try out. 1.2.0 comes with CSS variables (https://github.com/hyperapp/hyperapp/pull/612) support in inline styles, several bug fixes (notably https://github.com/hyperapp/hyperapp/pull/614 and https://github.com/hyperapp/hyperapp/pull/595), a moderate performance boost via delegation of DOM events (https://github.com/hyperapp/hyperapp/pull/638), extensive documentation & code readability improvements — and a game-changing new feature: Lazy Components.

    Lazy components (a.k.a subviews) refers to Hyperapp's new ability to treat a function as a virtual node. This allows you to create components that are wired to the global state and actions effortlessly.

    For example, this is a regular component: you need to feed it its state and actions as props, which can be painful if the component is deeply nested within the document hierarchy.

    const MyComponent = props => <div>{props.value}</div>
    

    Now, this is a lazy component. Notice it returns a function that receives the application state and actions (just like the top-level view).

    const MyComponent = props => (state, actions) => <div>{state.counter.value}</div>
    

    See the documentation for examples or refer to this issue for more information and background.

    Changelog

    • 3b0b284aa7c3687f64dd9e6a12dd197613e2f46f, c70be46ded8c2413d3f310d9aa07c16c52655c99, 335fa1a3762d87417f81fdd0a959be926ed4dc61, 2b45b6b02a08c664e737b02f30dd77db260abe1e, eb06f765b216935fbecb5b68068bcd4cb6082f11, ef968cbf29bfd9a774a07e2b9ffff6beb93683fc, c1be5bd0bb71dde413517100fdd6279ac69460c6, aed6d2cbfc6a36814d73e05615726dbd2b381a6f, 7617d8b7713f53a7cd8d9c9ffd840f8babdc83a1, a4a2d91c7894ca26707a2adff1c524a1c01bc496 More documentation improvements. (@slacktracer @warwickgrigg @SkaterDad @jorgebucaran)
    • 11d65a580adefae308716590ff78f8766b315cf9 #612 Support CSS variables in inline styles (@frenzzy @jorgebucaran)
    • 6e384153aada710b1c7a2613107a210d322c6272 #644 Use JSX in tests. @jorgebucaran
    • d82ed61dc35d165372469964027ec1cf46e9ce30, 7c1478c7d29c722a52c0c9bcb5a4066fb29d02a3, dcabd4bf4e9158f4487568f0e5c7a41ab4aaf4c0, cad9db7ef7d9c890af14e3daa6f2dc4adb73b6c5, 03971faa3fcf6855fb9fd77271b2894e4f2d2a50 Improve source readability. @jorgebucaran
    • ec5759566e31afcd5fe1fec76675f9e2f348c724 #638 Delegate DOM events to proxy for improved performance! @jorgebucaran
    • 167f7c07e91ba785bc0a9c9340232e0fc9a4f148 #640 Fix types. @dancespiele
    • 6e7f70f4c9f73bcf02a9da57f18284d14fefb55b, 48706f5169a3dbfe379f3de25afdd24b094d4248, d7ad890be52ec4aecdd5941d989dbb6d2b1aeefc, 8c8d40f640309f383d272a4edaa8df4c520048cc, 77b24ec8f990251a206c4bdc1a003a184780b3e3, 10116c50fbe09d52d6a2d68c6451a7a80c68546f. Documentation improvements. @jorgebucaran
    • 51d58ccb3c1c2d9f3884728ce8dd2f7693d43a2c #611 Fix uglifyjs usage in minify script. @titouancreach
    • 057e65dae8c481360084364722cd70914bb6a689, 11b7776f23ca257c18ae35636ecb13fee2dc3693 #606 Introduce lazy components. (@frenzzy @jorgebucaran)
    • f0534128989f0bfef1a43c551afcb2e91605c215 Now we can use <datalist>. Fix #622. @vgalaktionov
    • ea2c24c78b39ef5679f581e9e86d5e0d06f93075 #595 Invoke oncreate instead of onupdate during recycling/hydration. @frenzzy
    • a7cf41933f98e1474a90b66dec7c8adbb2fe93d6 #614 Do not mutate initial state. @frenzzy
    Source code(tar.gz)
    Source code(zip)
  • 1.1.2(Feb 10, 2018)

    Bug Fixes

    0d960dd4941e359c9e60a7303b7a68b511a1763c https://github.com/hyperapp/hyperapp/issues/584 Fix bug caused when removing empty text nodes from a list. (@JorgeBucaran, @mrozbarry)

    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Feb 7, 2018)

    What's new?

    ab5d899239a0595728700a50a4e14189a8942f0e #531 Rewrite and collapse entire documentation into a single README file. (@JorgeBucaran)

    Special thanks to @zaceno!

    Breaking Changes

    4a783a344670e183a99488e8f09e2a54cfab085d #578 Change internal VNode schema. Essentially: namenodeName and propsattributes. 9222f99f3de604397cfe9a3580fb8f30c1331947 #578 Store key in VNode.

    Why? To make Hyperapp's virtual nodes compatible with Preact's virtual nodes. This means Hyperapp & Preact support in —your— library is now easier and in some cases (it always depends) comes for free! See #578 for a fuller background justification.

    Documentation Fixes

    Thank you all! ❤️

    4c95855fe63b4facebc3c9dd4e69e90e08291872 @O4epegb b0ce980c0f3588dfac7c4213d3d440b304c76141 @ChristianHarms 5cba88dbad080f23e7ad1b66b7e3de8e16aea399 @sndstudy b2afac780b6c7a767b21a71c15bdaed938d600ec @CanyonTurtle e713abfdd44925c1e8392c50802e099b7b5a0926 @eschaefer d01bba6d2b1b6934d6a87e1e62f979feda3b1d72 @dance2die

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Dec 29, 2017)

    Introducing Hyperapp 1.0 🎉

    Hyperapp is a JavaScript library for building fast and feature-rich applications in the browser. Out of the box, Hyperapp combines state management with a VDOM engine that supports keyed updates & lifecycle events — all with no dependencies.

    import { app } from "hyperapp"
    import { state, actions, view } from "./app"
    export const main = app(state, actions, view, document.body)
    

    Please refer to the documentation for up-to-date information and everything else you need to get started using Hyperapp. For live examples, check out the official CodePen account.

    This 1.0 milestone means the API has reached stability, and the churn is finally over. It took us almost a year to arrive at the current API and while it will never be perfect, done is better than perfect and I am extremely pleased with the result. Thank you, everyone, for contributing your precious time, feedback, and bug-free code to Hyperapp! 😉❤️

    To learn more see the discussion on /r/javascript and read the blog post!

    So, what’s coming next?

    Some of the cool things I am planning for the first quarter of 2018 are submitting a Hacker News PWA to https://hnpwa.com and adding a new example implementation to gothinkster/RealWorld.   I also want to refine the documentation and work more on the ecosystem and tools: scaffolding, bundling, DevTools integration, etc. If you have ideas for improvements please get involved, hop on Slack or file a bug report. And if you’re working on something cool using Hyperapp, let us know on Twitter @HyperappJS!

    Happy hacking and happy holidays! 👋😉🎁

    Source code(tar.gz)
    Source code(zip)
  • 0.16.0(Nov 7, 2017)

    Thank you, everyone, who contributed to this new release (the third one) before 1.0! Special shoutout to @Mytrill, @Swizz, @vdsabev, @andyrj, @SahAssar, @zaceno, @pockethook, @okwolf, @lukejacksonn, and @SkaterDad!

    Also thank you @Pyrolistical and @rajaraodv for your proposals and/or issue findings. Thank you, everyone. 🎉🎉🎉

    What's new?

    Immutable state

    @JorgeBucaran @Mytrill (https://github.com/hyperapp/hyperapp/issues/425)

    Since the addition of modules, the state was no longer immutable: when an action, or a nested action, or an action in a module was called, its result was merged with the current state (or state slice for nested actions/modules).

    This prevented users from using memoize functions on the view with simple === checks for equality and forced us to use deep equality, which is expensive or difficult to implement.

    The benefit of having cheap memoize functions based on immutable state far outweighs the cost of maintaining an immutable state (both in terms of performance and source code size).

    • Allow debugging tools to keep the state history and implement time traveling.
    • Allow performant memoization of components/views on large apps (deep equality on state can be checked simply with ===)
    • Example — Thanks @Mytrill!

    Now, when an action gets executed, the result is merged to the state slice/module's state this action operates on and create a new instance of the state and re-use the part of the state that hasn't been touched.

    Short circuit vnodes

    @andyrj

    This change adds a check in patch() to return early when oldNode equals newNode. This covers two use cases. The first one is when both nodes are text nodes, and as such, there is no need to change the element's text content. The second one is when both nodes refer to the same object reference, which may occur if you are memoizing components.

    Memoize components to save vnode creation CPU, and as a bonus we'll skip patching the element (updating its children). This is similar to React's shouldComponentUpdate optimizations, only that we get it out of the box, and free, like in a free beer. 🍻

    The reason we can accomplish this easily is only that our components are always pure, and as such memoizing, them is a trivial prop check.

    Read the issue here and check out the screenshots!.

    Return a function in order to access the data argument inside actions

    @JorgeBucaran @Swizz @vdsabev

    Change the signature of actions from (state, actions, data) to (state, actions) => (data).

    This makes it easier to distinguish which part is Hyperapp's pre-wired state and actions and which part is your action implementation (data). In addition, make the API more elegant! 💅

       hyperapp          user
           ↓              ↓
    (state, actions) => (data) => ({ ... })
    

    Reducers

    const actions = {
      setValue: state => value => ({ value })
    }
    
    const actions = {
      incrementValue: state => value => ({ value: state.value + value })
    }
    

    Effects

    const actions = {
      downloadStuff: (state, actions) => url => {
        fetch(url)
          .then(data => data.json())
          .then(actions.setValue)
      }
    }
    

    Discussion

    To explain the rationale behind this, let's remember how we used to define actions before.

    myAction: (state, actions, data) => { ... }
    

    And then how we used to call those actions somewhere else.

    actions.myAction(data)
    

    In other words, the signature of the implementation was different from the action called.

    (data) => { ... }
    

    Our new API ameliorates the situation. It doesn't eliminate any possible confusion that could arise completely, but we believe it helps you better reason about actions and as a bonus, it improves API symmetry.

    (#448)

    Remove thunks

    @JorgeBucaran

    Thunks was a feature that allowed you to unlock a special update function by returning a function inside actions. You could use this function to update the state as you pleased, usually asynchronously. You can still achieve the same by calling one or more actions inside other actions. These kinds of actions are usually referred to as "effects".

    For a little bit of history, thunks were introduced to help enhance Hyperapp when the events API was in place. With events now gone too, thunks became less prominent and were mainly used as a secondary mechanism to update the state. We believe there should be one great way to do things and not many ways.

    Goodbye thunks! 👋

    Use setTimeout and not ~requestAnimationFrame~ for debouncing of actions fired in succession

    @JorgeBucaran

    Using rAF for debouncing causes issues with apps running in the background / inactive tags. Because an interval will keep running even when a tab is blurred, we've switched to setTimeout.

    When setTimeout is called, our render function is placed on a queue and scheduled to run at the next opportunity; not immediately. But more importantly, the currently-executing code will complete before functions on the queue are executed. This allows us to debounce sync actions called in rapid succession.

    You can still use rAF directly in your application when you need to optimize animations, etc.

    Don't lock patching inside view function

    @JorgeBucaran

    While still experimental, this feature allows you to call actions inside the view function while the new node is being computed, but before we patch the DOM.

    This means that when you are done computing the vnode, you may have an invalid state (if you called actions inside the view). This feature allows us to skip patching in this situation, because we know we'll be back immediately.

    Remove init function

    @JorgeBucaran

    We've removed props.init and gone back to using the actions object returned by the app() call to subscribe to global events, etc.

    const actions = app({
      state,
      actions,
      view
    })
    
    // Subscribe to global events, start timers, fetch stuff & more!
    
    actions.theWorldIsYours()
    

    For example (try it online here):

    const { tick } = app({
      state: {
        time: Date.now()
      },
      view: state => <Clock time={state.time} />,
      actions: {
        tick: () => ({
          time: Date.now()
        })
      }
    })
    
    setInterval(tick, 1000)
    

    Pass done/remove function to onremove as the 2nd argument

    @JorgeBucaran @zaceno @okwolf

    The lifecycle/vdom event onremove now receives a done function as the 2nd argument you may call to tell hyperapp you are done with your business and it can remove the element. If you don't call the function, the element will not be removed.

    function MessageWithFadeout({ title }) {
      return (
        <div onremove={(element, done) => fadeout(element).then(done)}>
          <h1>{title}</h1>
        </div>
      )
    }
    

    Fix sourcemaps (add missing --in-source-map cli flag)

    1e0cca4d4f80e0822aea502ce2f2178e8ecbb091 @zaceno

    Make Hyperapp easier to use as an ES module

    @SahAssar @JorgeBucaran

    Using Hyperapp as an ES module was already possible, but now it's easier because the entire source code, the whole 300 lines of it, resides in a single file. This means you can import hyperapp/hyperapp/src/index.js from a service like rawgit that serves directly from GitHub with the right Content-Type headers.

    <html>
    <head>
      <script type="module">
        import { h, app } from "https://rawgit.com/hyperapp/hyperapp/master/src/index.js"
        app({
          view: state => h("h1", {}, "Hello World!")
        })
      </script>
    </head>
    </html>
    

    Remove duplicated code

    @pockethook

    Doc updates

    @okwolf

    Refactor codebase for improved readability

    @JorgeBucaran

    Source code(tar.gz)
    Source code(zip)
  • 0.15.0(Oct 10, 2017)

    Thank you everyone who contributed to this second big release before 1.0! Shoutout to @Mytrill, @Swizz, @okwolf, @pspeter3, @lukejacksonn, @zaceno, @johanalkstal, @selfup, @vdsabev and everyone else I keep forgetting to mention! 🔥🎉🙇

    What's new?

    Succulent breaking changes and improvements, bug fixes and believe it or not: a smaller bundle size (1397B). Let me get you up to speed right away!

    This release introduces the init(state, actions) function, modules: { a, b, c } for your sandboxed encapsulation dreams, moves the root property to the second argument of the app(props, →container←) call and parts ways with our clumsy, didn't-get-much-fresh-air HOA built-in support in favor of good old DIY HOA madness.

    Init

    We don't have an elegant way to call actions, subscribe to global events or kickstart ourselves when our app starts. We may call actions after we return from app() (and there's nothing wrong with that), but self-contained libraries like the router or a mouse / keyboard interop interface, etc., are better exposed as modules and without an init function, it would impose too much boilerplate and manual setup on users.

    The new init function works like our good ol' events.load. Use it to subscribe to global events, start timers, fetch resources, etc.

    See https://github.com/hyperapp/hyperapp/issues/406 for details.

    app({
      init(state, actions) {
        // Subscribe to global events, start timers, fetch resources & more!
      }
    })
    

    Modules

    Modules allow you encapsulate your application behavior into reusable parts, to share or just to organize your code. They are similar to mixins, but without any of their pitfalls. This is possible because modules are scoped to a state / action slice and there is no way to use a module without supplying the slice key.

    const foo = {
      state: { value: 1 }
    }
    
    app({
      init(state) {
        console.log(state) // => { foo: { value: 1 } }
      },
      modules: { foo }
    })
    

    This means authors need not worry about namespaces and users can't mistakenly introduce implicit dependencies as it was commonplace when mixins roamed wild all over.

    Modules make it easy to share and modularize your app, but without losing transparency or any of the benefits of single state tree architecture.

    As you would expect, modules are allowed to have modules too.

    const bar  = {
      state: { value: 1 }
    }
    
    const foo = {
      modules: { bar }
    }
    
    app({
      init(state) {
        console.log(state) // => { foo: { bar: { value: 1 } } }
      },
      modules: { foo }
    })
    

    Inside your module's actions, you can only call actions your actions or those exposed in modules under you. This is similar to how a parent component can pass props down to a child component or how a top level action can access the entire state.

    See https://github.com/hyperapp/hyperapp/issues/406 for details.

    Higher-Order Apps

    Built-in support for HOA was removed in favor of a DIY approach.

    Before

    app(A)(B)(C)({ ... })
    

    Now

    C(B(A(app)))({ ... })
    

    This not only gives you more flexibility, but it opens the door to a more diverse ecosystem. It also helps keep core simpler and helps us focus on making Hyperapp better and not worry of HOAs as a "core feature".

    Container

    To render your app to a different element thandocument.body, pass the element to the app(props, container) function in the second argument.

    app(props, container)
    

    If you were using props.root, you will need to update your code. See https://github.com/hyperapp/hyperapp/issues/410 for details.

    Before

    app({ 
      view, 
      state, 
      actions, 
      root: document.getElementById("app") 
    }) 
    

    Now

    app(
      { 
        view, 
        state, 
        actions 
      }, 
      document.getElementById("app")
    )
    

    Other

    • Doc improvements, and bug fixes: https://github.com/hyperapp/hyperapp/issues/407, https://github.com/hyperapp/hyperapp/issues/404. Thanks @Mytrill and @Kenota.
    Source code(tar.gz)
    Source code(zip)
  • 0.14.0(Oct 6, 2017)

    Thank you everyone who contributed to this huge release! Shoutout to @okwolf, @andyrj, @rajaraodv, @Mytrill, @Swizz, @lukejacksonn, @zaceno and everyone else I forgot to mention! 🎉🙇

    Hopefully, this will be our last release before the better-late-than-never, long-awaited, infamous & scandalous 1.0.


    What's new?

    A lot has changed and here's everything you need to know to get up to speed with the latest and greatest Hyperapp.

    Summary

    • Remove events, emit and mixins.
    • Introduce state slices.
    • Easier immutable and deeply nested state updates.
    • Out-of-the-box hydration.
    • Less lifecycle boilerplate.

    State Slices

    Hyperapp uses a single state tree — that is, this single object contains all your application level state and serves as the single source of truth. This also means, if you are coming from Redux/Flux, that you have only one store for each app. A single state tree makes it straightforward to locate a specific piece of state, and allows for incredibly easy debugging.

    A single state tree is not free from struggle. It can be daunting to update a part of the state deeply nested in the state tree immutably and without resorting to functional lenses / setters or advanced martial arts.

    State slices attempt to address this issue by giving you via actions, a slice of the state tree that corresponds to the namespace where both state and action are declared.

    actions: {
      hello(state) {
      // The state is the global `state`.
      },
      foo: {
        bar: { 
          howdy(state) {
          // The state is: `state[foo][bar]`
          }
        }
      }
    }
    

    State slices allow you to update deeply nested state easily and immutably.

    For example, before when you had something like this:

    state: {
      foo: {
        bar: {
          value: 0,
          anotherValue: 1
        }
      }
    }
    

    ...and wanted to update value, you had to update an entire record (including siblings), since there is no way to single out value from a nested state.

    In other words, you had to write something like the following in order to update the tree immutably.

    actions: {
      updateValue(state) {
        return {
          foo: {
            bar: {
              value: state.foo.bar.value + 1,
              anotherValue: state.foo.bar.anotherValue
            }
          }
        }
      }
    }
    

    With state slices, it's possible to update value more simply. In order to do this, your state must look like this.

    state: {
      foo: {
        bar: {
          value: 0,
          anotherValue: 1
        }
      }
    }
    

    And have a corresponding action inside a namespace that matches the state you want to update.

    actions: {
      foo: {
        bar: {
          updateValue(state) {
            // State is `state[foo][bar]`
            return { value: state.value + 1 }
          }
        }
      }
    }
    

    Here is another example with a component.

    /* counter.js */
    import { h } from "hyperapp"
    
    export const counter = {
      state: {
        value: 0
      },
      actions: {
        up(state, actions) {
          return { value: state.value + 1 }
        }
      }
    }
    
    export function Counter(props) {
      return (
        <main>
          <h1>{props.value}</h1>
          <button onclick={props.up}>1UP</button>
        </main>
      )
    }
    
    /* index.js */
    import { counter, Counter } from "./counter"
    
    app({
      state: {
        counter: counter.state
      },
      actions: {
        counter: counter.actions
      },
      view: (state, actions) => (
        <Counter value={state.counter.value} up={actions.counter.up} />
      )
    })
    

    The counter is defined completely oblivious of the rest of your app. It exports an object with the state and actions that describe how it can be operated on and a component, Counter that describes how it should look like.

    On the app side, your job is just to wire things up and kick it off. It's alive!

    Events

    This release bids farewell to events. So, what's life going to look like without them? The app() now returns your actions, wired to the state update mechanism, ready to go.

    const actions = app({ 
      // Your app here!
    })
    

    Register global DOM event listeners using addEventListener, download / fetch stuff from a remote end point, create a socket connection and essentially do the things you would normally use events.load for right here.

    actions.doSomethingFunky()
    

    Can you show me a real example? Yes, try it online here.

    const { move } = app({
      state: { x: 0, y: 0 },
      view: state => state.x + ", " + state.y,
      actions: {
        move: (state, actions, { x, y }) => ({ x, y })
      }
    })
    
    addEventListener("mousemove", e =>
      move({ 
        x: e.clientX, 
        y: e.clientY  
      })
    )
    

    What if you prefer keeping all your logic inside your app? That's possible too, just use actions.

    app({
      view(state, actions) { /* ... */ },
      state: {
        repos: [],
        isFetching: false,
        org: "hyperapp"
      },
      actions: {
        toggleFetching(state) { /* ... */ },
        populate(state, actions, repos) { /* ... */ },
    
        load(state, actions) {
          actions.toggleFetching() 
          fetch(`https://api.github.com/orgs/${state.org}/repos?per_page=100`)
            .then(repos => repos.json())
            .then(repos => actions.populate(repos) && actions.toggleFetching())
        }
      }
    }).load({...})
    

    In the old days, your app had the ability to bootstrap itself up. Now, your app is just a model describing what happens when something else happens exposing a list of "instructions" (we call 'em actions) to the world.

    Fair enough! But what about the other events we used to have? Where did events.action, events.resolve, events.update, events.render, etc. go?

    See Higher Order Apps for the answer.

    Higher Order Apps

    A higher order app (HOA) is an escape hatch for times when app() doesn't cut it, but mostly a pattern for tool authors to enable some of the things that were previously possible using the now-gone events.

    A HOA is not a new concept and it was very much possible to create them before this release, but it's now simpler. For starters, a HOA is a function that receives the app function and returns a new app function.

    It looks like this.

    function doNothing(app) {
      return props => app(props)
    }
    

    And it's used like this.

    app(doNothing)({
      // Your app here!
    })
    

    Calling app() with doNothing returns a new app() function that can be used in the same way as usual, as well as to create a new HOA.

    app(doNothing)(doThis)(doThat)({
      // Your app here!
    })
    

    In practice, if you are authoring a HOA you'll use something like this.

    function doNothing(app) {
      return props => {
        return app(enhance(props))
    
        function enhance(props) {
          // Enhance your props here.
        }
      }
    }
    

    The props argument refer to the same properties that are passed to the app, the usual suspects: state, actions, view and root.

    Hydration

    Hydration is a perceived performance and search engine optimization technique where you can turn statically rendered DOM nodes into an interactive application.

    In the old days, to enable hydration you used events.load to return a VNnode that corresponded to a server-side-rendered DOM tree. Now, you just sit down and do nothing. Hydration is now built-in & free. Hyperapp now works transparently with SSR and pre-rendered HTML, enabling SEO optimization and improving your sites time-to-interactive. The server-side part of the equation still consists of serving a fully pre-rendered page together with your application.

    How does it work? We check if there are any children elements in the supplied root (or look in document.body if none is given) and assume you rendered them on the server.

    If your root is already populated with other elements we don't know about, you will have to provide a different root otherwise Hyperapp will obliterate them. 🔥🎉

    Lifecycle

    The onremove lifecycle/VDOM event can return a function that takes a remove function, so you don't have to remove the element inside onremove by yourself anymore. See #357 for the origin story.

    function AnimatedButton() {
      return (
        <div
          onremove={element => remove => fadeout(element).then(remove)}
        />
      )
    }
    

    Mixins

    The tl;dr is that mixins have been removed from this release. They are gone & done.

    Mixins had their fair share of supporters and were not always considered harmful, but they were often abused and used to introduce implicit dependencies.

    Say you had two mixins, Cheese and Burger. You wire them to your app and end up with new state and actions. So far so good. But because actions received the global state (and global actions), it was easy to abuse the system.

    Burger's actions could call any actions defined in a Cheese. In this way, Burger depends on Cheese. This kind of dependency is known as an implicit dependency. If you take out the Cheese, Burger breaks. Not to mention, how hard it is to test and debug Burger.

    But this release also introduces State Slices, which would effectively prevent mixin from communicating with each other and begs the question: what harm can they cause now? Have a look at the following code.

    const Burger = {
      state: {
        burger: {
          isVegan: true
        }
      },
      actions: {
        burger: {
          toggleVegan(state, actions) {
            return { isVegan: !state.isVegan }
          }
        }
      }
    }
    
    app({
      mixins: [Burger]
    })
    

    The problem with this mixin is that the author would be forced to define the mixin's namespace and the state ends up looking more complex than it should, defeating the purpose of state slices. This approach is also prone to name collisions. It also makes it impossible for users to rename the mixins's namespace or have multiple burgers.

    So how does life look like after mixins?

    // burger.js
    export const burger = {
      state: {
        isVegan: 0
      },
      actions: {
        toggleVegan(state, actions) {
          return { isVegan: !state.isVegan }
        }
      }
    }
    
    // index.js
    import { burger } from "./burger"
    
    app({
      state: {
        burger: burger.state
      },
      actions: {
        burger: burger.actions
      }
    })
    

    But this is more verbose. True. But it's also transparent and clear where and how we are wiring Burger's state and actions to our app's state and actions. There is no internal magic to merge your state with Burger's and anyone looking at the code can guess what's happening without having to look at Burger's source code or documentation.

    Source code(tar.gz)
    Source code(zip)
  • 0.12.1(Sep 5, 2017)

    Thank you, everyone, as usual! Shoutout to @okwolf, @Swizz, @zaceno, @lukejacksonn, @SkaterDad, and @andyrj!

    What's new?

    This patch introduces a ton of documentation fixes and some improvements, more examples, and a few delicious core changes! 🍰

    Set element.nodeValue to replace text nodes. 🎉

    When both oldNode and node are text nodes:

    set element.nodeValue = node
    

    ...instead of creating a new text node and removing the old one.

    Doing otherwise causes extra GC in situations like described in DBMon (#342).

    Thanks, @andyrj. 💪

    Allow update to take a reducer. 🎉

    Inside a thunk, update usually takes a partial state and merges it with the previous state producing a new state.

    This commit extends update to also take a function that we will immediately call with the latest state and like an action/reducer, allows you to update the state by returning a partial state.

    You'd want to use this feature when you need to update the state inside an async process and you are not sure whether the state that was passed to the action that started the async process has become out-of-date or not.

    A reducer is a function that receives the state and returns a partial state (or a reducer :mindblow:).

    actions: {
      someAyncAction(state) {
        return update => {
          longTaskWithCallback(someData, () =>
            update(state => ({ value: state.value + 1 }))
          )
        }
      }
    }
    

    This allows you to get the current & latest state inside the callback of some async call.

    Allow mixins to be simple objects. 🎉

    Mixins that simply take no options can be written as a plain old JavaScript object now. The mixin, as usual, is an object that extends your application state, actions or events.

    const simpleMixin = {
      events: {
        load() {
          console.log("It works!")
        }
      }
    }
    

    Bonus

    Source code(tar.gz)
    Source code(zip)
  • 0.12.0(Aug 18, 2017)

    Thank you everyone who helped this time! 👋

    What's new?

    tl;dr

    • Introduce a shiny & hot new logo.
    • Rename ~~HyperApp~~ to Hyperapp.
    • Improve docs about keys. @zaceno
    • Reverse mixin initialization order.
      • Initialize mixins first, then initialize the app with your props object.
      • Remove presets (builtin mixin inside mixin support.) Sorry @jamen! 😉
    • Fix doc typos and broken links, etc. @dylan et al
    • Move implementation notes to a gist to relieve its maintenance from the main repo.

    Other

    About the new logo

    Hyperapp Logo

    • Now it is obvious the logo represents both the letters h and a.
    • It looks great on a thumbnail.
      • The symmetric round corners gives it a sharper edge and the thicker lines makes it stand out.
    • It's a joy to glance at.
    • The color also changed to #00C8FF.

    And here are a couple of wallpapers in case you are mad-in-love with Hyperapp like me.

    Click to enlarge!

    wp wp0

    Source code(tar.gz)
    Source code(zip)
  • 0.11.0(Aug 12, 2017)

    Thank you everyone who made this release possible and see you next time! 👋 ❤️ 🙌

    @Swizz - @lukejacksonn - @andyrj - @jamen - @zaceno - @fsodano - @tscholl2 - @MatejMazur - @jcubic - @dodekeract - @madebyherzblut

    What's new?

    tl; dr

    In a nutshell, 0.11.0 has new docs, non-destructive rendering, root as a container, improvements to hydration, thunks, app events, completely rewritten component lifecycle event architecture, POJO state, back to 100% test coverage and several bug fixes.

    Docs

    • The documentation has been carefully revised and extensively rewritten. A new section on hydration has been added.

    Root & Hydration

    • The root is a now a container not a replaceable target.

    • Rendering is non-destructive. This means child nodes in the root are not replaced or removed during rendering.

    • Now we check if the return value of load is the same root node that was passed to the event. If that is the case, we know that load was not used for hydration so we can set both oldNode and element to null.

    • If they are different, then we'll assume oldNode is a valid virtual node and element a DOM node and leave it to the patch function to re-hydrate the node data.

    • The update event is now called only if the new state is truthy and before we schedule a re-render. This means you can return false from the event to cancel re-rendering.

    • Before we also skipped null states, but called the event regardless.

    App Events

    • Simplify the merge function and enforce the use of a POJO (plain old JavaScript object) as the application state. This means state primitive types are no longer valid. ⚠️
    • load: Use it to initialize and "load" your app resources here. This event fires before the very first render and actions you call here will be scheduled for render appropriately.
    • render: Use it to overwrite the view function to "render" your own view.
    • action: Use it to log or save information about actions.
    • resolve: Use it to modify how actions work and what types they are allowed to return.
    • update: Use it to inspect / validate the previous state against the future (new) state. Returning a different state here will overwrite the current state. Return false to invalidate the state (cancel update) and also not render.

    A picture is worth a thousand words so:

    Lifecycle Events

    • Defer calling oncreate and onupdate immediately after patch is done with correct order for nested elements (event bubbling).
    • onupdate receives now the old data / attributes as the second argument to the function. This is a good place to write logic in response to prop changes.
    • Correctly call onremove when an element is going to be replaced for another element.
    • Remove oninsert (use oncreate instead).

    Other

    • Remove rollup.config.js file, until now used only to specify the uglify plugin and use uglify on the command line directly.
    • Rename mixin composition to presets.
    • Refactor thunks. Remove built-in promise support in favor of using thunk composition.
    • Rewrite CoC based on the open code of conduct: http://todogroup.org/opencodeofconduct.
    Source code(tar.gz)
    Source code(zip)
  • 0.10.0(Jul 13, 2017)

    This release packs a lot of new changes, here is the full disclosure. Thank you everyone who made this release possible and see you next time! 👋

    • Hello https://hyperapp.js.org! We now have a working landing page for HyperApp on the web. Thank you @lukejacksonn for doing all the work. 👍 [Source].

    • Use the Contributor Covenant Code of Conduct.

    • Introduce DOM hydration support. 💦

      • The aim of hydration is to avoid trashing out of server side rendered (SSR) DOM nodes and inject missing/dynamic attributes, like event handlers, inline styles, etc., in them. Thanks to @andyrj and @ngryman.
    • Use requestAnimationFrame to batch patches and optimize render pipeline. 🔥

      • Use rAF to throttle renders / batch render calls.
      • Introduce new init event that run before the view has rendered the first time, but after the app internal state has been initialized.
      • The loaded event is still kicking around and triggers (only once) after the view has been rendered the first time.
    • Don't hardcode DOMContentLoaded.

      • This is a breaking change if you were previously including your app bundle in the <head> section of your HTML.
        • To fix the issue above, you now have two options:
          • Use addEventListener("DOMContentLoaded", () => app(options))
          • Use the attribute defer in the script tag, e.g., <script defer src="bundle.js"></script>
        • If you were including your script tag at the bottom of your <body> tag, no changes are necessary.
    • Introduce a new lifecycle event oninsert

      • oninsert is fired after oncreate when the element has been inserted in the DOM. That is after the app() has returned and the element is rendered.
    • Use bundlesize to track bundle size changes.

    • Mixins can include their own mixins now. Thanks @jamen.

    • Allow events to be triggered from outside the app() call. Thanks @zaceno.

    • New TweetBox example.

    • The router has graduated from core and moved outside of core. Please see @hyperapp/router for details.

      • The router is still under maintenance and currently going through a makeover. Stay tuned!
    Source code(tar.gz)
    Source code(zip)
  • 0.9.2(Jun 4, 2017)

    This release includes two bug fixes:

    • Don't call onupdate handler if it is undefined. https://github.com/hyperapp/hyperapp/issues/215
    • Fix input type=text selection reset. The cursor/selection no longer jumps to the end of the text when the value attribute is bound to the state. https://github.com/hyperapp/hyperapp/pull/224
    • Router.go now handles URLs with query strings. https://github.com/hyperapp/hyperapp/pull/217

    And modifies the behavior of onremove. Now, if you use onremove you are responsible to remove the element from the DOM yourself. With this, it's possible now to use onremove to create slide-out transitions/animations. Thanks, @zaceno.

    Source code(tar.gz)
    Source code(zip)
  • 0.9.0(Apr 30, 2017)

    What's new?

    @madebyherzblut.

    • Fix attributes that were always converted to lowercase breaking case-sensitive attributes like viewBox for most browsers.

    @maraisr.

    • Check if data is set before calling onremove.

    @zaceno.

    • Add test for when plain-string vnodes are removed.

    @JorgeBucaran.

    • Rewrite docs, add tutorials
    • Special thanks to @lukejacksonn and @selfup for helping with redaction tips.
    • No more camelCase for events. Breaking. onClickonclick, onCreateoncreate, etc.
    • Normalize actions/events signatures: (state, actions, data, emit). Breaking. https://github.com/hyperapp/hyperapp/issues/190

    Noteworthy

    By @ngryman.

    • Optimize h. https://github.com/hyperapp/hyperapp/pull/187
    • Add bench and trace scripts for h. https://github.com/hyperapp/hyperapp/pull/186
    Source code(tar.gz)
    Source code(zip)
  • 0.8.1(Apr 15, 2017)

    What's new?

    In a nutshell, this version is smaller, but packs more features and a more advanced patching/diffing algorithm. The biggest change in 0.8.0 is the introduction of keys, largely thanks to @zaceno!

    Many thanks to all the rest of the awesome people that helped to get this release out. In no particular order:

    • @pedroborges
    • @lukejacksonn
    • @selfup
    • @ngryman
    • @dodekeract
    • @zaceno
    • @leeoniya

    Thank you! 🙇

    Changes

    model has been renamed to state. https://github.com/hyperapp/hyperapp/issues/173

    subscriptions and hooks have been removed in favor of events. https://github.com/hyperapp/hyperapp/issues/174

    app({
      events: {
        loaded: (state, actions, emit) =>                   
          {/* Same as former subscriptions. */},
    
        action: (state, actions, data, emit) =>   
          {/* Similar to former onAction. data: { name, data }. */},
    
        update: (state, actions, data, emit) =>     
          {/* Similar to former onUpdate. data: changed state. */},
    
        render: (state, actions, data, emit) =>             
          {/* Similar to former onRender. data: view. */},
    
        route:  (state, actions, data, emit) => 
          {/* New in >=0.8.0. data: { match, params }. */}
      }
    })
    
    • Applications without a default root are mounted on document.body. https://github.com/hyperapp/hyperapp/pull/140. Thanks @ngryman.

    • Remove deferring of lifecycle events. https://github.com/hyperapp/hyperapp/issues/171.

    • Set element event handlers as properties (not as attributes) https://github.com/hyperapp/hyperapp/issues/175. Thanks @crixusshen and @leeoniya.

    What's new?

    Keys https://github.com/hyperapp/hyperapp/pull/172, https://github.com/hyperapp/hyperapp/pull/141, https://github.com/hyperapp/hyperapp/issues/117

    Similar to keys in React, now you can add a key prop to your elements.

    You don't always need keys, in fact you may never need them. But if you are inserting/reordering elements in a list, and it's vital that these elements are not destroyed or mutated during the patch process, then keys are very useful.

    I still haven't found a really simple way to explain keys so I apologize in advance if the above description seems obscure at first. I'll do a better job in the docs when touching on the subject.

    Events https://github.com/hyperapp/hyperapp/pull/177, https://github.com/hyperapp/hyperapp/pull/178

    • Introduce "events". The default app/router events are the ones above, but you can create your own events now using the event emitter. The event emitter is a function (emit) and the last argument passed to events (as you can see above) and (now) also to actions. The signature is emit(eventName, eventData). The signature of the event handler is eventName: (state, actions, eventData, emit).

    • Don't confuse actions with events. Actions are functions you call/run, events are function called for you (hyperapp calls them). So, in this way they are also like hooks. You can also create your own events. Notice the former onError hook is gone. This is because it doesn't need to be baked into the framework no more; you can simply emit("error", error) and handle it in events: { error: (state, actions, error, emit) => {} }.

    • Other than plugins and the loaded event (which is basically subscriptions >=0.8.0) you will rarely use custom events.

    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Feb 15, 2017)

    Changes

    • Enter cdnjs https://github.com/cdnjs/cdnjs/pull/10613. 🎉
      • Grab it at https://cdnjs.com/libraries/hyperapp
    • Remove hyperx dependency.
      • Hyperx is great, but it's better when we don't distribute it together with hyperapp.
      • 1/3 smaller bundle size for CDN grabbers.
      • True independence, hyperapp is a dep free module.
      • Now it's possible to use hyperxify with hyperapp without hacks.
    • Use ES6 https://github.com/hyperapp/hyperapp/pull/89.
      • This means simpler configs on your end if you are using webpack/rollup.
      • ES6 allows webpack/rollup to run treeshaking to remove unused/not-imported modules.
      • Introduce jsnext:main and module to play well with modern bundlers; webpack/rollup.
      • Distribute library as an UMD bundle now and make pkg.main → dist/hyperapp.js so that users can still require hyperapp in node.
    • The router now accepts a render(view) function and options, instead of a single option with a render function property embedded in it.
    • Add a release and prepublish npm scripts to help with house chores.
    • Better docs. Now there's a detailed guide for setting up hyperapp with hyperx and jsx for each major module bundler: browserify, webpack and rollup.
    • Run uglify optimizations to generate an even smaller bundle.

    Thanks

    Thank you to all the lovely folks who have been helping with HyperApp since the beginning. Here's a short list of mentions: @rbiggs @tzellman @danigb @selfup @terkelg 👋

    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Feb 12, 2017)

    Changes

    • Support function nodes (tag is a function). Basically child components like <MyComponent props=...>children</MyComponent> when using jsx or h. See example.
    • Distribute a single minified hyperapp.js on CDNs.
    • More consistent docs. Thanks @rbiggs.
    • More consistent editor styles for contributors. Thanks @tzellman.
    • 100% coverage.
    Source code(tar.gz)
    Source code(zip)
  • 0.0.13(Feb 9, 2017)

    No breaking changes, more coverage, better documentation, more consistent API and easier than ever usage. 🎉

    Usage

    CommonJS

    const { app, html } = require("hyperapp")
    

    ES6

    import { app, html } from "hyperapp"
    

    Bundle

    With Browserify.

    browserify -t hyperxify -g uglifyify index.js | uglifyjs > bundle.js
    

    Or Webpack/Rollup.

    CDN

    HyperApp is also distributed as a minified file, hosted on a CDN.

    For JSX.

    <script src="https://unpkg.com/[email protected]/dist/hyperapp.js"></script>
    

    For Hyperx.

    <script src="https://unpkg.com/[email protected]/dist/hyperapp.hx.js"></script>
    

    Changes

    • Tons of new tests by @danigb and @maraisr ❤️ https://github.com/hyperapp/hyperapp/pull/60
    • More crisp and concise documentation
    • More consistent API via request by @rbiggs https://github.com/hyperapp/hyperapp/issues/53
    Source code(tar.gz)
    Source code(zip)
  • 0.0.12(Feb 7, 2017)

    Changes

    HyperApp now supports using Hyperx (tagged template literals) or Facebook's JSX. Depending on which one you want to use, you need to select the appropriate distribution.

    For JSX.

    https://unpkg.com/[email protected]/dist/hyperapp.js
    

    For Hyperx.

    https://unpkg.com/[email protected]/dist/hyperapp.hx.js
    

    Usage

    Browser

    • Hyperx
    const { app, html } = hyperapp
    
    • JSX
    /** @jsx h */
    const { app, h } = hyperapp
    

    ES6

    • Hyperx
    import { app, html } from "hyperapp/hx"
    
    • JSX
    /** @jsx h */
    import { app, h } from "hyperapp"
    

    CommonJS

    • Hyperx
    const { app, h } = require("hyperapp/hx")
    
    • JSX
    /** @jsx h */
    const { app, h } = require("hyperapp")
    
    Source code(tar.gz)
    Source code(zip)
  • 0.0.11(Feb 6, 2017)

    CDN

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.11/dist/hyperapp.min.js"></script>
    
    const { app, html } = hyperapp
    

    Changes

    • Fix reducers overriding each other.
    • Don't use arrow func in .replace callback because we need bound arguments.
    Source code(tar.gz)
    Source code(zip)
  • 0.0.10(Feb 6, 2017)

    CDN

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.10/dist/hyperapp.min.js"></script>
    
    const { app, html } = hyperapp
    

    or

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.10/dist/app.min.js"></script>
    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.10/dist/html.min.js"></script>
    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.10/dist/h.min.js"></script>
    

    Notable Changes

    • ~~Work on HyperApp User Guide started.~~
    • Welcome aboard @maraisr!
    • Add docs for lifecycle events (finally) by @danigb. https://github.com/hyperapp/hyperapp/pull/40
    • Prevent default browser behaviour compliant with specs by @terkelg. https://github.com/hyperapp/hyperapp/pull/36
    • Modernize. https://github.com/hyperapp/hyperapp/pull/37
      • Introduced more ES6 idioms (not a full rewrite).
      • Webpack (smaller bundle ftw) 🚀 by @maraisr.
      • Add first couple of tests by @maraisr.
      • Add coverage by @maraisr
    Source code(tar.gz)
    Source code(zip)
  • 0.0.9(Feb 4, 2017)

    CDN

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.9/dist/app.min.js"></script>
    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.9/dist/html.min.js"></script>
    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.9/dist/h.min.js"></script>
    
    Source code(tar.gz)
    Source code(zip)
  • 0.0.8(Feb 4, 2017)

    CDN

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.8/dist/app.min.js"></script>
    

    If you are using html tags, include h.min.js.

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.8/dist/html.min.js"></script>
    

    If you are using JSX instead, include html.min.js.

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.8/dist/h.min.js"></script>
    

    Changes

    • Fix h. Tree needs to be an array for JSX. Thanks @maraisr
    Source code(tar.gz)
    Source code(zip)
  • 0.0.7(Feb 3, 2017)

    CDN

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.7/dist/app.min.js"></script>
    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.7/dist/html.min.js"></script>
    

    To use the h function directly (e.g. JSX).

    <script src="https://cdn.rawgit.com/hyperapp/hyperapp/0.0.7/dist/h.min.js"></script>
    

    If you are using the h function directly or including it in your bundle and compiling JSX to raw h calls, you don't need to include html.min.js.

    Changes

    • Add h function to dist as it will be necessary when using JSX.

    Notes

    Source code(tar.gz)
    Source code(zip)
  • 0.0.6(Feb 2, 2017)

    • Optimize merge (#3).
    • Fix reducers not being functions in update description (#1).
    • Don't merge arrays, treat them as a primitive type instead.
    Source code(tar.gz)
    Source code(zip)
Owner
Jorge Bucaran
Engineer ⎢ Creator of @hyperapp
Jorge Bucaran
A JavaScript Framework for Building Brilliant Applications

mithril.js What is Mithril? Installation Documentation Getting Help Contributing What is Mithril? A modern client-side JavaScript framework for buildi

null 13.5k Dec 28, 2022
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

Supporting Vue.js Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome ba

vuejs 201.6k Jan 7, 2023
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

vue-next This is the repository for Vue 3.0. Quickstart Via CDN: <script src="https://unpkg.com/vue@next"></script> In-browser playground on Codepen S

vuejs 34.6k Jan 4, 2023
🐰 Rax is a progressive React framework for building universal application. https://rax.js.org

Rax is a progressive React framework for building universal applications. ?? Write Once, Run Anywhere: write one codebase, run with Web, Weex, Node.js

Alibaba 7.8k Dec 31, 2022
Ember.js - A JavaScript framework for creating ambitious web applications

Ember.js is a JavaScript framework that greatly reduces the time, effort and resources needed to build any web application. It is focused on making yo

Ember.js 22.4k Jan 4, 2023
Dojo Framework. A Progressive Framework for Modern Web Apps

@dojo/framework Dojo is a progressive framework for modern web applications built with TypeScript. Visit us at dojo.io for documentation, tutorials, c

Dojo 549 Dec 25, 2022
Tiny (2 KB) turboboosted JavaScript library for creating user interfaces.

Develop web applications with 100% JavaScript and web standards. ?? RE:DOM is a tiny (2 KB) UI library by Juha Lindstedt and contributors, which adds

RE:DOM 3.2k Jan 3, 2023
🙋‍♀️ 3kb library for tiny web apps

3kb library for tiny web apps. Sometimes, all you want to do is to try and do something—No boilerplate, bundlers, or complex build processes. Lucia ai

Aiden Bai 699 Dec 27, 2022
A declarative, efficient, and flexible JavaScript library for building user interfaces.

React · React is a JavaScript library for building user interfaces. Declarative: React makes it painless to create interactive UIs. Design simple view

Facebook 200k Jan 4, 2023
:fire: An extremely fast, React-like JavaScript library for building modern user interfaces

Inferno is an insanely fast, React-like library for building high-performance user interfaces on both the client and server. Description The main obje

Inferno 15.6k Dec 31, 2022
A declarative, HTML-based language that makes building web apps fun

A declarative, HTML-based language that makes building web apps fun ?? Docs ∙ Try Online ∙ Contribute ∙ Get Support Intro Marko is HTML re-imagined as

Marko 12k Jan 3, 2023
A Web Component compiler for building fast, reusable UI components and static site generated Progressive Web Apps

Stencil: A Compiler for Web Components and PWAs npm init stencil Stencil is a simple compiler for generating Web Components and static site generated

Ionic 11.3k Jan 4, 2023
A declarative, efficient, and flexible JavaScript library for building user interfaces.

Solid is a declarative JavaScript library for creating user interfaces. It does not use a Virtual DOM. Instead it opts to compile its templates down t

Ryan Carniato 24.5k Jan 4, 2023
jCore - JavaScript library for building UI components

JavaScript library for building UI components

iOnStage 11 Jan 21, 2022
OpenUI5 lets you build enterprise-ready web applications, responsive to all devices, running on almost any browser of your choice.

OpenUI5. Build Once. Run on any device. What is it? OpenUI5 lets you build enterprise-ready web applications, responsive to all devices, running on al

SAP 2.7k Dec 31, 2022
One framework. Mobile & desktop.

Angular - One framework. Mobile & desktop. Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScr

Angular 85.6k Dec 31, 2022
🌱 React and redux based, lightweight and elm-style framework. (Inspired by elm and choo)

English | 简体中文 dva Lightweight front-end framework based on redux, redux-saga and react-router. (Inspired by elm and choo) Features Easy to learn, eas

null 16.1k Jan 4, 2023
A rugged, minimal framework for composing JavaScript behavior in your markup.

Alpine.js Alpine.js offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost. You get to keep your DOM,

Alpine.js 22.5k Jan 2, 2023
The AMP web component framework.

AMP ⚡ ⚡ ⚡ ⚡ Metrics Tooling AMP is a web component framework for easily creating user-first websites, stories, ads, emails and more. AMP is an open so

AMP 14.9k Jan 4, 2023