Magicians never share their secrets. But we do. Sign up for our Ruby Magic email series and receive deep insights about garbage collection, memory allocation, concurrency and much more.
At the beginning of the internet age, websites were much simpler and not very interactive. With the advancement of technology, devices, and programming languages, they became more complex and consisted of several files, including assets like images and CSS stylesheets.
This article takes a deep dive into Webpacker and offers a detailed explanation that will enable you to understand how this tool works under the hood. To make the content as valuable as possible, I decided to divide it into the following sections:
After reading this article, you’ll know what Webpack and Webpacker are and why we need them in our Rails application. The deep dive into Webpacker’s internals will help you understand how the tool connects with Webpack and how it communicates with the Rails application.
Before going out into deep water, we first need to prepare. A high-level overview is a great way to start working with any technology as it helps us understand the purpose of a given tool and the problems it solves without going deep into its internals.
A bundle is a file where multiple modules are intelligently placed, respecting the dependency graph that is first created. Thanks to this process, we can be sure that our code will work as expected and before we invoke a given library’s code, it will have been loaded.
Now that you know why Webpack was created and what role Wepacker plays in a Rails application, we can focus on Webpacker’s internals to see how it organizes files, speeds up the development process, and optimizes files for the production environment.
Webpacker is available out-of-the-box in the newest version of Rails. Before creating a new project, ensure that the Node version is greater or equal to 10.17.0 as the
webpacker:install command will be automatically invoked with rails new command.
After the install command is executed, the following files are created:
config/webpacker.yml— the main configuration file that contains the default configuration and configs for specific environments
bin/webpack— an executable file that invokes webpack to create bundles
The main configuration file for Webpacker is located under the config directory, and it’s named
webpacker.yml. Unlike Webpacker, configuration for Webpack is stored separately for each environment under the
By default, the configuration file contains many entries — default ones, and sections for each environment where you can overwrite specific settings. Let’s take a look at the most important settings:
source_entry_path— the name of the directory under the source_path where you keep the pack files, aka entry points. By default, this setting is set to the packs’ directory.
public_root_path— path to the directory in your application that is accessible from a browser. In a typical Rails application, it’s a public directory
public_output_path— when Webpacker compiles your files, it will put all compiled files in this directory under the
public_root_path. By default, the directory is named packs, but you can call it whatever you want.
webpack_compile_output— if the flag is set to true, then output messages are displayed when files are compiled. It’s useful when compilation fails, as you’ll be aware of that and can take action.
It is worth mentioning that the development section also contains configuration for the dev server that is used to compile files in the development environment without the need for restarting the server.
If you would like to access the configuration from the rails console or code level, you can call
Webpacker.manifest.config, which will return the configuration class instance.
Each environment has its configuration file, but in every file, the main environment file is imported:
config/webpack/environment.js. In the environment configuration file, there is a place for loading custom plugins that will modify the default behavior of Webpack. We can also add custom rules for compiling our files.
Packs are located under the
When you generate a new Rails project, a default pack file named application.js is created with the following content:
1 2 3 4 5 6 7 8
import Rails from "@rails/ujs" import Turbolinks from "turbolinks" import * as ActiveStorage from "@rails/activestorage" import "channels" Rails.start() Turbolinks.start() ActiveStorage.start()
As you can see, the first step is to import the given library and then call its initialization method when it’s needed. When you call import, the system searches for a given node module or a local library. With the standard approach, you don’t have to explicitly initialize the library as it’s initialized when you include it in the page source with the script tag.
Pack files are not automatically included in the website’s source. Just like in the asset pipeline case, we have to use a special tag inside our views:
How does this method work? Under the hood, it calls the Webpacker configuration that holds the data you put in the
config/webpacker.yml file. It looks for an application.js file inside the entry points directory, which, in our case, is
When entries are found, Webpacker calls
ActionView library available by default in Rails. The method accepts one or more sources and returns script tags that you can apply straight to your view.
Webpacker development server’s entry point is the executable file placed inside the
bin folder and named
webpack-dev-server. The process of running the server consists of five steps:
config/webpacker.ymlis loaded with settings for the environment set in the previous step.
--httpsoption is given, but we didn’t specify it in the
The server is now running, and it compiles your code on the fly, so you don’t have to restart the server to see the changes and check if webpack was able to create the bundle with the new code.
webpack serve command. You can also run it by hand, but you don’t have to take care of proper command arguments with the built-in command.
Suppose you want to deploy the application that’s using webpacker. In that case, you can simply invoke the
assets:precompile task as Webpacker automatically hooks up the task
webpacker:compile to it.
How does the
webpacker:compile task work under the hood? Let’s dig into it and see. It does the following things:
NODEenvironment is set and Webpacker logs are output to the standard out.
You can now visit the
public/packs/js directory to see the compiled files. They should be deployed to the server.
To summarize the whole article, let’s recall the main elements of Webpacker again:
For many developers without much experience, Wepacker seems to be a little magical, but in fact, it’s a simple library that helps us use Webpack in a Ruby way.
P.S. If you’d like to read Ruby Magic posts as soon as they get off the press, subscribe to our Ruby Magic newsletter and never miss a single post!
Our guest author Paweł is an open-source fan and growth seeker with over a decade of experience in writing for both human beings and computers. He connects the dots to create high-quality software, valuable relations with people and businesses.