diff --git a/.gitignore b/.gitignore index c321496..a87368d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,14 @@ -/.* -!/.gitignore -!/.travis.yml -/bower_components/ -/node_modules/ -/output/ -/dist/app.js +.* +!.gitignore +!.travis.yml +!.purs-repl + +.spago +bower_components +node_modules +output + +*.lock package-lock.json + +dist/app.js diff --git a/.purs-repl b/.purs-repl new file mode 100644 index 0000000..6802fc7 --- /dev/null +++ b/.purs-repl @@ -0,0 +1 @@ +import Prelude diff --git a/.travis.yml b/.travis.yml index bee6f35..2fc6f0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,7 @@ dist: trusty sudo: required node_js: stable install: - - npm install -g bower - npm install - - bower install script: - npm run build + - npm run test diff --git a/README.md b/README.md index 90daf6f..964340e 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,57 @@ -# purescript-halogen-template +# Halogen Template -This is a template for starting a fresh project using the [purescript-halogen](https://github.com/slamdata/purescript-halogen) library for declarative user interfaces. +This is a template for starting a fresh project with the [Halogen](https://github.com/slamdata/purescript-halogen) library for writing declarative, type-safe user interfaces. -## Prerequisites +You can learn more about Halogen with these resources: -This guide assumes you already have Git and Node.js installed with `npm` somewhere on your path. +- The [Halogen documentation](https://github.com/purescript-halogen/purescript-halogen/tree/master/docs), which includes a quick start guide and a concepts reference. +- The [Learn Halogen](https://github.com/jordanmartinez/learn-halogen) learning repository. +- The [Real World Halogen](https://github.com/thomashoneyman/purescript-halogen-realworld) application and guide. +- The [API documentation](https://pursuit.purescript.org/packages/purescript-halogen) on Pursuit -In the PureScript ecosystem [Bower](http://bower.io/) is currently the most commonly used package manager and we'll be relying on it for this project, so if you don't already have it, you can install it like this: - -``` shell -npm install --global bower -``` +You can chat with other Halogen users on the [PureScript Discourse](https://discourse.purescript.org), or join the [Functional Programming Slack](https://functionalprogramming.slack.com) ([invite link](https://fpchat-invite.herokuapp.com/)) in the `#purescript` and `#purescript-beginners` channels. ## Getting started -First clone the repo and step into it: +**Prerequisites:** This template assumes you already have Git and Node.js installed with `npm` somewhere on your path. -``` shell -git clone https://github.com/slamdata/purescript-halogen-template.git my-halogen-project -cd my-halogen-project +First, clone the repository and step into it: + +```sh +git clone https://github.com/purescript-halogen/purescript-halogen-template.git halogen-project +cd halogen-project ``` -If you don't already have a global installation of the PureScript compiler and [Pulp](https://github.com/bodil/pulp) (or you want a local installation with the appropriate versions) you can run: +Then, install the PureScript compiler, the [Spago](https://github.com/purescript/spago) package manager and build tool, and [Webpack](https://github.com/webpack/webpack) bundler locally: -``` shell +```shell npm install ``` -Finally you'll need to install the PureScript library dependencies for this project with Bower: - -``` shell -bower install -``` +This will automatically trigger Spago to install the PureScript library dependencies for this project. ## Building -The project can now be built with: +You can now build the PureScript source code with: -``` shell +```sh +# An alias for `spago build` npm run build ``` -This will build the PureScript source code and produce a bundled JS file as `dist/app.js`. +You can produce a bundled JS file you can run in the browser with: -This is an alias for the Pulp command: - -``` shell -pulp build --to dist/app.js +```sh +# An alias for `spago bundle-app --to dist/app.js` +npm run bundle ``` -If you open `dist/index.html` you should now have a basic working Halogen app. +This deposits a bundled JS file named `app.js` in the `dist` directory. You can view your running Halogen app by opening the `dist/index.html` file. -You can also use the command: +Alternatively, if you use an editor that supports `purs ide` or if you are running [`pscid`](https://github.com/kRITZCREEK/pscid), then you can get near-instant builds of the app while you work: -``` shell -npm run watch +```sh +npm run bundle:watch ``` -To start a process that will watch the source files and trigger a reload whenever they are modified. Alternatively... - -## Fast watching with `purs ide` - -If you're using an editor that supports `purs ide` or running [`pscid`](https://github.com/kRITZCREEK/pscid) there's an option for getting near-instant builds of the app while you work on it: - -``` shell -npm run watch-fast -``` - -This will start a watch process that uses [Webpack](https://github.com/webpack/webpack) to rebundle the app whenever the _output_ files are changed. Since `purs ide` rebuilds modules on save, this means you can use this much faster bundle-only rebuild script. - :warning: `purs ide` only rebuilds one module at a time, so sometimes the bundle will end up in an inconsistent state, resulting in runtime errors. This occurs when a change is made in one module that breaks other modules that depend on it. The solution is to run a full build when a change like this is made, as the compiler will force you to resolve those errors. diff --git a/bower.json b/bower.json deleted file mode 100644 index d0bf7ef..0000000 --- a/bower.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "private": true, - "name": "purescript-halogen-template", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "output", - "dist" - ], - "dependencies": { - "purescript-halogen": "^4.0.0", - "purescript-prelude": "^4.1.0", - "purescript-console": "^4.1.0", - "purescript-effect": "^2.0.0" - } -} diff --git a/dist/index.html b/dist/index.html index acddbf1..fd93d38 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,15 +1,8 @@ - + - + My Halogen App - diff --git a/package.json b/package.json index db7007a..5e8e019 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,16 @@ { "private": true, "scripts": { - "build": "pulp build --to dist/app.js", - "watch": "pulp -w build --to dist/app.js", - "watch-fast": "webpack --mode=development --entry ./entry.js --output-path ./dist --output-filename app.js --progress --watch" + "test": "spago test", + "build": "spago build", + "bundle": "spago bundle-app --to dist/app.js", + "bundle:watch": "webpack --mode=development --entry ./entry.js --output-path ./dist --output-filename app.js --progress --watch" }, "devDependencies": { - "pulp": "^12.3.0", - "purescript": "^0.12.0", - "purescript-psa": "^0.7.2", - "webpack": "^4.16.2", - "webpack-cli": "^3.1.0" + "purescript": "^0.13.6", + "purescript-psa": "^0.7.3", + "spago": "^0.15.2", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.11" } } diff --git a/packages.dhall b/packages.dhall new file mode 100644 index 0000000..2dc7c50 --- /dev/null +++ b/packages.dhall @@ -0,0 +1,127 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Warning: Don't Move This Top-Level Comment! + +Due to how `dhall format` currently works, this comment's +instructions cannot appear near corresponding sections below +because `dhall format` will delete the comment. However, +it will not delete a top-level comment like this one. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +Replace the overrides' "{=}" (an empty record) with the following idea +The "//" or "⫽" means "merge these two records and + when they have the same value, use the one on the right:" +------------------------------- +let overrides = + { packageName = + upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } + , packageName = + upstream.packageName // { version = "v4.0.0" } + , packageName = + upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } + } +------------------------------- + +Example: +------------------------------- +let overrides = + { halogen = + upstream.halogen // { version = "master" } + , halogen-vdom = + upstream.halogen-vdom // { version = "v4.0.0" } + } +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +Replace the additions' "{=}" (an empty record) with the following idea: +------------------------------- +let additions = + { package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , etc. + } +------------------------------- + +Example: +------------------------------- +let additions = + { benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } + } +------------------------------- +-} + +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.6-20200507/packages.dhall sha256:9c1e8951e721b79de1de551f31ecb5a339e82bbd43300eb5ccfb1bf8cf7bbd62 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/spago.dhall b/spago.dhall new file mode 100644 index 0000000..a8753f7 --- /dev/null +++ b/spago.dhall @@ -0,0 +1,5 @@ +{ name = "halogen-project" +, dependencies = [ "halogen", "psci-support" ] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/src/App/Button.purs b/src/App/Button.purs new file mode 100644 index 0000000..77959ab --- /dev/null +++ b/src/App/Button.purs @@ -0,0 +1,35 @@ +module App.Button where + +import Prelude + +import Data.Maybe (Maybe(..)) +import Halogen as H +import Halogen.HTML as HH +import Halogen.HTML.Events as HE + +type State = { count :: Int } + +data Action = Increment + +component :: forall q i o m. H.Component HH.HTML q i o m +component = + H.mkComponent + { initialState: \_ -> { count: 0 } + , render + , eval: H.mkEval $ H.defaultEval { handleAction = handleAction } + } + +render :: forall cs m. State -> H.ComponentHTML Action cs m +render state = + HH.div_ + [ HH.p_ + [ HH.text $ "You clicked " <> show state.count <> " times" ] + , HH.button + [ HE.onClick \_ -> Just Increment ] + [ HH.text "Click me" ] + ] + +handleAction :: forall cs o m. Action → H.HalogenM State Action cs o m Unit +handleAction = case _ of + Increment -> + H.modify_ \st -> st { count = st.count + 1 } diff --git a/src/Component.purs b/src/Component.purs deleted file mode 100644 index 3a37bd7..0000000 --- a/src/Component.purs +++ /dev/null @@ -1,48 +0,0 @@ -module Component where - -import Prelude - -import Data.Maybe (Maybe(..)) - -import Halogen as H -import Halogen.HTML as HH -import Halogen.HTML.Events as HE - -data Query a = ToggleState a - -type State = { on :: Boolean } - -component :: forall m. H.Component HH.HTML Query Unit Void m -component = - H.component - { initialState: const initialState - , render - , eval - , receiver: const Nothing - } - where - - initialState :: State - initialState = { on: false } - - render :: State -> H.ComponentHTML Query - render state = - HH.div_ - [ HH.h1_ - [ HH.text "Hello world!" ] - , HH.p_ - [ HH.text "Why not toggle this button:" ] - , HH.button - [ HE.onClick (HE.input_ ToggleState) ] - [ HH.text - if not state.on - then "Don't push me" - else "I said don't push me!" - ] - ] - - eval :: Query ~> H.ComponentDSL State Query Void m - eval = case _ of - ToggleState next -> do - _ <- H.modify (\state -> { on: not state.on }) - pure next diff --git a/src/Main.purs b/src/Main.purs index 9e66943..57971c8 100644 --- a/src/Main.purs +++ b/src/Main.purs @@ -1,13 +1,13 @@ module Main where import Prelude + +import App.Button as Button import Effect (Effect) import Halogen.Aff as HA import Halogen.VDom.Driver (runUI) -import Component (component) - main :: Effect Unit main = HA.runHalogenAff do body <- HA.awaitBody - runUI component unit body + runUI Button.component unit body diff --git a/test/Main.purs b/test/Main.purs new file mode 100644 index 0000000..24d86ab --- /dev/null +++ b/test/Main.purs @@ -0,0 +1,10 @@ +module Test.Main where + +import Prelude + +import Effect (Effect) +import Effect.Class.Console (log) + +main :: Effect Unit +main = do + log "You should add some tests."