Improve CLI commands
Our implementation is based on
thor, which doesn’t work well with subcommands. Aside from that, the implementation of the generators is hard to maintain. Luckily we have a really good integration testing coverage so we can apply the following ideas.
As mentioned above,
thor doesn’t work well with subcommands and with exit codes. We can replace it with
optparse from Ruby’s standard library.
thor ships with useful file manipulation utilities. We can promote our file helpers from our test suite as replacement.
Our helpers don’t provide a consistent indentation of Ruby code. We should find a solution for that (https://rubygems.org/gems/rubyfmt ?).
Commands as objects
thor demands that commands are methods of an object.
class MyCli < Thor def command_a end end
We want to Implement each (sub)command as an object. This approach allows us to put args validations in each class and it decouples the command (
hanami routes) from the concrete implementation that can be provided by us or a third party gem.
class MyCommand < Hanami::Command # arguments validations DSL def call(arguments) # do something end end
Let commands to register themselves
class MyCommand < Hanami::Command # hanami routes register_as "routes" # or ... # hanami generate auth register_as "auth", subcommand_of: "generate" # ... end
This opens an endless possibilities for our ecosystem.
Please note that a third party-gem can take over an entire (sub)command (eg.
hanami-cool-orm can take over
hanami generate model)
There are commands that don’t need the full blown Hanami project to do their job.
hanami routes, it only needs the routes from the project, without connecting to the database.
0.9, we already let some commands to pick that dependencies. The goal is to let all the commands to work with this approach. See this example: https://github.com/hanami/hanami/blob/master/lib/hanami/commands/routes.rb
These features can be shipped in the
1.x series, as they don’t introduce breaking changes for our users.
Improve Code Reloading
shotgun as a soft-dependency for code reloading. If required in
hanami server auto-detects it and the code is auto-reloaded after each incoming HTTP request.
We broke code reloading a few times, and the only way to fix it was to introduce
Hanami::Utils.reload! in order to
load again the files under
We can investigate alternatives for
shotgun and integrate them:
guardmy favorite, it comes with a lot of useful plugins like
guard-livereloadand it works on Windows too.
rerunit works out-of-the-box, with less configurations. It works only on *NIX.
entrthis is a *NIX executable written in C. We introduced experimental support for it from
0.9and didn’t worked well. But some people in our chat are promoting it, so we can have a second look.
The goal is still the same: keep Hanami project unaware of code reloading. Only
hanami server is aware of this feature, and it acts as a reloadable shell for a project.
The target release for this has to be decided. There are some solutions like
entr that don’t require changes in existing projects, while
guard requires the addition of a
Depending on the decision that we’ll take and the effort it can be in
1.x series or even in
Native Webpack Support
I confessed several times, I’m a backend guy. Hanami assets as they are now, work fine for my needs. However, we received several feedbacks about how this system is limiting and how Webpack is better for advanced features. No doubt it is. So why don’t let frontent devs to work with their favorite tool?
By default, a new project will have the actual assets system (
hanami new bookshelf).
But when the
--webpack flag, it generates the configurations needed by Webpack.
There are a few technical issues to address:
- How to hook Webpack paths for assets with our helpers (eg.
- We should provide a smooth development experience to start both Hanami and Webpack server. My idea is to use
Procfile.dev, and when
hanami serveris started, it will use it.
This will probably need to introduce breaking change, so the target release is
2.0. I want a frontend dev to work/advise on this.
Unobtrusive JS (UJS)
The idea is to use
vanilla-ujs gem to provide AJAX capabilities to Hanami, without depending on a JS framework.
This is a two steps improvement:
vanilla-ujsfiles to make them available into a Hanami project
- Expand the capabilities of our helpers (eg.
This can theoretically be part of the
New Router Implementation
http_router as engine. This gem served well us until now, but it’s no longer maintained. We want to switch to
This will require breaking changes in the routing API, so the target release is
Roadmap for v2.0.0.alpha1
Introduce an events system that can provide an API to emit/handle them. The system is similar to
ActiveSupport::Notifications, and it should use
The idea is to “broadcast” an event happening in the framework or in a Hanami project and let the other part of the system to react to it. There are several scenarios.
class WelcomeMailer subscribe_to "user.signup" end
class DripAdapter subscribe_to "user.signup" end
class Signup include Hanami::Interactor def call(data) user = UserRepository.new.create(data[:user]) broadcast("user.signup", user: user) end end
When that event is emitted,
DripAdapter will receive a notification and react accordingly.
Continuing on the previous example, the broadcast is immediate, but the execution of the receiver logic can be async. We can send to a queue system (eg.
sidekiq) the name of the event and the payload and let it to schedule the execution.
The API could be
broadcast("user.signup", user: user).async(...)
def render broadcast('rendering.template') do # ... end end
This reports the elapsed time. We can use it to log when a template was rendered.
This can be part of
Move Mailers To
Hanami architecture has one golden rule: the core of a Hanami project lives in
lib/, while the deliverability mechanisms (for the web) live in
apps/. The code in
apps/ can reference (depend) code in
lib/ but NOT viceversa.
Because we offer Interactors (aka service objects) as part of the core of a Hanami project, their natural place is
Interactors sometimes need to send emails, so to not break the golden rule above, we put mailers in
This is wrong for two reasons:
- Mailers are deliverability mechanisms too, so they shouldn’t stay in
- If they stay out of
apps/they cannot access to assets helpers
The solution is to move mailers to
apps/, and so the command to generate a mailer should go from:
hanami generate mailer welcome
hanami generate mailer web welcome
web is one of the applications living under
apps/. This is the same concept of
hanami generate action command.
Because this is a breaking change the target release is
I think we can ask help from Samuel Simões (https://github.com/samuelsimoes) for this
Great, do you know Samuel?
group admin: AdminMiddleware do resources 'books' end
And have an
AdminMiddleware called before every route on the group.
Nope, but I think it will not a problem for us
We can send an email or tweet him.
What’s the advantage of this? Do you know you can add a middleware in front of single apps as now? Thanks.
Ok, but why him then?
because he is the author of https://github.com/samuelsimoes/hanami-webpack and I think he have experience in this question
I didn’t know that, can you give me some pointers please?
@CassioGodinho please open
apps/web/application.rb and search for
middleware.use, it’s commented code.
One advantage I can think of is having a Middleware for only some routes on an app that needs to be authenticated and halting the request before it gets to the controller eliminating the need of a
Maybe I’m just trying to find a way to work the way I’m used to work on Laravel and I have yet to understand how things work with Hanami.
First of all, I’m very happy to hear that Hanami team is considering Webpack. Webpack is an awesome tool to bundle/process assets.
I’ve created the hanami-webpack, a very experimental and hacky gem to run Webpack with Hanami, but it’s important to tell that I just followed some principles that I saw in https://github.com/mipearson/webpack-rails.
The answers to your questions:
In my gem I used the Webpack’s
StatsPlugin to expose, through a JSON manifest, the path for my [webpack entry points] (http://webpack.github.io/docs/configuration.html#entry), so the Hanami can download this manifest in order to figure out the paths for the entries.
Here some key points about the implementation:
About the server, I totally agree with you about the smooth integration between webpack dev server and Hanami, in my gem I made a monkey patch on the Hanami::DevServer.start to spawn a process with the webpack dev server https://github.com/samuelsimoes/hanami-webpack/blob/master/lib/hanami_webpack/dev_server.rb#L7 to make the dev server integration transparent, I don’t know if it’s a good idea, just sounded good for me.
I’m not a specialist in Webpack or Hanami, but I’m glad to help you guys on this topic.