V2.2: Upgrade to 2.1
These notes cover an upgrade from 2.0.0 to 2.1.0.
Update the app
-
Edit
Gemfile
and update the versions of the Hanami gems to"~> 2.1"
. -
Add the following gems to
Gemfile
:
gem "hanami-assets", "~> 2.1"
gem "hanami-view", "~> 2.1"
group :development do
gem "hanami-webconsole", "~> 2.1"
end
group :test do
gem "capybara"
end
- Add the following lines to
.gitignore
:
public/
node_modules/
spec/examples.txt
- Update
Guardfile
to match the following:
group :server do
guard "puma", port: ENV.fetch("HANAMI_PORT", 2300) do
# Edit the following regular expression for your needs.
# See: https://guides.hanamirb.org/app/code-reloading/
watch(%r{^(app|config|lib|slices)([\/][^\/]+)*.(rb|erb|haml|slim)$}i)
end
end
- Create
Procfile.dev
and add the following:
web: bundle exec hanami server
assets: bundle exec hanami assets watch
- Create
bin/dev
, mark it as executable, (chmod a+x
) and add the following:
#!/usr/bin/env sh
if ! gem list foreman -i --silent; then
echo "Installing foreman..."
gem install foreman
fi
exec foreman start -f Procfile.dev "$@"
- If you are using the default
config/puma.rb
, update it to match the following (note the addition and use of thepuma_concurrency
andpuma_cluster_mode
variables):
# frozen_string_literal: true
#
# Environment and port
#
port ENV.fetch("HANAMI_PORT", 2300)
environment ENV.fetch("HANAMI_ENV", "development")
#
# Threads within each Puma/Ruby process (aka worker)
#
# Configure the minimum and maximum number of threads to use to answer requests.
max_threads_count = ENV.fetch("HANAMI_MAX_THREADS", 5)
min_threads_count = ENV.fetch("HANAMI_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
#
# Workers (aka Puma/Ruby processes)
#
puma_concurrency = Integer(ENV.fetch("HANAMI_WEB_CONCURRENCY", 0))
puma_cluster_mode = puma_concurrency > 1
# How many worker (Puma/Ruby) processes to run.
# Typically this is set to the number of available cores.
workers puma_concurrency
#
# Cluster mode (aka multiple workers)
#
if puma_cluster_mode
# Preload the application before starting the workers. Only in cluster mode.
preload_app!
# Code to run immediately before master process forks workers (once on boot).
#
# These hooks can block if necessary to wait for background operations unknown
# to puma to finish before the process terminates. This can be used to close
# any connections to remote servers (database, redis, …) that were opened when
# preloading the code.
before_fork do
Hanami.shutdown
end
end
- Add the following line to
spec/spec_helper.rb
, underneath therequire_relative "support/rspec"
:
require_relative "support/features"
- Create
spec/support/features.rb
:
# frozen_string_literal: true
require "capybara/rspec"
Capybara.app = Hanami.app
- If you wish, update
spec/support/rspec.rb
to include the following configs:
config.example_status_persistence_file_path = "spec/examples.txt"
# Uncomment this to enable warnings. This is recommended, but in some cases
# may be too noisy due to issues in dependencies.
# config.warnings = true
Add views
The steps below apply to each of your app and slices. The code examples use Bookshelf
as the enclosing Ruby module; replace this with the relevant module for your app or slice.
- Add a
view.rb
(toapp/
or your slice):
# auto_register: false
# frozen_string_literal: true
require "hanami/view"
module Bookshelf
class View < Hanami::View
end
end
- Add a
views/helpers.rb
(toapp/
or your slice):
# auto_register: false
# frozen_string_literal: true
module Bookshelf
module Views
module Helpers
# Add your view helpers here
end
end
end
- Add a
templates/layout/app.html.erb
(toapp/
or your slice):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bookshelf</title>
<%= favicon_tag %>
<%= stylesheet_tag "app" %>
</head>
<body>
<%= yield %>
<%= javascript_tag "app" %>
</body>
</html>
- Create
public/404.html
with the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The page you were looking for doesn’t exist (404)</title>
<style>
:root {
--foreground-rgb: 0, 0, 0;
--background-rgb: 255, 255, 255;
--font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-rgb: 0, 0, 0;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body,
html {
max-width: 100vw;
overflow-x: hidden;
font-size: 100%;
}
body {
color: rgb(var(--foreground-rgb));
background: rgb(var(--background-rgb));
font-family: var(--font-sans);
font-style: normal;
}
main {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
padding: 0 4vw;
}
.message {
display: flex;
gap: 1rem;
flex-direction: column;
text-align: center;
}
.message h1 {
font-size: 2rem;
font-weight: 500;
}
p {
line-height: 1.6;
}
@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}
</style>
</head>
<body>
<!-- This file lives in public/404.html -->
<main>
<div class="message">
<h1>404</h1>
<p>The page you were looking for doesn’t exist.</p>
</div>
</main>
</body>
</html>
- Create
public/500.html
with the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>We’re sorry, but something went wrong (500)</title>
<style>
:root {
--foreground-rgb: 0, 0, 0;
--background-rgb: 255, 255, 255;
--font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-rgb: 0, 0, 0;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body,
html {
max-width: 100vw;
overflow-x: hidden;
font-size: 100%;
}
body {
color: rgb(var(--foreground-rgb));
background: rgb(var(--background-rgb));
font-family: var(--font-sans);
font-style: normal;
}
main {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
padding: 0 4vw;
}
.message {
display: flex;
gap: 1rem;
flex-direction: column;
text-align: center;
}
.message h1 {
font-size: 2rem;
font-weight: 500;
}
p {
line-height: 1.6;
}
@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}
</style>
</head>
<body>
<!-- This file lives in public/500.html -->
<main>
<div class="message">
<h1>500</h1>
<p>We’re sorry, but something went wrong.</p>
</div>
</main>
</body>
</html>
Add assets
- Create
package.json
with the following:
{
"name": "rc3fresh",
"private": true,
"type": "module",
"dependencies": {
"hanami-assets": "^2.1.0"
}
}
-
Run
npm install
-
Append the following to
Procfile.dev
:
assets: bundle exec hanami assets watch
- Create
config/assets.js
with the following:
import * as assets from "hanami-assets";
await assets.run();
// To provide additional esbuild (https://esbuild.github.io) options, use the following:
//
// Read more at: https://guides.hanamirb.org/assets/overview/
//
// await assets.run({
// esbuildOptionsFn: (args, esbuildOptions) => {
// // Add to esbuildOptions here. Use `args.watch` as a condition for different options for
// // compile vs watch.
//
// return esbuildOptions;
// }
// });
- Create
app/assets/css/app.css
(orassets/css/app.css
in your slice) with the following:
body {
background-color: #fff;
color: #000;
font-family: sans-serif;
}
- Create
app/assets/js/app.js
(orassets/js/app.js
in your slice) with the following:
import "../css/app.css";
- Create
app/assets/images/favicon.ico
(orassets/images/favicon.ico
in your slice) with the contents of this file.