Published by Vladimir DraloJun 1, 2017

Here, at Elixirator, we had a major rework for one of our projects. We were moving project's backend from Rails to Hanami as part of this task. The Rails application had a mix of the javascript code, including vanilla JS, Coffeescript, JQuery and React. The final goal was to get rid of all extra dependencies, and use only one approach for writing frontend code - React.js. READMORE

We have decided to use Webpack as the main source of all frontend code, including Javascript and CSS. One of the first steps of the migration was making Hanami and Webpack work together.

After some initial testing, the best approach was found for our needs. Here is a short overview how it can be done.

Webpack configuration

First what is needed to be done, is Webpack. Hopefully, there is nothing difficult here. Just some basic Webpack stuff. Dev server needs to be started at some address, serving assets from the specific location.

An example of simple configuration could look like this:

// webpack.config.js
{
  output: {
    path: path.join(__dirname, '..', 'public', 'assets'),
    filename: '[name]-bundle.js',
    publicPath: 'http://localhost:8080/assets/'
  }
}

Hanami configuration

Hanami configuration is easy thanks to built-in helpers, which allow consuming assets from CDN. It is needed to specify content security policy to accept Javascript, CSS, images, etc. from location different than a website address. Providing config with the same host and port (as in the Webpack config) allows achieving this.

# application.rb
configure :development do
  security.content_security_policy %(
    script-src 'unsafe-eval' *;
    connect-src 'self' *;
    img-src 'self' data: *;
    style-src 'unsafe-inline' *;
    font-src 'self' *;
  )

  assets do
    compile false
    cdn true
    host '0.0.0.0'
    port 8080
  end
end

Going live

Despite using React.js as our main frontend library, most of the views are still written in plain HTML. These views are using Hanami asset helpers, such as image and javascript. We wanted to keep them. And we wanted to keep digested assets provided to us by Hanami.

When I was looking for the solution, I have tried to solve manifest file generation from the Webpack side initially. But existing plugins were producing it with the format that was not understood by Hanami. After spending some time, trying to export manifest with JS, I realized that I can achieve same easily using plain Ruby.

Webpack already outputs filenames with digest hash inside to the specified folder. So all I need is just get all files in assets folder, and save them to the JSON in the format that could be understood by Hanami.

The final solution is really straightforward:

# assets_tasks.rake
namespace :assets do
  desc 'Generate assets from webpack'
  task :generate do
    pty 'npm run build:development'

    assets_hash = {}

    Dir.glob('./public/assets/**/*.*').each do |f|
      file       = Pathname(f.sub('./public', ''))
      folder     = file.dirname
      asset_name = file.basename.to_s.split('_').first
      extension  = file.extname
      assets_hash["#{folder}/#{asset_name}#{extension}"] = { target: file, sri: '' }
    end

    File.open('./public/assets.json', 'w') { |f| f.write(assets_hash.to_json) }
  end
end

Summary

As the result, we started to use the combination of Hanami and React.js as our main tools. Adding minor features like auto mounting of React components, using mini SPAs inside the application, made our experience really smooth and pleasant. Webpack integration was just one of the first steps of our journey from Rails to Hanami. But this is a really long story. Stay tuned.

Like the article? Spread the world

Also recommend

We’re always attentive to the opinion of our customers and take into account all the shortcomings

front-end

Nuxt, Netlify forms and "failed to execute 'appendChild'"

Maria Tsvetkova

Mobile

React Native vs Flutter - which way to go?

Serhii Rosinets, Stepan Rudenko

tips

Talent managing remotely. Tips and tricks

Kateryna Shubina

back-end

How to create Slack bot in Elixir

Alex Beznos