Rails Friends: API and Webpacker

Rails Friends: API and Webpacker

It appears you can not use --api and --webpack=react together when creating a new Rails App. It’s a shame, because having Rails handle the backend and React, or other JS framework, handle the frontend is a common setup. But it is possible to add webpacker to an api App and use HtmlWebpackPlugin to serve the webpack bundles.

Nothing on the rails new documentation suggest that the two are incompatible, but running rails new rails-api-webpacker-demo --api --webpack=react together, appears to ignore the webpacker configuration steps.

$ rails new --help
...
    [--api], [--no-api]          # Preconfigure smaller stack for API only apps
--webpacker, [--webpack=WEBPACK] # Preconfigure Webpack with a particular framework (options: react, ...)
...

I found this comment on a Webpacker issue titled: “Rails API + Webpacker?”. This blog post is based on the linked repository, broken down into steps for easier understanding.

Tutorial

Create an --api App

Because --api preconfigures a smaller stack, let’s start with it and add webpacker later.

rails new rails-api-webpacker-demo --api

Install Webpacker

Add to Gemfile:

gem 'webpacker'

Run:

bundle install
rails webpacker:install
rails webpacker:install:react

Install HtmlWebpackPlugin and HtmlWebpackHarddiskPlugin

Run:

yarn add html-webpack-plugin html-webpack-harddisk-plugin

Configure the installed plugins in config/webpack/environment.js according to their documentation (1)(2):

const { environment } = require('@rails/webpacker')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin')

environment.plugins.append(
  'html',
  new HtmlWebpackPlugin({
    alwaysWriteToDisk: true
  })
)

environment.plugins.append(
  'html-harddisk',
  new HtmlWebpackHarddiskPlugin()
)

module.exports = environment

a8fad1d

Setup Rails to Serve the HTML Generated by Webpack

rails generate controller pages index

Rewrite the pages controller to:

  1. Inherit from ActionController::Base. Because this is an API app, ApplicationController inherits from ActionController::API instead
  2. Have :index render the file generated by webpack
class PagesController < ActionController::Base
  def index
    render file: 'public/packs/index.html'
  end
end

Remove the get 'pages/index' added to routes (config/routes.rb) and add:

root 'pages#index', as: :pages_index
get '*path', to: 'pages#index'

6ff32b0

Conclusion

Run both commands in different terminals:

webpack-dev-server
rails server

Open http://localhost:3000/ and you’ll see both: “Hello React” in the body and “Hello World from Webpacker” in the browser’s console.

I’ve published this on Github at leonelgalan/rails-api-webpacker-demo and deployed to Heroku as ancient-falls-96742.herokuapp.com


Photo by Erfan Moradi