on master help sign in
Migrate upgrade docs from elm-platform repo
commit54493055f1ccc603571ee73f2a2e6d2e304e9560 authorEvan Czaplicki <evancz@users.noreply.github.com> dateWed 21 Feb 2018, 17:31 (9 years ago) parentc807154
3 files changed+610
docs/upgrade/0.16.md+174 docs/upgrade/0.17.md+275 docs/upgrade/0.18.md+161
docs/upgrade/0.16.mdnew file+174
@@ -0,0 +1,174 @@
1+# Upgrading to 0.16
2+
3+Upgrading should be pretty easy. Everything is quite mechanical, so I would not be very afraid of this process.
4+
5+
6+## Update elm-package.json
7+
8+First thing you want to do is update your `elm-package.json` file. The fields that need work are `repository`, `elm-version`, and `dependencies`.
9+
10+If you have some dummy information in `repository`, something like `https://github.com/USER/PROJECT.git`, you will need to change it such that the project is all lower case. This should work: `https://github.com/user/project.git`.
11+
12+Here is a working `elm-version`:
13+
14+```json
15+{
16+ "elm-version": "0.16.0 <= v < 0.17.0"
17+}
18+```
19+
20+Here are the latest bounds for a bunch of `dependencies`.
21+
22+```json
23+{
24+ "dependencies": {
25+ "elm-lang/core": "3.0.0 <= v < 4.0.0",
26+ "evancz/elm-effects": "2.0.1 <= v < 3.0.0",
27+ "evancz/elm-html": "4.0.2 <= v < 5.0.0",
28+ "evancz/elm-http": "3.0.0 <= v < 4.0.0",
29+ "evancz/elm-markdown": "2.0.0 <= v < 3.0.0",
30+ "evancz/elm-svg": "2.0.1 <= v < 3.0.0",
31+ "evancz/start-app": "2.0.2 <= v < 3.0.0"
32+ },
33+}
34+```
35+
36+The easiest way to get this all set up is to remove everything from `dependencies` and just install the things you need one at a time with `elm-package install`.
37+
38+
39+## Updating Syntax
40+
41+The major syntax changes are:
42+
43+
44+<table>
45+ <tr>
46+ <th>feature</th>
47+ <th>0.15.1</th>
48+ <th>0.16</th>
49+ </tr>
50+
51+ <tr>
52+ <td>field update</td>
53+ <td><pre lang="elm">{ record | x <- 42 }</pre></td>
54+ <td><pre lang="elm">{ record | x = 42 }</pre></td>
55+ </tr>
56+
57+ <tr>
58+ <td>field addition</td>
59+ <td><pre lang="elm">{ record | x = 42 }</pre></td>
60+ <td>removed</td>
61+ </tr>
62+
63+ <tr>
64+ <td>field deletion</td>
65+ <td><pre lang="elm">{ record - x }</pre></td>
66+ <td>removed</td>
67+ </tr>
68+
69+ <tr>
70+ <td>record constructors that add fields</td>
71+ <td>
72+<pre lang="elm">
73+type alias Named r =
74+ { r | name : String }
75+
76+-- generates a function like this:
77+-- Named : String -> r -> Named r
78+</pre>
79+ </td>
80+ <td>
81+<pre lang="elm">
82+type alias Named r =
83+ { r | name : String }
84+</pre>
85+Generates no function. Field addition is gone. A function
86+will still be generated for "closed" records though.
87+ </td>
88+ </tr>
89+
90+ <tr>
91+ <td>field parameters</td>
92+ <td>
93+<pre lang="elm">
94+type alias Foo =
95+ { prefix : String -> String }
96+
97+foo : Foo
98+foo = { prefix x = "prefix" ++ x }
99+</pre>
100+ </td>
101+ <td>
102+<pre lang="elm">
103+type alias Foo =
104+ { prefix : String -> String }
105+
106+foo : Foo
107+foo = { prefix = \x-> "prefix" ++ x }
108+ </td>
109+ </tr>
110+
111+ <tr>
112+ <td>multi-way if</td>
113+ <td>
114+<pre lang="elm">
115+if | x < 0 -> "left"
116+ | x > 0 -> "right"
117+ | otherwise -> "neither"
118+</pre>
119+ </td>
120+ <td>
121+<pre lang="elm">
122+if x < 0 then
123+ "left"
124+
125+else if x > 0 then
126+ "right"
127+
128+else
129+ "neither"
130+</pre>
131+ </td>
132+ </tr>
133+</table>
134+
135+The most common by far should be the record update change. That was the only syntax that used the `<-` operator, so you can pretty safely do a find-and-replace from `<-` to `=` and be all set.
136+
137+The multi-way if is also pretty easy. You just translate it into the equivalent `if/then/else` construct. As you are doing this, notice the style used. It should look quite a bit like Python or any C-like language really. You start with an `if` and do `else if` until you are done. The body of each branch should be indented and things look way nicer if you have a blank line between each branch. I sometimes put a blank line above and below each branch, especially when the branch is more complex.
138+
139+If you are using field addition and deletion, it is possible to translate your code into:
140+
141+ 1. A union type that models things with a simpler API, like [in this case](https://github.com/elm-lang/elm-compiler/issues/985#issuecomment-121927230).
142+ 2. Nesting records instead of adding things onto them. Rather than adding a field, create an outer record that contains a field for the two things you are trying to put together. This seems to lead to nicer code in the long run.
143+
144+
145+## Incomplete Pattern Matches
146+
147+As of 0.16, incomplete pattern matches are caught at compile time as errors. This is true both of `case` expressions and function arguments.
148+
149+As I updated things, I ran into this only when I had been tricky with `Maybe` and `List` where I knew something about their structure based on some incidental details. The nicest example of this was [some code in package.elm-lang.org](https://gist.github.com/evancz/e590750a5bd1ea04c2d2) where the priority has often been "get it working" over "excellent quality code".
150+
151+The compiler should give you pretty nice hints in all these cases, so I think the best advice is just to expect this sort of thing and treat it as an oppurtunity to clean your code up a bit where you were being tricky.
152+
153+
154+## Updating Library Usages
155+
156+There is not actually a lot that changed in `elm-lang/core` and in `evancz/*` libraries.
157+
158+The most noticable removals will be:
159+
160+ * `Basics.otherwise`
161+ * `Signal.(<~)`
162+ * `Signal.(~)`
163+
164+`otherwise` is gone because it is very useless without the multi-way if syntax.
165+
166+Removing `(<~)` and `(~)` is in the spirit of "infix functions should be avoided" and the overall move towards removing redundant and ugly syntax in this release. You can instead use `Signal.mapN` to fill the void here. If you are combining a ton of signals, you can redefine the equivalent of `(~)` like this:
167+
168+```elm
169+andMap : Signal (a -> b) -> Signal a -> Signal b
170+andMap =
171+ Signal.map2 (<|)
172+```
173+
174+Otherwise it is pretty much all small bug fixes and improvements to documentation.
docs/upgrade/0.17.mdnew file+275
@@ -0,0 +1,275 @@
1+
2+# Upgrading to 0.17
3+
4+Upgrading should be pretty easy. Everything is quite mechanical, so I would not be very afraid of this process.
5+
6+
7+## Update elm-package.json
8+
9+Some core packages have been renamed:
10+
11+ - `evancz/elm-html` is now `elm-lang/html`
12+ - `evancz/elm-svg` is now `elm-lang/svg`
13+ - `evancz/virtual-dom` is now `elm-lang/virtual-dom`
14+ - The functionality of `evancz/start-app` now lives in `elm-lang/html` in `Html.App`
15+ - The functionality of `evancz/elm-effects` now lives in `elm-lang/core` in `Platform.*`
16+ - The functionality of `Graphics.*` now lives in `evancz/elm-graphics`
17+
18+So the first thing you want to do is update your `elm-package.json` file. Here is one that has been properly updated:
19+
20+```json
21+{
22+ "version": "1.0.0",
23+ "summary": "let people do a cool thing in a fun way",
24+ "repository": "https://github.com/user/project.git",
25+ "license": "BSD3",
26+ "source-directories": [
27+ "src"
28+ ],
29+ "exposed-modules": [],
30+ "dependencies": {
31+ "elm-lang/core": "4.0.0 <= v < 5.0.0",
32+ "elm-lang/html": "1.0.0 <= v < 2.0.0",
33+ "evancz/elm-http": "3.0.1 <= v < 4.0.0",
34+ "evancz/elm-markdown": "3.0.0 <= v < 4.0.0"
35+ },
36+ "elm-version": "0.17.0 <= v < 0.18.0"
37+}
38+```
39+
40+The only changes should be in the `dependencies` and `elm-version` fields where you need to update constraints. The easiest way to get this all set up is to update `elm-version` by hand, and then remove everything from `dependencies` so you can install the dependencies you still need one at a time with `elm package install`.
41+
42+
43+## Updating Syntax
44+
45+The major syntax changes are:
46+
47+
48+<table>
49+ <tr>
50+ <th>feature</th>
51+ <th>0.16</th>
52+ <th>0.17</th>
53+ </tr>
54+
55+ <tr>
56+ <td>module declaration</td>
57+ <td><pre lang="elm">module Queue (..) where</pre></td>
58+ <td><pre lang="elm">module Queue exposing (..)</pre></td>
59+ </tr>
60+</table>
61+
62+This is a super easy change, so we will add a link to an auto-upgrade tool here when one exists.
63+
64+
65+## `Action` is now `Msg`
66+
67+The Elm Architecture tutorial uses the term `Action` for the data that gets fed into your `update` function. This is a silly name. So in 0.17 the standard name is *message*.
68+
69+```elm
70+-- 0.16
71+type Action = Increment | Decrement
72+
73+-- 0.17
74+type Msg = Increment | Decrement
75+```
76+
77+The idea is that your app is receiving *messages* from the user, from servers, from the browser, etc. Your app then reacts to these messages in the `update` function.
78+
79+
80+## No More `Signal.Address`
81+
82+The most common thing in your code will probably be that `Signal.Address` no longer exists. Here is a before and after of upgrading some typical `view` code.
83+
84+```elm
85+-- 0.16
86+view : Signal.Address Action -> Model -> Html
87+view address model =
88+ div []
89+ [ button [ onClick address Decrement ] [ text "-" ]
90+ , div [ countStyle ] [ text (toString model) ]
91+ , button [ onClick address Increment ] [ text "+" ]
92+ ]
93+
94+-- 0.17
95+view : Model -> Html Msg
96+view model =
97+ div []
98+ [ button [ onClick Decrement ] [ text "-" ]
99+ , div [ countStyle ] [ text (toString model) ]
100+ , button [ onClick Increment ] [ text "+" ]
101+ ]
102+```
103+
104+This change is pretty simple. Any occurance of `address` just gets deleted. In the types, you see the addresses removed, and `Html` becomes `Html Msg`. You can read `Html Msg` as "an HTML node that can produce messages of type `Msg`". This change makes addresses unnecessary and makes it much clearer what kind of messages can be produced by a particular block of HTML.
105+
106+The `Signal.forwardTo` function is replaced by `Html.App.map`. So you may need to make changes like this:
107+
108+```elm
109+-- 0.16
110+view : Signal.Address Action -> Model -> Html
111+view address model =
112+ div []
113+ [ Counter.view (Signal.forwardTo address Top) model.topCounter
114+ , Counter.view (Signal.forwardTo address Bottom) model.bottomCounter
115+ , button [ onClick address Reset ] [ text "RESET" ]
116+ ]
117+
118+-- 0.17
119+view : Model -> Html Msg
120+view model =
121+ div []
122+ [ map Top (Counter.view model.topCounter)
123+ , map Bottom (Counter.view model.bottomCounter)
124+ , button [ onClick Reset ] [ text "RESET" ]
125+ ]
126+```
127+
128+These changes are nice for a couple really good reasons:
129+
130+ - Addresses were consistently one of the things that new folks found most confusing.
131+ - It allows the `elm-lang/virtual-dom` implementation to be more efficient with `lazy`
132+ - It uses a normal `map` instead of some unfamiliar API.
133+
134+You can see more examples of the new HTML API [here](https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/user_input/index.html).
135+
136+
137+## `Effects` is now `Cmd`
138+
139+If you are working with HTTP or anything, you are probably using `evancz/elm-effects` and have your `update` function returning `Effects` values. That library was a successful experiment, so it has been folded into `elm-lang/core` and given a name that works better in the context of Elm 0.17.
140+
141+The changes are basically a simple rename:
142+
143+```elm
144+-- 0.16
145+update : Action -> Model -> (Model, Effects Action)
146+update action model =
147+ case action of
148+ RequestMore ->
149+ (model, getRandomGif model.topic)
150+
151+ NewGif maybeUrl ->
152+ ( Model model.topic (Maybe.withDefault model.gifUrl maybeUrl)
153+ , Effects.none
154+ )
155+
156+-- 0.17
157+update : Msg -> Model -> (Model, Cmd Msg)
158+update msg model =
159+ case msg of
160+ RequestMore ->
161+ ( model, getRandomGif model.topic )
162+
163+ NewGif maybeUrl ->
164+ ( Model model.topic (Maybe.withDefault model.gifUrl maybeUrl)
165+ , Cmd.none
166+ )
167+```
168+
169+The `Cmd` stuff lives in `elm-lang/core` in `Platform.Cmd`. It is imported by default with `import Platform.Cmd as Cmd exposing (Cmd)` to make it easier to use.
170+
171+Again, very easy changes. The key goal of 0.17 was to manage effects in a nicer way, so in making these facilities more complete, the term `Effects` became very ambiguous. You should read more about this in the updated Elm Architecture Tutorial which has [a section all about effects](https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/effects/index.html).
172+
173+
174+## `StartApp` is now `Html.App`
175+
176+The `evancz/start-app` package was an experiment to help people get productive with Elm more quickly. It meant that newcomers could get really far with Elm without knowing a ton about signals, and it has been very effective. With 0.17, it has been folded in to `elm-lang/html` in the `Html.App` module.
177+
178+Upgrading looks like this:
179+
180+```elm
181+-- 0.16 ---------------------------------------
182+import StartApp
183+import Task
184+
185+app =
186+ StartApp.start
187+ { init = init, update = update, view = view, inputs = [] }
188+
189+main =
190+ app.html
191+
192+port tasks : Signal (Task.Task Never ())
193+port tasks =
194+ app.tasks
195+
196+-- 0.17 ---------------------------------------
197+import Html.App as Html
198+
199+main =
200+ Html.program
201+ { init = init, update = update, view = view, subscriptions = \_ -> Sub.none }
202+```
203+
204+The type of `main` has changed from `Signal Html` to `Program flags`. The main value is a program that knows exactly how it needs to be set up. All that will be handled by Elm, so you no longer need to specially hook tasks up to a port or anything.
205+
206+
207+## Upgrading Ports
208+
209+Talking to JavaScript still uses ports. It is pretty similar, but adapted to fit nicely with commands and subscriptions.
210+
211+Here is the change for *outgoing* ports:
212+
213+```elm
214+-- 0.16
215+port focus : Signal String
216+port focus =
217+ ...
218+
219+-- 0.17
220+port focus : String -> Cmd msg
221+```
222+
223+Instead of hooking up a signal, you have a function that can create commands. So you just call `focus : String -> Cmd msg` from anywhere in your app and the command is processed like all the others.
224+
225+And here is the change for *incoming* ports:
226+
227+```elm
228+type User = { name : String, age : Int }
229+
230+-- 0.16
231+port users : Signal User
232+
233+-- 0.17
234+port users : (User -> msg) -> Sub msg
235+```
236+
237+Instead of getting a signal to route to the right place, we now can create subscriptions to incoming ports. So wherever you need to know about users, you just subscribe to it.
238+
239+You should definitely read more about this [here](https://evancz.gitbooks.io/an-introduction-to-elm/content/interop/javascript.html).
240+
241+
242+## JavaScript Interop
243+
244+The style of initializing Elm programs in JS has also changed slightly.
245+
246+<table>
247+ <tr>
248+ <th>Initialize</th>
249+ <th>0.16</th>
250+ <th>0.17</th>
251+ </tr>
252+
253+ <tr>
254+ <td>Embed</td>
255+ <td><pre lang="javascript">Elm.embed(Elm.Main, someNode);</pre></td>
256+ <td><pre lang="javascript">Elm.Main.embed(someNode);</pre></td>
257+ </tr>
258+
259+ <tr>
260+ <td>Fullscreen</td>
261+ <td><pre lang="javascript">Elm.fullscreen(Elm.Main);</pre></td>
262+ <td><pre lang="javascript">Elm.Main.fullscreen();</pre></td>
263+ </tr>
264+
265+ <tr>
266+ <td>Worker</td>
267+ <td><pre lang="javascript">Elm.worker(Elm.Main);</pre></td>
268+ <td><pre lang="javascript">Elm.Main.worker();</pre></td>
269+ </tr>
270+</table>
271+
272+
273+## Next Steps
274+
275+From here, I would highly recommend looking through [guide.elm-lang.org](http://guide.elm-lang.org/), particularly the sections on [The Elm Architecture](http://guide.elm-lang.org/architecture/index.html). This will help you get a feel for 0.17.
docs/upgrade/0.18.mdnew file+161
@@ -0,0 +1,161 @@
1+# Upgrading to 0.18
2+
3+Like always, not that much has really changed. To make the process as smooth as possible, this document outlines all the things you will want to do to use 0.18.
4+
5+ - [Update `elm-package.json`](#update-elm-packagejson)
6+ - [List Ranges](#list-ranges)
7+ - [No More Primes](#no-more-primes)
8+ - [Backticks and `andThen`](#backticks-and-andthen)
9+ - [Renamed Functions in Core](#renamed-functions-in-core)
10+ - [Package Changes](#package-changes)
11+
12+A lot of this can be done automatically with [`elm-upgrade`](https://github.com/avh4/elm-upgrade#elm-upgrade), so check it out after reading through this document!
13+
14+
15+## Update elm-package.json
16+
17+So the first thing you want to do is update your `elm-package.json` file. The only tricky thing is that the HTTP package moved:
18+
19+ - `evancz/elm-http` => [`elm-lang/http`](http://package.elm-lang.org/packages/elm-lang/http/latest)
20+
21+From there, here is an `elm-package.json` that has been properly updated:
22+
23+```json
24+{
25+ "version": "1.0.0",
26+ "summary": "let people do a cool thing in a fun way",
27+ "repository": "https://github.com/user/project.git",
28+ "license": "BSD3",
29+ "source-directories": [
30+ "src"
31+ ],
32+ "exposed-modules": [],
33+ "dependencies": {
34+ "elm-lang/core": "5.0.0 <= v < 6.0.0",
35+ "elm-lang/html": "2.0.0 <= v < 3.0.0",
36+ "elm-lang/http": "1.0.0 <= v < 2.0.0",
37+ "evancz/elm-markdown": "3.0.1 <= v < 4.0.0"
38+ },
39+ "elm-version": "0.18.0 <= v < 0.19.0"
40+}
41+```
42+
43+The only changes should be in the `dependencies` and `elm-version` fields where you need to update constraints.
44+
45+The easiest way to get this all set up is to use [`elm-upgrade`](https://github.com/avh4/elm-upgrade#elm-upgrade), but you can also:
46+
47+ - Update `elm-version` by hand.
48+ - Remove everything from `dependencies` by hand.
49+ - Install what you need with `elm-package install elm-lang/core` one-by-one.
50+
51+
52+## List Ranges
53+
54+The `[1..5]` syntax has been removed.
55+
56+So replace any occurance of `[1..9]` with `List.range 1 9`.
57+
58+
59+## No More Primes
60+
61+You are not allowed to have primes in variable names, so things like `type'` are renamed to `type_`.
62+
63+
64+## Backticks and `andThen`
65+
66+Elm used to let you take normal functions and use them as infix operators. This is most notable in the case of `andThen` which is pretty much the only function that used this feature. You will want to make the following updates to your code:
67+
68+```elm
69+-- old
70+
71+andThenIn17 : Result String Int
72+andThenIn17 =
73+ String.toInt "1234"
74+ `Result.andThen` \year -> isValidYear year
75+
76+-- andThen : Result x a -> (a -> Result x b) -> Result x b
77+
78+
79+-- new
80+
81+andThenIn18 : Result String Int
82+andThenIn18 =
83+ String.toInt "1234"
84+ |> Result.andThen (\year -> isValidYear year)
85+
86+-- andThen : (a -> Result x b) -> Result x a -> Result x b
87+```
88+
89+Notice that the backtick style is replaced by pipelining. The `onError` function has been flipped in the same way, so if you are working with tasks you may say something like this in 0.18:
90+
91+```elm
92+type Msg = NewText String | DidNotLoad
93+
94+tasksIn18 : Task x Msg
95+tasksIn18 =
96+ Http.toTask (Http.getString "http://example.com/war-and-peace")
97+ |> Task.andThen (\fullText -> Task.succeed (NewText fullText))
98+ |> Task.onError (\error -> Task.succeed DidNotLoad)
99+```
100+
101+This also means that `andThen` and `onError` group together much better than in the infix style.
102+
103+**This change should be happening across the entire Elm ecosystem as package authors upgrade to 0.18.**
104+
105+
106+## Renamed Functions in Core
107+
108+A couple functions have been removed or renamed.
109+
110+ - [`Json.Decode`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Json-Decode)
111+ - `objectN` becomes `mapN` (Note: `object1` becomes `map`)
112+ - `tupleN` becomes `mapN` with `index`
113+ - `(:=)` becomes `field`
114+ - `andThen` args flip
115+
116+ - [`Bitwise`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Bitwise)
117+ - `shiftLeft` becomes `shiftLeftBy` and args flip
118+ - `shiftRight` becomes `shiftRightBy` and args flip
119+ - `shiftRightLogical` becomes `shiftRightZfBy` and args flip
120+
121+ - [`Task`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Task)
122+ - `andThen` args flip
123+ - `onError` args flip
124+ - Removed `perform : (x -> msg) -> (a -> msg) -> Task x a -> Cmd msg`
125+ - Added `perform : (a -> msg) -> Task Never a -> Cmd msg`
126+ - Added `attempt : (Result x a -> msg) -> Task x a -> Cmd msg`
127+ - Removed `toMaybe` and `toResult` in favor of using `onError` directly
128+
129+ - [`Result`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Result)
130+ - Renamed `formatError` to `mapError` to match names in `Task`
131+ - `andThen` args flip
132+
133+ - [`Maybe`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Maybe)
134+ - `andThen` args flip
135+ - Removed `oneOf`
136+
137+ - [`Random`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Random)
138+ - `andThen` args flip
139+
140+ - [`Tuple`](http://package.elm-lang.org/packages/elm-lang/core/5.0.0/Tuple)
141+ - `Basics.fst` becomes `Tuple.first`
142+ - `Basics.snd` becomes `Tuple.second`
143+
144+
145+## Package Changes
146+
147+The following packages have changed a little bit:
148+
149+ - [`elm-lang/html`](http://package.elm-lang.org/packages/elm-lang/html/latest) collapsed `Html.App` into `Html`. So you need to remove any `import Html.App` imports and refer to `Html.program` instead.
150+
151+ - [`elm-lang/http`](http://package.elm-lang.org/packages/elm-lang/http/latest) was redone to be easier and have more features. It now supports tracking progress and rate-limiting HTTP requests. It should be pretty easy to upgrade to the new stuff, but if you have a complex `Task` that chains many requests, you will want to use the `Http.toTask` function to keep that code working the same.
152+
153+ - [`elm-lang/navigation`](http://package.elm-lang.org/packages/elm-lang/navigation/latest) no longer has its own concept of a `Parser`. You just turn a `Navigation.Location` into a message and it is fed into your normal `update` function. This means `Navigation.program` is now much closer to `Html.program` so this should simplify things a bit.
154+
155+ - [`evancz/url-parser`](http://package.elm-lang.org/packages/evancz/url-parser/latest) is pretty much the same, but works better and is friendlier. New things include:
156+ - You can use `<?>` to parse query parameters.
157+ - Some bugs about parsing leading and trailing slashes are fixed.
158+ - The parser backtracks, always finding a valid parse of the URL if one exists.
159+ - You can use `parsePath` to parse a `Navigation.Location` directly.
160+
161+In all cases, the packages have become simpler and easier to use. The actual changes did not seem to be too serious as I upgraded `elm-lang.org` and `package.elm-lang.org` and all the examples I control.