Changes in v6

This is a crash-course on the changes from Halogen 5 to Halogen 6. Please open an issue or PR if you notice missing information or ways this guide could be improved!

Halogen 6 introduces several quality-of-life improvements for using Halogen on a day-to-day basis, without major changes to how you use the library to build your applications. It's an intentionally small release which adds polish to the library and which is the first version to support version 0.14 of the PureScript compiler.

If you are migrating an application from Halogen 5 we recommend reading through the full transition guide. However, you can also hop directly to a relevant section using the table of contents below.

  1. PureScript 0.14
  2. Component Types
  3. Event Handler Types
  4. Query Helper Functions
  5. Subscriptions
  6. Other Changes

PureScript 0.14

Halogen 6 is the first version of Halogen compatible with PureScript 0.14. You'll need PureScript 0.14 to compile the library, and if you're upgrading your application to use PureScript 0.14 then you'll need to be on Halogen 6. We know it can be painful dealing with compiler changes and library changes, so we've kept this release intentionally small.

Component Types

Component types have been simplified by removing the surface parameter.

In Halogen 5 (and prior versions), components and the internal functions which manage them carried a surface parameter which indicated the target for the UI to render. As no one ever wrote an alternate target from HTML, Halogen applications have always fixed this parameter to HTML in component definitions, as in:

import Halogen as H
import Halogen.HTML as HH

myComponent :: forall q i o m. H.Component HH.HTML q i o m

In Halogen 6 the surface parameter has been removed. The only real user-visible change is that components and functions which operate on them no longer carry the surface parameter.

import Halogen as H

myComponent :: forall q i o m. H.Component q i o m

This is a breaking change, but one which is easily fixed: remove this parameter from your components and any related functions and types.

Added in #616.

Event Handler Types

We've also made event handlers a little nicer to work with. The Maybe action return value has been removed from event handlers, which now return action directly.

In Halogen 5, when you wanted to respond to a click event, or a message from a child component, the output was of type Maybe action. This allowed you to selectively emit outputs (you could emit Nothing for some events). In practice, though, few do this.

To remove friction around such a common task, these handlers no longer return in Maybe in Halogen 6. Instead, they return the action directly. Here is how some simple render code would change from Halogen 5 to Halogen 6:

 HH.div_
   [ HH.button
-      [ HE.onClick \_ -> Just Clear ]
+      [ HE.onClick \_ -> Clear ]
       [ HH.text "Clear" ]
-   , HH.slot _id unit component unit (Just <<< Handle)
+   , HH.slot _id unit component unit Handle
   ]

You're no longer able to ignore the output of a child component by providing a handler \_ -> Nothing. Instead, you can use the slot_ function if you don't care about a child component's output. This code from Halogen 5:

HH.slot _id unit component unit (\_ -> Nothing)

becomes this code in Halogen 6:

HH.slot_ _id unit component unit

Note: You can recover the old Halogen 5 behavior by adding a DoNothing constructor to your action type, or by wrapping your action type in Maybe.

Added in #636 and #642.

Query Helper Functions

We've simplified the helper functions which are used with queries so that you can use tell and request directly, rather than use them in conjunction with the query and request functions.

In Halogen 5, to execute a query you would use the query function and combine it with the request function (for request-style queries, which return a result) or the tell function (for tell-style queries, which don't return a result). This was always a bit difficult to explain and easy to trip over when writing queries yourself.

Here's how you would execute a request-style and then a tell-style query in Halogen 5:

handleAction = do
  a <- H.query _a unit (H.request Child.SomeRequestQuery)
  _ <- H.query _a unit (H.tell Child.SomeTellQuery)

In Halogen 6, you no longer use the query function. Instead, you use request and tell directly. You also don't have to throw away the result of tell, as it can already be safely discarded:

handleAction = do
  a <- H.request _a unit Child.SomeRequestQuery
  H.tell _a unit Child.SomeTellQuery

The old tell and request functions still exist in Halogen 6, but they've been renamed to mkTell and mkRequest and are only used when querying the root of your application. For example, this code in Halogen 5:

io <- runUI component unit body

state <- io.query $ H.request SomeRequestQuery
_ <- io.query $ H.tell SomeTellQuery

becomes this code in Halogen 6:

io <- runUI component unit body

state <- io.query $ H.mkRequest SomeRequestQuery
_ <- io.query $ H.mkTell SomeTellQuery

Added in #621.

Subscriptions

Event sources have been replaced with the new halogen-subscriptions library. The previous implementation of event sources was built on top of coroutines. This update simplifies the library internals and connects Halogen with a subscription management library that can be used independently of Halogen itself.

Notable changes include:

  • The entire Halogen.Query.EventSource module has been removed and replaced with Halogen.Query.Event which provides only an eventListener function. The new function is a drop-in replacement for the old eventListenerEventSource, so all you need to do is update your import.
  • affEventSource and effectEventSource functions can be trivially replaced with code using the halogen-subscriptions library directly, so they have been removed. Examples of how to rewrite these functions are below.
  • The other helper functions and types from the Halogen.Query.EventSource module are no longer required.
  • The subscribe function and Subscribe constructor no longer take an EventSource m action to subscribe to. They take an Emitter action instead.
  • The HalogenIO type returned by running your root-level component now contains a messages :: Emitter output instead of a subscribe :: Coroutine.Consumer output m Unit -> m Unit.

If you were previously using effectEventSource, then you would change this Halogen 5 code:

import Halogen as H
import Halogen.Query.EventSource as ES

do
  void $ H.subscribe $ ES.effectEventSource \emitter -> do
    ES.emit emitter MyAction
    pure mempty

with this Halogen 6 code:

import Halogen as H
import Halogen.Subscription as HS

do
  { emitter, listener } <- H.liftEffect HS.create
  void $ H.subscribe emitter
  H.liftEffect $ HS.notify listener MyAction

When running your root component, you'll also need to replace your use of coroutines. For example, this Halogen 5 code:

main :: Effect Unit
main = ...
  io <- runUI component unit body
  io.subscribe $ Coroutine.consumer \msg -> do
     ...

should be replaced with this Halogen 6 code:

main :: Effect Unit
main = ...
  io <- runUI component unit body
  _ <- liftEffect $ HS.subscribe io.messages \msg -> do
     ...

Other changes

Halogen 6 is an intentionally small release because it coincides with the PureScript 0.14 release. There are only a few other changes in the library to report:

  • The id_ function has been renamed to id now that id has been renamed to identity in the PureScript Prelude. id_ continues to work, but has a deprecation notice and will be removed in the next version. See #717.
  • PureScript 0.14 deprecated the SProxy type in favor of the simpler Proxy type. For this reason, all usages of SProxy in Halogen have been replaced with Proxy. You can do the same in your application with a simple find/replace which replaces SProxy with Proxy and the import Data.Symbol (SProxy(..)) with Type.Proxy (Proxy(..)).
  • The AttrName, PropName, and ClassName types from Halogen have been migrated into the web-html library and imported back into Halogen. This allows libraries to share these types rather than re-implement them over and over. These types are re-exported from Halogen, so your code doesn't need to change.