Webpack dev server and Rails on Cloud9
Please note that this article is particularly relevant when
migrating the webpacker
gem from v3.0.1 to v3.0.2, as described in
the below.
Contents
Context
This article describes how to properly configure
webpack-dev-server
with webpacker
gem on a Cloud9 workspace.
After a preliminary remark about the proper binstub version of the
./bin/webpack-dev-server
script, this article presents two ways to
tackle the task: a simple and quick solution, which
is sufficient if we work alone on a project, and a slightly more
involved but flexible approach, that can be
useful when several people might work in the same codebase.
Binstub versions
A lot of the confusion about the webpack-dev-server
options and
why they might not be properly taken into account, might be due to an
outdated version of the ./bin/webpack-dev-server
script. The script
created by the rails webpacker:install
task of the webpacker
gem
v3.0.1 (source) is not
compatible with how v3.0.2 (sic) of the gem handles the
webpack-dev-server
option flags (see full list of
versions below), which logically expects the
corresponding binstub version of the script
(source). So please make sure that
you are using the correct binstub
(the same applies to ./bin/webpack
). To be
fair, the changelog of v3.0.2 properly mentions the change:
- Added: Binstubs #833
- (…)
- Removed: Inline CLI args for dev server binstub, use env variables instead
Quick solution
If you are working alone, the easiest way to fix the configuration of
the webpack-dev-server
is to modify the development.dev_server
entry of the config/webpacker.yml
file.
config/webpacker.yml
file
The development.dev_server
entry of the config/webpacker.yml
file
has to be changed from the following default values:
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
disable_host_check: true
use_local_ip: false
into these custom configuration:
dev_server:
https: true
host: localhost
port: 8082
public: your-workspace-name-yourusername.c9users.io:8082
hmr: false
inline: false
overlay: true
disable_host_check: true
use_local_ip: false
You can obtain the value your-workspace-name-yourusername.c9users.io
for your Cloud9 workspace with echo ${C9_HOSTNAME}
.
There are four main differences with the approaches found in the mentioned sources:
- Some solutions suggested to set the
host
option toyour-workspace-name-yourusername.c9users.io
, which required to add a line to the/etc/hosts
file by runningecho "0.0.0.0 ${C9_HOSTNAME}" | sudo tee -a /etc/hosts
. This was only necessary due to restrictions in previous versions ofwebpacker
and how the value of thepublic
setting was calculated. Currently it is no longer necessary to modify the/etc/hosts
file because thehost
setting can be kept aslocalhost
.
-
Some solutions stressed the need to set the
https
option tofalse
but this failed withnet::ERR_ABORTED
in the browser console and raised the following exception in the server when the client tried to get the JavaScript sources:#<OpenSSL::SSL::SSLError: SSL_connect SYSCALL returned=5 errno=0 state=unknown state>
Setting
https: true
removes the issue. -
By leaving the
inline
option to the defaultfalse
value, the live compilation still works but the browser console constantly reports the following error:Failed to load https://your-workspace-name-yourusername.c9users.io:8082/sockjs-node/info?t=1511016561187: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://your-workspace-name-yourusername.c9users.io' is therefore not allowed access. The response had HTTP status code 503.
Setting
inline: false
removes the issue. -
None of the solutions suggested to set the
public
option in theconfig/webpacker.yml
file and some suggested to pass it to thewebpack-dev-server
command line. By setting it in the configuration file we don’t need to care about it in the terminal.
With this configuration, running as usual ./bin/webpack-dev-server
in one terminal and ./bin/rails s -b $IP -p $PORT
in another should
work.
Flexible solution
The previous solution is useful and fast to implement, but if you are
working with other people on the same repo it can be tricky to
maintain the proper configuration in the config/webpacker.yml
file.
Moreover, the hostname of your Cloud9 workspace is hardcoded, so
that the configuration is not portable.
A hint about another way to configure the webpack-dev-server
can be
found in the README of this repo:
You can use environment variables as options supported by webpack-dev-server in the form
WEBPACKER_DEV_SERVER_<OPTION>
. Please note that these environment variables will always take precedence over the ones already set in the configuration file.
Note that when the configuration of the webpack-dev-server
is
tweaked with ENV variables, those same values have to be passed to
the rails server
process as well in order to let it use the same
configuration.
Taking that into account, a flexible solution can be implemented using
foreman
with the following Procfile.dev
:
web: ./bin/rails server -b ${RAILS_SERVER_BINDING:-localhost} -p ${RAILS_SERVER_PORT:-3000}
webpacker: ./bin/webpack-dev-server
and this bin/start
script:
#!/bin/bash
# Immediately exit script on first error
set -e -o pipefail
APP_ROOT_FOLDER="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${APP_ROOT_FOLDER}"
if [ -n "${C9_USER}" ]; then
# We are in a Cloud9 machine
# Make sure that Postgres is running
sudo service postgresql status || sudo service postgresql start
# Adapt the configuration of the webpack-dev-server
export APP_DOMAIN="${C9_HOSTNAME}"
export RAILS_SERVER_BINDING='0.0.0.0'
export RAILS_SERVER_PORT='8080'
export WEBPACKER_DEV_SERVER_PORT='8082'
export WEBPACKER_DEV_SERVER_HTTPS='true'
export WEBPACKER_DEV_SERVER_HOST="localhost"
export WEBPACKER_DEV_SERVER_PUBLIC="${C9_HOSTNAME}:${WEBPACKER_DEV_SERVER_PORT}"
export WEBPACKER_DEV_SERVER_HMR='false'
export WEBPACKER_DEV_SERVER_INLINE='false'
export WEBPACKER_DEV_SERVER_OVERLAY='true'
export WEBPACKER_DEV_SERVER_DISABLE_HOST_CHECK='true'
export WEBPACKER_DEV_SERVER_USE_LOCAL_IP='false'
fi
foreman start -f Procfile.dev
With these two scripts in place, the application can always be started
by running bin/start
, in both Cloud9 and other systems. The
trick is that by exporting the WEBPACKER_DEV_SERVER_*
variables
before calling foreman start
, we make sure that those values are
available to both webpack-dev-server
and rails server
processes.
Sources
- “Webpack dev server and Rails on Cloud9” (the original source for the present article, inspired by this comment)
- “Making Webpacker run on Cloud 9” (GitHub issue)
- “Anyone here got webpack-dev-server to work on Cloud 9?” (GitHub issue)
webpacker
documentationwebpacker/dev_server.rb
codewebpack-dev-server
documentation- “Using Rails With Webpack in Cloud 9” (blog article)
Versions
Since things in this ecosystem move fast, it’s important to mention the versions of the world for which this documentation is relevant:
$ egrep '^ ?(ruby|webpacker|rails) ' Gemfile.lock
rails (5.1.4)
webpacker (3.0.2)
ruby 2.4.2p198
$ yarn versions
yarn versions v1.1.0
{ http_parser: '2.7.0',
node: '8.5.0',
v8: '6.0.287.53',
uv: '1.14.1',
zlib: '1.2.11',
ares: '1.10.1-DEV',
modules: '57',
nghttp2: '1.25.0',
openssl: '1.0.2l',
icu: '59.1',
unicode: '9.0',
cldr: '31.0.1',
tz: '2017b' }
$ cat /etc/os-release | head -6
NAME="Ubuntu"
VERSION="14.04.5 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.5 LTS"
VERSION_ID="14.04"
Everything was tested using Chrome Version 62.
tl;dr
-
Make sure that you are running the proper binstub version of
./bin/webpack-dev-server
. -
Change the
development.dev_server
entryconfig/webpacker.yml
file into:dev_server: https: true host: localhost port: 8082 public: your-workspace-name-yourusername.c9users.io:8082 hmr: false inline: false overlay: true disable_host_check: true use_local_ip: false
-
Now running as usual
./bin/webpack-dev-server
in one terminal and./bin/rails s -b $IP -p $PORT
in another should work as expected.