Assets Serving: Webpack
Pros and Cons
There several benefits to using webpack to build assets like images.
- Webpacker adds sha checksums to assets as a part of building them to the
public/packsfolder. The checksums optimize performance since images can be cached for very long periods of time. IE: 10y.
- You’ll be able to configure high values for the
max-ageresponse header. This article Increasing Application Performance with HTTP Cache Headers covers how cache headers work. The default max-age for assets serving out of s3 is 3600s or 1h.
- If you replace an image and keep the same name, you don’t have to update the code as the
image_pack_taguses the compiled image with the sha checksum. It’s nice to offload menial tasks like file renames to automation. Instead, we can spend the precious mental energy on coding business logic.
There are also some downsides with using webpacker, though:
- Webpacker and the node world tend to move very rapidly. As such, it tends to feel like the wild west at times.
- This is the nature of the beast. Moving fast can break things. Configurations like
config/webpacker.ymlinterfaces can change. Here are just some examples: 2059, 2202, 2342
- If you’re not keeping up with the changes of the ecosystem, it is sometimes faster to treat things like black box. IE: Upgrade yarn, node, and regenerate the configuration files and see if that fixes issues.
All that being said, it is recommended that you take advantage of webpack for the benefits.
How To Tutorial
Here’s a summary of the steps on how to use webpacker for assets like images. Note, the folder structure and instructions can be adjusted your our own preferences. The source code for this tutorial is available at: tongueroo/jets-webpacker-demo
- Put files in
- Import images in
- Use the
image_pack_tagin your views with the conventional
1. Put files in
We’ll put files in:
app/assets/ └── images ├── jets.png └── southpark ├── eric.png └── stan.png
config/webpacker.yml with the
With webpacker, have found success by configuring
default: &default # ... resolved_paths: ['app/assets'] extract_css: true
Note, these should be the default values, but there are noted here in case these defaults change. Please double check
3. Import images in
public/packs/manifest.json. Note: In development mode,
bin/webpack runs automatically as part of the request cycle.
Instead of importing images one at a time, we’ll import the entire folder recursively. See: 705. Here’s a more concise way to import a folder of images. Add this line to your code.
4. Use the
image_pack_tag in your views with the conventional
Now you’re ready to use the
image_pack_tag in the views. Here’s an example.
<div>Jets: <%= image_pack_tag("media/images/jets.png") %></div> <div>Eric: <%= image_pack_tag("media/southpark/eric.png") %></div>
Notice the convention:
app/assets/images/jets.png => image_pack_tag("media/images/jets.png") app/assets/images/southpark/jets.png => image_pack_tag("media/southpark/eric.png")
This is the current convention that webpack has chosen.
To double-check that the assets are compiling correctly, run
bin/webpack and check generated
$ bin/webpack $ grep media public/packs/manifest.json "media/images/jets.png": "/packs/media/images/jets-87771aa5.png", "media/southpark/eric.png": "/packs/media/southpark/eric-6809100c.png", "media/southpark/stan.png": "/packs/media/southpark/stan-91559ff6.png", $
The Jets default max-age for assets serving out of s3 is 3600s or 1h. When using webpacker, since the sha checksums are added, it makes sense to use longer TTLs. Here’s an example:
Jets.application.configure do # ... # Default assets settings config.assets.folders = %w[assets images packs] config.assets.max_age = 3600 # max_age is a short way to set cache_control and expands to cache_control="public, max-age=3600" # config.assets.cache_control = nil # IE: "public, max-age=3600" # override max_age for more fine-grain control. # config.assets.base_url = nil # IE: https://cloudfront.com/my/base/path, defaults to the s3 bucket url # IE: https://s3-us-west-2.amazonaws.com/demo-dev-s3bucket-1inlzkvujq8zb end
Jets will automatically upload images in
public/packs to s3 by default. See the
assets.folders setting at Config References. Jets has also decorated the
image_pack_tag so assets will be served from the s3 bucket. Running:
And viewing the html source should show something like this:
<img src="https://s3-us-west-2.amazonaws.com/demo-dev-s3bucket-11hmo46sdaczc/jets/public/packs/media/images/jets-87771aa5.png" /> <img src="https://s3-us-west-2.amazonaws.com/demo-dev-s3bucket-11hmo46sdaczc/jets/public/packs/media/southpark/eric-6809100c.png" /> <img src="https://s3-us-west-2.amazonaws.com/demo-dev-s3bucket-11hmo46sdaczc/jets/public/packs/media/southpark/stan-91559ff6.png" />
Using webpack with assets gives you the benefit of performance and automation. It can take some time to set up, though, and debugging webpack can be difficult since the ecosystem tends to move fast. You are often times better off upgrading the tools like yarn, node, and updating the configuration files. For innovation, fast-moving technologies are generally a good thing.