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
Setup Rails to Serve the HTML Generated by Webpack
rails generate controller pages index
Rewrite the pages controller to:
- Inherit from
ActionController::Base
. Because this is an API app,ApplicationController
inherits fromActionController::API
instead - 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'
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