Skip to content

Commit 5087554

Browse files
Upgrate from Halogen 4 to Halogen 5 (#26)
* update dependencies (link remotedata) * wip migration to halogen 5 * compiling * add bus subscriptions for global state * more explicit subscriptions, better routing initialization * broadcast value changes * fixes * forgot stashed changes * Global state with subscribed components (#27) add bus subscriptions for global state * Convert to Spago (#28) convert to spago * Revert "Global state with subscribed components (#27)" * switch to Slot' from Formless * update to latest spago / package set & update to latest Formless * Update packages.dhall * Update code to use 'Expose input' Formless PR (#29) * Update Formless dependency to Jordan's "exposeInput" branch * Remove unneeded whitespace characters * Migrate Editor page to new Formless * Migrate Login page to new Formless * Migrate Register page to new Formless * Migrate Settings page to new Formless * Convert back to using Thomas' Halogen 5 PR as dependency * Update to use Halogen RC5 and PS 0.13 (#34) * Update code for purs 0.13, update halogen to rc5 * Remove override for remotedata as its in the snapshot now * Gitignore VSCode workspace files * Use hash symbol instead of its code * Merge master branch into halogen-5 and update readme * Update README.md
1 parent d7b5273 commit 5087554

33 files changed

+1502
-1385
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ bower_components
44
node_modules
55

66
# Dot files
7+
.spago
78
.psci
89
.pulp-cache
910
.purs-repl
1011
.package-lock
1112
.psc-ide-port
1213
.cache
1314

15+
# IDE files
16+
*.code-workspace
17+
1418
# Generated
1519
output
1620
dce-output

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
[PureScript](https://github.com/purescript) is a delightful purely-functional language that offers powerful, pragmatic tools to manage complexity and help you design, build, and refactor reliable apps of any size. This repository demonstrates the principles I apply at work every day in more than 2,000 lines of thoroughly commented code and has an accompanying long-form [guide to building real-world Halogen applications](https://thomashoneyman.com/guides/real-world-halogen).
77

8-
> Using Halogen 5? See the [fully-functioning branch of RealWorld for Halogen 5](https://github.com/thomashoneyman/purescript-halogen-realworld/tree/halogen-5)
8+
> Using Halogen 4? Browse the repository at the [tag for Halogen 4](https://github.com/thomashoneyman/purescript-halogen-realworld/tree/v1.0.0). Upgrading from Halogen 4 to Halogen 5? See the [PR which migrated this repository to Halogen 5](https://github.com/thomashoneyman/purescript-halogen-realworld/pull/26).
99
1010
I’m a senior software engineer at [Awake Security](https://github.com/awakesecurity) (and previously at [CitizenNet](https://citizennet.com)). Both companies have large production PureScript applications that have remained reliable, understandable, and maintainable as they scale. I’m convinced PureScript is the best language available today for most single-page applications.
1111

assets/index.html

+22-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,22 @@
1-
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Conduit</title> <link href="//code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css"> <link href="//fonts.googleapis.com/css?family=Titillium+Web:700|Source+Serif+Pro:400,700|Merriweather+Sans:400,700|Source+Sans+Pro:400,300,600,700,300italic,400italic,600italic,700italic" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="//demo.productionready.io/main.css"> </head> <body> <script src="../dist/app.js"></script> </body> </html>
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>Conduit</title>
7+
<link
8+
href="//code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"
9+
rel="stylesheet"
10+
type="text/css"
11+
/>
12+
<link
13+
href="//fonts.googleapis.com/css?family=Titillium+Web:700|Source+Serif+Pro:400,700|Merriweather+Sans:400,700|Source+Sans+Pro:400,300,600,700,300italic,400italic,600italic,700italic"
14+
rel="stylesheet"
15+
type="text/css"
16+
/>
17+
<link rel="stylesheet" href="//demo.productionready.io/main.css" />
18+
</head>
19+
<body>
20+
<script src="../dist/app.js"></script>
21+
</body>
22+
</html>

bower.json

-37
This file was deleted.

package.json

+12-12
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
"version": "1.0.0",
44
"description": "An exemplary real-world application demonstrating PureScript and the Halogen framework",
55
"scripts": {
6-
"postinstall": "bower install",
7-
"build": "pulp --then 'parcel build assets/index.html' build --to dist/app.js",
8-
"build-dev": "pulp build",
9-
"watch-dev": "pulp -w build",
10-
"build-serve": "pulp --then 'parcel build assets/index.html && http-server dist' build --to dist/app.js",
11-
"watch-serve": "pulp -w --then 'parcel build assets/index.html && http-server dist' build --to dist/app.js"
6+
"postinstall": "spago install",
7+
"clean": "rm -rf node_modules output .spago dist/* *.lock",
8+
"build": "spago build",
9+
"watch": "spago build --watch",
10+
"bundle": "spago bundle --main Main --to dist/app.js && parcel build assets/index.html",
11+
"serve": "yarn bundle && http-server dist",
12+
"test": "spago test"
1213
},
1314
"repository": {
1415
"type": "git",
@@ -26,14 +27,13 @@
2627
},
2728
"homepage": "https://github.com/thomashoneyman/purescript-halogen-realworld#readme",
2829
"devDependencies": {
29-
"bower": "^1.8.4",
30-
"parcel-bundler": "^1.11.0",
31-
"pulp": "12.3.0",
32-
"purescript": "0.12.1"
30+
"parcel-bundler": "^1.12.3",
31+
"purescript": "0.12.5",
32+
"spago": "^0.7.7"
3333
},
3434
"dependencies": {
35-
"decimal.js": "^10.0.2",
35+
"decimal.js": "^10.1.1",
3636
"http-server": "^0.11.1",
37-
"marked": "^0.6.1"
37+
"marked": "^0.6.2"
3838
}
3939
}

packages.dhall

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
let mkPackage =
2+
https://raw.githubusercontent.com/purescript/package-sets/psc-0.13.2-20190725/src/mkPackage.dhall sha256:0b197efa1d397ace6eb46b243ff2d73a3da5638d8d0ac8473e8e4a8fc528cf57
3+
4+
let upstream =
5+
https://raw.githubusercontent.com/purescript/package-sets/psc-0.13.2-20190725/src/packages.dhall sha256:60cc03d2c3a99a0e5eeebb16a22aac219fa76fe6a1686e8c2bd7a11872527ea3
6+
7+
8+
let overrides =
9+
{ halogen =
10+
upstream.halogen // { version = "v5.0.0-rc.5" }
11+
, halogen-vdom =
12+
upstream.halogen-vdom // { version = "v6.1.0" }
13+
}
14+
15+
let additions =
16+
{ halogen-formless =
17+
mkPackage
18+
[ "halogen"
19+
, "variant"
20+
, "heterogeneous"
21+
, "generics-rep"
22+
, "profunctor-lenses"
23+
]
24+
"https://github.com/thomashoneyman/purescript-halogen-formless.git"
25+
"halogen-5"
26+
, slug =
27+
mkPackage
28+
[ "prelude"
29+
, "maybe"
30+
, "strings"
31+
, "unicode"
32+
, "generics-rep"
33+
, "argonaut-codecs"
34+
]
35+
"https://github.com/thomashoneyman/purescript-slug.git"
36+
"v1.0.0"
37+
, precise-datetime =
38+
mkPackage
39+
[ "arrays"
40+
, "console"
41+
, "datetime"
42+
, "either"
43+
, "enums"
44+
, "foldable-traversable"
45+
, "formatters"
46+
, "integers"
47+
, "js-date"
48+
, "lists"
49+
, "maybe"
50+
, "newtype"
51+
, "prelude"
52+
, "strings"
53+
, "tuples"
54+
, "unicode"
55+
, "numbers"
56+
, "decimals"
57+
]
58+
"https://github.com/awakesecurity/purescript-precise-datetime.git"
59+
"v5.1.1"
60+
}
61+
62+
in upstream // overrides // additions

spago.dhall

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{ sources =
2+
[ "src/**/*.purs", "test/**/*.purs" ]
3+
, name =
4+
"purescript-halogen-realworld"
5+
, packages =
6+
./packages.dhall
7+
, dependencies =
8+
[ "prelude"
9+
, "console"
10+
, "effect"
11+
, "variant"
12+
, "nonempty"
13+
, "aff"
14+
, "halogen"
15+
, "halogen-formless"
16+
, "remotedata"
17+
, "routing"
18+
, "formatters"
19+
, "routing-duplex"
20+
, "now"
21+
, "affjax"
22+
, "slug"
23+
, "precise-datetime"
24+
, "typelevel-prelude"
25+
, "argonaut-core"
26+
, "argonaut-codecs"
27+
, "aff-bus"
28+
]
29+
}

src/Api/Utils.purs

+13-8
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ import Conduit.Capability.LogMessages (class LogMessages, logError)
1111
import Conduit.Capability.Now (class Now)
1212
import Conduit.Data.Profile (Profile)
1313
import Conduit.Data.Username (Username)
14+
import Conduit.Env (UserEnv)
1415
import Control.Monad.Reader (class MonadAsk, ask, asks)
1516
import Data.Argonaut.Core (Json)
1617
import Data.Argonaut.Decode (class DecodeJson, decodeJson, (.:))
1718
import Data.Either (Either(..), hush)
1819
import Data.Maybe (Maybe(..))
1920
import Data.Tuple (Tuple(..))
21+
import Effect.Aff.Bus as Bus
2022
import Effect.Aff.Class (class MonadAff, liftAff)
2123
import Effect.Class (class MonadEffect, liftEffect)
22-
import Effect.Ref (Ref)
2324
import Effect.Ref as Ref
2425

2526
-- | This function performs a request that does not require authentication by pulling the base URL
@@ -53,23 +54,27 @@ mkAuthRequest opts = do
5354

5455
-- | Logging in and registering share a lot of behavior, namely updating the application environment
5556
-- | and writing the auth token to local storage. This helper function makes it easy to layer those
56-
-- | behaviors on top of the request.
57+
-- | behaviors on top of the request. This also performs the work of broadcasting changes in the
58+
-- | current user to all subscribed components.
5759
authenticate
5860
:: forall m a r
5961
. MonadAff m
60-
=> MonadAsk { baseUrl :: BaseURL, currentUser :: Ref (Maybe Profile) | r } m
62+
=> MonadAsk { baseUrl :: BaseURL, userEnv :: UserEnv | r } m
6163
=> LogMessages m
6264
=> Now m
6365
=> (BaseURL -> a -> m (Either String (Tuple Token Profile)))
6466
-> a
6567
-> m (Maybe Profile)
6668
authenticate req fields = do
67-
{ baseUrl, currentUser } <- ask
69+
{ baseUrl, userEnv } <- ask
6870
req baseUrl fields >>= case _ of
6971
Left err -> logError err *> pure Nothing
7072
Right (Tuple token profile) -> do
71-
liftEffect $ writeToken token
72-
liftEffect $ Ref.write (Just profile) currentUser
73+
liftEffect do
74+
writeToken token
75+
Ref.write (Just profile) userEnv.currentUser
76+
-- any time we write to the current user ref, we should also broadcast the change
77+
liftAff $ Bus.write (Just profile) userEnv.userBus
7378
pure (Just profile)
7479

7580
-- | We can decode records and primitive types automatically, and we've defined custom decoders for
@@ -114,12 +119,12 @@ decode decoder (Just json) = case decoder json of
114119
decodeWithUser
115120
:: forall m a r
116121
. MonadEffect m
117-
=> MonadAsk { currentUser :: Ref (Maybe Profile) | r } m
122+
=> MonadAsk { userEnv :: UserEnv | r } m
118123
=> LogMessages m
119124
=> Now m
120125
=> (Maybe Username -> Json -> Either String a)
121126
-> Maybe Json
122127
-> m (Maybe a)
123128
decodeWithUser decoder json = do
124-
maybeProfile <- (liftEffect <<< Ref.read) =<< asks _.currentUser
129+
maybeProfile <- (liftEffect <<< Ref.read) =<< asks _.userEnv.currentUser
125130
decode (decoder (_.username <$> maybeProfile)) json

0 commit comments

Comments
 (0)