|
1 | 1 | # Upgrading from legacy Hyperloop |
2 | 2 |
|
3 | | -These instructions are subject to change as the project matures. |
| 3 | +This guide sets out to provide the steps necessary to move an existing project from legacy Hyperloop to Hyperstack. There are a number of changes which need to be considered. |
4 | 4 |
|
5 | | -TBD |
| 5 | +## Summary of changes |
| 6 | + |
| 7 | ++ Creating a new Hyperstack Rails application |
| 8 | ++ New Hyperstack gems |
| 9 | ++ Renamed folders |
| 10 | ++ Hyperstack configuration |
| 11 | ++ Hyperloop classes have been renamed Hyperstack |
| 12 | ++ There is a new concept of a base `HyperComponent` and `HyperStore` base class |
| 13 | ++ State syntax has changed |
| 14 | ++ Param syntax has changed |
| 15 | ++ The Router DSL has changed slightly |
| 16 | + |
| 17 | +## Creating a new Hyperstack Rails application |
| 18 | + |
| 19 | +In Hyperstack we are using Rails templates to create new applications. |
| 20 | + |
| 21 | ++ Follow these instructions: https://github.com/hyperstack-org/hyperstack/tree/edge/install |
| 22 | ++ See the template for an understanding of the installation steps: https://github.com/hyperstack-org/hyperstack/blob/edge/install/rails-webpacker.rb |
| 23 | + |
| 24 | +**If you are not upgrading an existing Hyoperloop application, you do not need to follow the rest of these instructions.** |
| 25 | + |
| 26 | +## Hyperstack gem |
| 27 | + |
| 28 | +Hyperstack (with Rails) requires just one Gem: |
| 29 | + |
| 30 | +```ruby |
| 31 | +# gem 'webpacker' # if you are using webpacker |
| 32 | +gem 'rails-hyperstack' |
| 33 | +``` |
| 34 | + |
| 35 | +Delete all Hyperloop gems from your gemfile and do a `bundle update`. |
| 36 | + |
| 37 | +## Renamed folders |
| 38 | + |
| 39 | ++ `app/hyperloop` has become `app/hyperstack` |
| 40 | ++ The sub-folder structure has not changed (components, models, stores, etc) |
| 41 | + |
| 42 | +## Hyperstack configuration |
| 43 | + |
| 44 | ++ `config/initializers/hyperloop.rb` has been renamed `config/initializers/hyperstack.rb` |
| 45 | + |
| 46 | +The configuration initialiser has changed a little. Please see this page for details: https://github.com/hyperstack-org/hyperstack/blob/edge/docs/installation/config.md |
| 47 | + |
| 48 | +## Hyperloop classes have been renamed Hyperstack |
| 49 | + |
| 50 | +In all cases, `Hyperloop` has been replaced with `Hyperstack`. For example: |
| 51 | + |
| 52 | +In Hyperloop: |
| 53 | + |
| 54 | +```ruby |
| 55 | +Hyperloop::Application.acting_user_id |
| 56 | +``` |
| 57 | +In Hyperstack becomes: |
| 58 | + |
| 59 | +```ruby |
| 60 | +Hyperstack::Application.acting_user_id |
| 61 | +``` |
| 62 | + |
| 63 | +The simplest way to implement this change is a global search and replace in your project. |
| 64 | + |
| 65 | +## There is a new concept of a base HyperComponent and HyperStore base class |
| 66 | + |
| 67 | +In Hyperloop, all Components and Stores inherited from a base `Hyperloop::Component` class. In HyperStack (following the new Rails convention), we do not provide the base class but encourage you to create your own. This is very useful for containing methods that all your Components share. |
| 68 | + |
| 69 | +To implement this change, you need to create your HyperComponent class: |
| 70 | + |
| 71 | +```ruby |
| 72 | +class HyperComponent |
| 73 | + include Hyperstack::Component |
| 74 | + include Hyperstack::State::Observable # if you are using state |
| 75 | + include Hyperstack::Router::Helpers # if you are using the router |
| 76 | + |
| 77 | + def some_shared_method |
| 78 | + # a helper method that all your Component might need |
| 79 | + end |
| 80 | +end |
| 81 | +``` |
| 82 | + |
| 83 | +Then you need to do a search and replace on all your `Hyperloop::Component` classes and replace them with `HyperComponent`. For example: |
| 84 | + |
| 85 | +In Hyperloop: |
| 86 | + |
| 87 | +```ruby |
| 88 | +class MyComp < Hyperloop::Component |
| 89 | + render do |
| 90 | + ... |
| 91 | + end |
| 92 | +end |
| 93 | +``` |
| 94 | + |
| 95 | +In Hyperstack becomes: |
| 96 | + |
| 97 | +```ruby |
| 98 | +class MyComp < HyperComponent |
| 99 | + render do |
| 100 | + ... |
| 101 | + end |
| 102 | +end |
| 103 | +``` |
| 104 | + |
| 105 | +`HyperComponent` is explained here: https://github.com/hyperstack-org/hyperstack/blob/edge/docs/dsl-client/hyper-component.md#hypercomponent |
| 106 | + |
| 107 | + |
| 108 | +**The same is true for `Hyperloop::Store` to `HyperStore`**. |
| 109 | + |
| 110 | +You will need to create a `HyperStore` class and make the same changes as above. |
| 111 | + |
| 112 | +Note that in Hyperstack, any ruby class can be a store by merely including the `include Hyperstack::State::Observable` mixin. |
| 113 | + |
| 114 | +For example: |
| 115 | + |
| 116 | +```ruby |
| 117 | +class StoresAreUs |
| 118 | + include Hyperstack::State::Observable |
| 119 | + |
| 120 | + def store_something thing |
| 121 | + mutate @thing = thing # note the new mutate syntax |
| 122 | + end |
| 123 | +end |
| 124 | +``` |
| 125 | + |
| 126 | +## State syntax has changed |
| 127 | + |
| 128 | +In Hyperloop you mutated state like this: |
| 129 | + |
| 130 | +```ruby |
| 131 | +mutate.something true |
| 132 | +``` |
| 133 | + |
| 134 | +In Hyperstack becomes: |
| 135 | + |
| 136 | +```ruby |
| 137 | +mutate @something = true |
| 138 | +``` |
| 139 | + |
| 140 | +You also use reference in a different way: |
| 141 | + |
| 142 | +In Hyperloop: |
| 143 | + |
| 144 | +```ruby |
| 145 | +H1 { 'Yay' } if state.something |
| 146 | +``` |
| 147 | + |
| 148 | +In Hyperstack becomes: |
| 149 | + |
| 150 | +```ruby |
| 151 | +H1 { 'Yay' } if @something |
| 152 | +``` |
| 153 | + |
| 154 | +There are several advantages to this new approach: |
| 155 | + |
| 156 | ++ It is significantly faster (ask Mitch) |
| 157 | ++ It feels more natural to think about state variables as normal instance variables |
| 158 | ++ You only use the `mutate` method when you want React to re-render based on the change to state. This gives you more control. |
| 159 | ++ You can string mutations together. For example: |
| 160 | + |
| 161 | +```ruby |
| 162 | +mutate @something = true, @amount = 100, @living = :good |
| 163 | +``` |
| 164 | + |
| 165 | +You can read more about state here: https://github.com/hyperstack-org/hyperstack/blob/edge/docs/dsl-client/hyper-component.md#state |
| 166 | + |
| 167 | +## Param syntax has changed |
| 168 | + |
| 169 | +The syntax for using params has changed: |
| 170 | + |
| 171 | +In Hyperloop: |
| 172 | + |
| 173 | +```ruby |
| 174 | +class SayHello < Hyper::Component |
| 175 | + param :first_name |
| 176 | + |
| 177 | + render do |
| 178 | + H1 { "Hello #{params.first_name}" } |
| 179 | + end |
| 180 | +``` |
| 181 | + |
| 182 | +In Hyperstack becomes: |
| 183 | + |
| 184 | +```ruby |
| 185 | +class SayHello < HyperComponent |
| 186 | + param :first_name |
| 187 | + |
| 188 | + render do |
| 189 | + H1 { "Hello #{@FirstName}" } # Note the conversion of snake_case to CamelCase |
| 190 | + end |
| 191 | +``` |
| 192 | + |
| 193 | +This change has been made to underline that params are immutable. (Though this is not true for Models, but they get the same CamelCase treatment). |
| 194 | + |
| 195 | +You can read more about this here: https://github.com/hyperstack-org/hyperstack/blob/edge/docs/dsl-client/hyper-component.md#params |
| 196 | + |
| 197 | +## The Router DSL has changed slightly |
| 198 | + |
| 199 | +Routers are now normal Components with a render method. |
| 200 | + |
| 201 | +A Hyperstack router looks like this: |
| 202 | + |
| 203 | +```ruby |
| 204 | +class MainFrame < HyperComponent |
| 205 | + include Hyperstack::Router # note the inclusion of the Router mixin |
| 206 | + |
| 207 | + render(DIV) do # note the render method |
| 208 | + Switch do |
| 209 | + Route('/', exact: true, mounts: HomeIndex) |
| 210 | + Route('/app', exact: true, mounts: AppIndex) |
| 211 | + end |
| 212 | + end |
| 213 | +end |
| 214 | +``` |
0 commit comments