hanami dev
Working on your app’s front-end now starts with a single new command: hanami dev
.
Running hanami dev
starts the familiar Hanami web server alongside our new front-end assets watcher and compiler.
From there, you’re ready to open http://localhost:2300
and take in our gorgeous new welcome screen, in both light and dark mode.
Welcome (back!) to Hanami. We’ve been building something special for you!
To build your new front-end, you can start with views. Like actions, Hanami views are standalone, callable objects, bringing a new level of clarity and reusability to the view layer.
# app/views/posts/index.rb
module MyApp
module Views
module Posts
class Index < MyApp::View
include Deps["posts_repo"]
expose :posts do |page:|
posts_repo.listing(page:)
end
end
end
end
end
View exposures explicitly prepare the values we pass to templates, and they work seamlessly with Hanami’s Deps mixin, allowing your view to cleanly access other parts of your app as required.
<h1>Posts</h1>
<%= posts.each do |post| %>
<h2><%= post.title %></h2>
<% end %>
Hanami 2.1 delivers a brand new ERB engine, providing you a familiar template environment while also allowing for natural Ruby in view-focused methods, with a simple yield
capturing nested template content, with no special handling required.
Your views have access to a library of familiar helpers:
<%= form_for :post, routes.path(:create_post) do |f| %>
<%= f.label "title" %>
<%= f.text_field "title" %>
<% end %>
You can write your own helpers, too:
module MyApp
module Views
module Helpers
def warning_box
# tag is Hanami's built-in HTML builder helper
tag.div(class: "warning") do
yield # captures nested content in the template; so natural!
end
end
end
end
end
On their own, helpers can become a bit of a mishmash, so Hanami provides view parts that encapsulate your view logic right alongside the value it relates to. They can even render their own partials! This keeps your templates simple and lets you use ordinary OO techniques to refactor and independently test your view code.
module MyApp
module Views
module Parts
# Every post exposed from a view comes with these methods
class Post < MyApp::Views::Part
def title_link
helpers.tag.a(title, href: context.routes.path(:post, id:))
end
def feature_box
render("feature_box", title: title, text: teaser_text)
end
end
end
end
end
<ul>
<% posts.each do |post| %>
<li>
<%= post.title_link %>
<%= post.feature_box %>
</li>
<% end>
</ul>
Rendering views from actions is a breeze. From the get go, actions render their matching view automatically, no extra work required. Once your views need certain input, you can also make that wiring clear:
def handle(request, response)
response.render(view, id: request.params[:id])
end
app/assets/
With your views ready to go, it’s time to explore assets.
Your assets live in app/assets/
. JavaScript files live under js/
, with app
files serving as your entry points:
import "../css/app.css";
console.log("Hello from app.ts");
As you can see, TypeScript works out of the box. Just run npm install typescript
.
Hanami assets are powered by esbuild, giving you lightning quick build times.
Modern front-end affordances are ready for you out of the box, no configuration required, with our standard assets config a picture of simplicity:
import * as assets from "hanami-assets";
await assets.run();
If you need more, you can have more! Assets config can be gracefully extended to provide advanced esbuild options or take advantage of its many plugins. A fully integrated PostCSS, for example, is just a few lines away:
import * as assets from "hanami-assets";
import postcss from "esbuild-postcss";
await assets.run({
esbuildOptionsFn: (args, esbuildOptions) => {
const plugins = [...esbuildOptions.plugins, postcss()];
return {
...esbuildOptions,
plugins,
};
},
});
As first-class Hanami features, views and assets work great inside slices as well as your app/
. Every slice can have its own views/
, templates/
and assets/
directories, for your views, parts, helpers, assets and more.
With Hanami we want to help you draw the right boundaries to support your app’s domain, and views are no different.
With Hanami 2.1, we are continuing to deliver our vision for a fresh take for Ruby apps. We’d love for you dive in and give our views and assets a try!
Check out our updated getting started guide for your first steps in building a full stack Hanami app. You’re only a few commands away:
$ gem install hanami
$ hanami new my_app
$ cd my_app
$ bundle exec hanami dev
$ open http://localhost:2300
With views and assets done, our next step is the persistence layer. You can look forward to hearing more about this later this year.
Thank you from Tim Riley and Luca Guidi.
Thank you also to these wonderful people for contributing to Hanami 2.1!
🌸
]]>With 2.1.0.rc3, we’re happy to release this new approach!
Now when you run hanami assets compile
or hanami assets watch
, we’ll fork and run a separate assets compilation process for each slice in your app containing assets.
These assets will then be compiled into separate directories under public/assets/
, each with their own manifest file: app assets compile into public/assets/
(containing apublic/assets/assets.json
manifest), whereas e.g. an "admin" slice’s assets compile into public/assets/admin/
(containing public/assets/admin/assets.json
).
Each slice will then have access to its own assets only, either via the view helpers or direct access using the registered "assets"
component.
With this, we now deliver the same separations for assets that Hanami offers for every other aspect of slices: complete independence.
Slices may now have their own config/assets.js
file, allowing you to customize asset compilation on a slice-by-slice basis. Of course, if you don’t require this, a single top-level config/assets.js
will still work for all slices.
You also no longer require an "scripts": {"assets": "..."}
entry within your package.json
. Instead, the Hanami CLI will detect config/assets.js
files wherever they exist and invoke them directly.
If you’d like to learn more about this new approach, see this detailed post on our forum.
Once you upgrade from rc2, each slice will only have access to its own assets, and those assets will no longer be namespaced with the slice’s name.
For example, if you have an admin slice, you can change stylesheet_tag("admin/app.css")
just stylesheet_tag("app.css")
.
Assets in the app are also isolated, and are accessible only within the app, and not any other slices.
This is a fairly significant change to assets, and while we’re confident it’s the right move for Hanami, we still need your help to test this with your apps.
Please give this release a try, especially for building views and using your favorite front end tools and packages. Check out our new guides for an introduction, and then let us know how you go.
We want this to be our last release candidate. The next step here is 2.1.0.
Today we’re releasing the following gems:
For specific changes in this release, please see each gem’s own CHANGELOG.
> gem install hanami --pre
> gem install hanami-cli --pre
> hanami new my_app
> cd my_app
> bundle exec hanami dev
Thank you to these fine people for contributing to this release!
Thank you as always for supporting Hanami! We can’t wait to hear from you about this release candidate! 🌸
]]>We discovered a couple of blockers for people generating new apps. These are now fixed. hanami new
will now generate:
app/templates/layouts/app.html.erb
layout.package.json
.In addition, detailed error messages (controlled via config.render_detailed_errors
) will now default only show when the app is the development environment. Previously, they also showed in the test environment. This change ensures that error output will not accidentally trigger false positives in your tests.
We now generate the "type": "module"
directive in package.json
, so front end JavaScript for new Hanami apps will now use ES modules by default. This allows our assets config at config/assets.js
to use the conventional .js
file extension, instead of .mjs
as previously generated.
Our RSpec support has been made friendlier for full stack apps, with Capybara support now included by default. Our standard RSpec setup in spec/support/rspec.rb
now includes code comments detailing the purpose of the various configs, making these easier to use or tailor to your preferences.
The hanami generate action
and hanami generate part
CLI commands now accept a --skip-tests
flag to skip test generation.
Our guides for 2.1 are close to ready, so we’re happy to share a preview for you to check out.
The guides include a full, test-driven walkthrough of building your first app, either as a full stack web app or an API. If you’ve been interested in checking out Hanami 2.1, this will help you get started! We’d love to hear your feedback.
We expect to make our stable 2.1.0 release just next week! We consider 2.1.0 to be frozen, and we need your help to shake out any bugs.
We’d love you to give this release a try, especially for building views and using your favorite front end tools and packages. Let us know how you go.
Today we’re releasing the following gems:
For specific changes in this release, please see each gem’s own CHANGELOG.
> gem install hanami --pre
> gem install hanami-cli --pre
> hanami new my_app
> cd my_app
> bundle exec hanami dev
Thank you to these fine people for contributing to this release!
Thank you as always for supporting Hanami! We can’t wait to hear from you about this release candidate! 🌸
]]>v2.1.0.rc1
, the final stop before our stable 2.1.0 release! This release brings a stylish new welcome experience, next level assets flexibility, and a range of view parts and helpers improvements. It is also our last stop before 2.1.0!
Your Hanami app now ships with a helpful and downright gorgeous first-run welcome screen, in both light and dark modes:
This welcome screen displays whenever you boot the app without any routes.
Along with this, we’re also giving your app elegant new designs for its production mode 404 and 500 error pages. These pages exist inside your apps public/
directory, so you can customize these as required, though we wouldn’t blame you at all for rolling with these ones at least for a while:
We’d like to extend a huge thanks to Aaron Moodie for designing and building these screens.
As of this release, your Hanami app will come with a new config/assets.mjs
file. By default, it is nice and streamlined:
import * as assets from "hanami-assets";
await assets.run();
For many apps and their assets, this out of the box arrangement will be enough, and you shouldn’t need to touch this file.
If you need something a little more, you can now use this file to configure and activate any number of esbuild plugins. For example, to use the postcss plugin:
import * as assets from "hanami-assets";
import postcss from "esbuild-postcss";
await assets.run({
esbuildOptionsFn: (args, esbuildOptions) => {
const plugins = [...esbuildOptions.plugins, postcss()];
return {
...esbuildOptions,
plugins,
};
},
});
With this esbuildOptionsFn
, you can mix your own esbuild options, into ours, offering support for all kinds of assets setups.
The hanami assets
now also work via a single "assets"
script managed within package.json
, affording you even more flexibility if you need a completely exotic setup for your assets, but want to maintain our standard CLI experience for your developers.
hanami dev
via bin/dev
New Hanami apps will now have their own bin/dev
script, which will be run by the hanami dev
CLI command.
By default, this file auto-installs the Foreman gem, so you can run your Hanami dev servers without any other setup.
This file is yours to own and modify, so you can feel free to add any other dev server affordances here.
After beta2, we made some refinments to our assets helper names to minimise naming collisions in your views. The adjusted names are javascript_tag
, stylesheet_tag
, favicon_tag
, image_tag
, video_tag
and audio_tag
.
In addition, helpers inside your view part classes are now contained inside a single helpers
object, ensuring no collisions with the many method names that view parts forward to your app’s domain objects. Accessing a helper inside a view part now looks like this:
module MyApp
module Views
module Parts
class Post
def title_header
helpers.tag.h1(title)
end
end
end
end
end
Finally, we added a new hanami generate part
CLI command, which will generate both a new part and a file for its unit tests (standalone testing of view behavior via parts is one of their best features!).
Thanks very much to Philip Arndt for his field testing and feedback in this area.
Our stable 2.1.0 release is just weeks away! We now consider 2.1.0 to be frozen, and we need your help to shake out any bugs.
Since we introduced our assets support in 2.1.0.beta2 just two weeks ago, early feedback from our users has helped us deliver all the improvements above.
You can help here too! We’d love you to give this a try with your favorite front end tools and packages, and let us know how you go.
Today we’re releasing the following gems:
For specific changes in this beta release, please see each gem’s own CHANGELOG.
> gem install hanami --pre
> hanami new my_app
> cd my_app
> bundle exec hanami dev
Thank you to these fine people for contributing to this release!
Thank you as always for supporting Hanami! We can’t wait to hear from you about this release candidate! 🌸
]]>v2.1.0.beta2
and share a preview of Hanami’s front end assets experience.
hanami dev
It all starts with a new command: hanami dev
.
Running hanami dev
starts the familiar Hanami web server alongside our new front end assets watcher and compiler. This is based on esbuild, and uses a brand new plugin to make it aware of Hanami’s app structure.
Hanami’s assets support now requires Node.js and npm to work.
Your assets live in app/assets/
. JavaScript files live under js/
and serve as your main entry points.
Here’s an example app/assets/js/app.ts
:
import "../css/app.css";
console.log("Hello from app.ts");
As you can see, TypeScript support comes out of the box. Just run npm install typescript --save-dev
.
With your initial assets files in place, you can hop over to your view layout to include them:
app/views/layouts/app.html.erb
<!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 %>
<%= css "app" %>
</head>
<body>
<%= yield %>
<%= js "app" %>
</body>
</html>
And with that, you’re done! Your app is now serving your custom styles and JavaScript behavior.
We provide a complete range of helpers for working with your assets in various ways, including js
, css
(or their fuller equivalents, javascript
and stylesheet
) asset_url
, image
and more.
For users of Hanami slices, we have you covered too: assets can live within each slice, in slices/[slice_name]/assets
directories that can take the same structure as the app-level assets.
Along with the hanami dev
command, you can also use the hanami assets compile
and hanami assets watch
commands directly.
If you’ve been waiting for the full stack Hanami experience, this beta release is a huge step forward.
Since our assets support is brand new, we need your help! We’d love you to give this a try with your favorite front end tools and packages, and let us know how you go.
Today we’re releasing the following gems:
For specific changes in this beta release, please see each gem’s own CHANGELOG.
> gem install foreman
> gem install hanami --pre
> hanami new my_app
> cd my_app
> bundle exec hanami dev
From here, we’ll be working through the small number of “Todo” items remaining on our Hanami v2.1 project board. These are mostly just polish and preparation tasks.
Depending on what we learn from your testing and feedback, this means the full 2.1 release may only be a matter of weeks away! We’ll also be focusing on getting our docs ready to go as well, and we’ll begin to release these as soon as they start to come together.
Thank you to these fine people for contributing to this release!
Thank you as always for supporting Hanami!
We’re very excited to be nearing 2.1, and we can’t wait to hear from you about this beta! 🌸
EDIT: We released v2.1.0.beta2.1
because one Pull Request wasn't merged before the release. Sorry for the problem.
Just like our actions, views are standalone, callable objects. They can work with their arguments and dependencies to prepare exposures to pass to a template for rendering:
# app/views/posts/index.rb
module MyApp
module Views
module Posts
class Index < MyApp::View
include Deps["posts_repo"]
expose :posts do |page:|
posts_repo.listing(page:)
end
end
end
end
end
<h1>Posts</h1>
<%= posts.each do |post| %>
<h2><%= post.title %></h2>
<% end %>
Views are automatically paired with matching actions, so they're ready for you to render:
# app/actions/posts/index.rb
module MyApp
module Actions
module Posts
class Index < MyApp::Action
def handle(request, response)
request.params => {page:}
# view is a ready-to-go instance of MyApp::Views::Posts::Index
response.render(view, page:)
end
end
end
end
end
Hanami views are built on top of Tilt, giving them support for a wide range of template engines. For HTML templates, we provide first-party support for ERB (using a brand new implementation for hanami-view), Haml and Slim.
Hanami will generate matching views when you generate your actions with the hanami generate action
command. You can also generate views directly via hanami generate view
.
Along with views, we’re also introducing a range of built-in helpers, giving you convenient ways to create forms and programatically generate HTML. You can also provide your own helpers inside a Views::Helpers
module within each app and slice namespace.
You can write your own helpers using natural, expressive Ruby, including straightforward yielding of blocks:
# app/views/helpers.rb
module MyApp
module Views
module Helpers
# Feel free to organise your helpers into submodules as appropriate
def warning_box
# `tag` is our built-in HTML builder helper
tag.div(class: "warning") do
# Yielding implicitly captures content from the block in the template
yield
end
end
end
end
end
<h1>Posts</h1>
<%= warning_box do %>
<h2>This section is under construction</h2>
<% end %>
hanami-view is the successor to dry-view, a view system honed over many years of real-world use. Along with the above, it includes even more powerful tools for helping you build a clean and maintainable view layer, such as custom view parts and scopes.
We’re working on updating our getting started guide to include an introduction to views, and we’ll release this as soon as its available.
In the meantime, we’re making this 2.1 beta release so you can give views a try and make sure they’re ready for prime time!
Today we’re releasing the following gems:
For specific changes in this beta release, please see each gem’s own CHANGELOG.
> gem install hanami --pre
> hanami new my_app
> cd my_app
> bundle exec hanami --help
Alongside our work on views, we’ve been preparing Hanami’s front end assets support. This will be based on esbuild, will integrate seamlessly with our views, and even support you splitting your front end assets by slice.
We plan to release this as hanami-assets in an upcoming Hanami v2.0.beta2 release. At this point, you’ll be able to build Hanami apps with a complete front end.
After a short testing period, we’ll release all of these as 2.1.0.
Thank you to these fine people for contributing to this release!
Thank you as always for supporting Hanami!
We’re excited to be expanding the Hanami vision again, and we can’t wait to hear from you about this beta! 🌸
]]>It ships with small enhancements and minor bug fixes.
Pattern Matching on request params is helpful to expand values into local variables:
# frozen_string_literal: true
module MyApp
module Actions
module Graphql
class Show < MyApp::Action
# ...
def handle(req, res)
# ...
req.params => {query:, variables:}
res.body = schema.execute(query, variables:).to_json
end
end
end
end
end
From now on it's possible to reference the HTTP statuses, not only via an Integer
, but also with a Symbol
.
Check our guides, for the entire list of allowed HTTP statuses.
# frozen_string_literal: true
module MyApp
module Actions
module Account
class Show < MyApp::Action
def handle(req, res)
halt :unauthorized unless logged_in?
# ...
end
end
end
end
end
# frozen_string_literal: true
module MyApp
module Actions
module Account
class Update < MyApp::Action
def handle(req, res)
unless req.params.valid?
res.status = :unprocessable_entity
# ...
end
end
end
end
end
end
Hanami::Action::UnknownHttpStatusError
hanami new
on Windowshanami generate action
with deeply nested action nameHanami::Utils::Blank.blank?
to check if the current object is non-nilhanami
2.0.3
hanami-cli
2.0.3
hanami-controller
2.0.2
hanami-utils
2.0.3
How to upgrade from a Hanami app:
$ bundle update hanami-utils hanami-controller hanami-cli hanami
How to try Hanami for the first time:
$ gem install hanami
$ hanami new bookshelf
$ cd bookshelf
$ bundle exec hanami server # visit http://localhost:2300
Thank you also to these wonderful people for contributing to Hanami 2.0.3!
🌸
]]>hanami
2.0.2
hanami-reloader
2.0.2
hanami-rspec
2.0.1
hanami-cli
2.0.2
hanami-controller
2.0.1
hanami-router
2.0.2
hanami-validations
2.0.1
hanami-utils
2.0.2
How to upgrade from a Hanami app:
$ bundle update hanami-utils hanami-validations \
hanami-router hanami-controller \
hanami-cli hanami-rspec \
hanami-reloader hanami
How to try Hanami for the first time:
$ gem install hanami
$ hanami new bookshelf
$ cd bookshelf
$ bundle exec hanami server # visit http://localhost:2300
🌸
]]>It ships with small enhancements and minor bug fixes, after our 2.0.0 release.
Content-Security-Policy
HTTP response header to be returned as a single line.env
files during CLI commands executionhanami server
to respect HTTP port used in .env
or the value given as CLI argument (--port
)Allow
when returning 405
HTTP statusHanami::Middleware::BodyParser::FormParser
to parse multipart file uploadHanami::Utils::Callbacks::Chain
and Hanami::Utils::Callbacks::Callback
comparable via #==
based on their contents, rather than their object identityhanami
2.0.1
hanami-reloader
2.0.1
hanami-cli
2.0.1
hanami-router
2.0.1
hanami-utils
2.0.1
How to upgrade from a Hanami app:
$ bundle update hanami-utils hanami-router hanami-cli hanami-reloader hanami
How to try Hanami for the first time:
$ gem install hanami
$ hanami new bookshelf
$ cd bookshelf
$ bundle exec hanami server # visit http://localhost:2300
Thank you also to these wonderful people for contributing to Hanami 2.0.1!
🌸
]]>Hanami 2.0 is better, faster, stronger.
Since the beginning we’ve called Hanami a modern web framework for Ruby. These beginnings have given us a solid foundation for the journey to 2.0: our focus on maintainability, testability, and your ability to scale your app from a small service to a large monolith.
For 2.0 we’ve gone further. We’ve listened to our community, we’ve simplified and simplified again, we’ve sought new approaches for building apps, and we’ve dared to challenge the status quo.
In turn, we want you to challenge yourself. We want you to try something new, to experiment, to level up as an engineer. To dare to change, just as as we did. Without change, there is no challenge, and without challenge, there is no growth.
The core of Hanami 2.0 is now the app/
directory. So familiar, yet so powerful. Here you can organize your code however you want, while still enjoying sensible defaults for common components. Then, as your app grows, you can take advantage of slices to separate your code into domains.
We’ve stripped everything back to its essence. Your new app is now refreshingly simple:
require "hanami"
module Bookshelf
class App < Hanami::App
end
end
Hanami 2.0 delivers a framework that is at once minimal and powerful:
There’s a lot to dig into for each of these. Check out the Highlights of Hanami 2.0 to see more, including code examples.
We’ve completely rewritten our HTTP routing engine, with benchmarks showing it outperforms nearly all others.
You will see actions served in microseconds:
[bookshelf] [INFO] [2022-11-22 09:48:41 +0100] GET 200 129µs 127.0.0.1 / -
When using Hanami in development, your app will boot and reload instantly thanks to our smart code loading. No matter how big your app grows, your console will load in milliseconds, and your tests will stay snappy. No more waiting!
This release is a triumph of indie development. Our small team of volunteer developers have put years of effort towards this release, and we’ve pulled it off!
We’ve also joined forces with the dry-rb team. Together we’ve rebuilt Hanami on top of and around the dry-rb libraries. If you’ve ever had an interest in dry-rb, Hanami 2.0 gives you a curated experience and your easiest possible onramp.
Hanami 2.0 marks a major moment for Ruby ecosystem diversity. With this release we’re providing a distinct and compelling new vision for Ruby apps. With the backing of a compassionate and dedicated core team, you can feel confident Hanami will be here for the long run.
Why don’t you take a look? We’d love for you to join us!
You’re just a few commands away from building better, faster, stronger apps:
$ gem install hanami
$ hanami new bookshelf
$ cd bookshelf
$ bundle exec hanami server
Thank you from the Core Team of Luca Guidi, Peter Solnica and Tim Riley.
Thank you also to these wonderful people for contributing to Hanami 2.0!
🌸
]]>