Why Webpacker Wouldn't Compile Assets in a Specific Environment
A while back, I started working in a Rails application in which I needed to introduce a JavaScript file that’d be compiled with Webpacker. To do so, I created the file in my packs
directory and loaded it up via content_for
:
<% content_for(:body_assets) do %>
<%= javascript_pack_tag("some-file") %>
<% end %>
Locally, things worked great! But once I deployed, integration tests running in the CI pipeline would unexpectedly fail, even though the same tests were passing on my machine. After some time spent troubleshooting, it turned out to be one primary issue, which was drawn out by my misunderstanding of how Webpacker loads configuration settings for an environment. This is a quick review of the entire debugging process.
Problem #1: A manifest.json
file wasn’t being generated.
As Rails is running a request and the javascript_pack_tag
method is encountered, it’ll reference a manifest.json
file in order to load the correct assets. If that file doesn’t exist, Rails vomits. This is the sort of error you’ll see:
ActionView::Template::Error: Webpacker can't find some-script in /my/app/path/public/packs/manifest.json. Possible causes:
1\. You want to set webpacker.yml value of compile to true for your environment
unless you are using the `webpack -w` or the webpack-dev-server.
2\. webpack has not yet re-run to reflect updates.
3\. You have misconfigured Webpacker's config/webpacker.yml file.
4\. Your webpack configuration is not creating a manifest.
This made sense. Upon deploy, Webpacker was apparently not being told to compile assets before requests were made or as they were made, and so that file was never getting correctly generated.
Solution: Ensure my webpacker.yml
file has compile
set to true
.
In all of my environments except production
, I wanted to set compile
to true
, so that on each request, Rails would check to see if it needs to compile assets before continuing. Instead of duplicating this change in my development
and test
environments, I opted to make it the default, since production
already had it explicitly set to false
.
default: &default
compile: true
development:
<<: *default
# other settings...
test:
<<: *default
# other settings...
production:
<<: *default
compile: false
# other settings...
I felt good about this… until it failed.
Problem #2: Webpacker wasn’t respecting default settings in its configuration file.
After some brief internal rage, I noticed a particular log that I must have passed over earlier:
RAILS_ENV=build environment is not defined in config/webpacker.yml, falling back to production environment
My tests were being run in the build
environment – not test
. And as it turns out, Webpacker will fall back production
if it can’t find the specified environment. This is why my assets weren’t being compiled. A build
environment wasn’t set in my Webpacker configuration file, so it was falling back to production
, which was explicitly telling Webpacker to not compile assets.
Solution: Ensure my environment exists in the webpacker.yml
file.
Like most bugs that tempt you to rip your hair out, the solution turned out to be two lines:
build:
<<: *default
Sure, enough. All was green after that change.
Key Takeaway: Read Your Logs Good.
What bit me here is some assumptions I made about how Webpacker loaded a configuration. The amount of time dealing with the consequences of those assumptions might have been avoided if I had been just a little more thorough in reading through the error logs. Don’t make this mistake yourself!
Alex MacArthur is a software engineer working for Dave Ramsey in
Nashville-ish, TN.
Soli Deo gloria.
Get irregular emails about new posts or projects.
No spam. Unsubscribe whenever.