Webpacker in Production & Customizing Webpacker

Learn about Webpacker in production and how to customizeWebpacker.

Webpacker in production

Deploying Webpacker to production or staging is similar to deploying previous Rails asset tools. Webpacker creates a Rake task, webpacker:compile, which is made part of the existing Rake task assets:precompile, which is likely part of your existing deployment script.

If you are starting a new project without an existing asset pipeline, you can still use assets:precompile for compatibility with older build tools. It’s essentially an alias to webpacker:compile. The compilation uses the RAILS_ENV value to determine which version of the Webpacker configuration to load.

Customizing Webpacker

Webpacker provides great defaults for webpack, but defaults aren’t always enough; you may still need to customize.

One way to customize Webpacker is to change the settings in the config/webpacker.yml file. You can’t add new settings to this file, but you can change the defaults that are already there, including the input and output paths, webpack-dev-server settings, and extensions to look for.

More elaborate customizations involve changes to the configuration files in the config/webpack directory. This directory contains four files by default: an environment.js and then a development.js, production.js, and test.js file.

The way this works is that Webpacker chooses which file to load based on the Rails environment, each of these files sets the NODE_ENV value (the test.js uses the Node environment of “development”). The files then require in the environment.js file, and do any environment-specific tweaks followed by that, and export the resulting webpack configuration after.

By default there are no environment-specific tweaks, but you can add some. The idea here is that the generated webpack configuration is loaded into a variable called environment. The value of environment is the webpack configuration as a JavaScript object. To make changes, you need to add keys or change the values of keys in accordance with webpack’s configuration.

For example, I talked earlier about how Webpacker enables source maps in production. If you’d like to override that choice, then you can add the following lines to the config/webpacker/production.js file after the environment variable is created, but before it is exported:

environment.config.merge({ devtool: 'none' })

Adding plugins is a little different, you need to prepend them to the environment.plugins array. The exact syntax is going to depend on the plugin, so check the documentation. Here is an example that uses the ProvidePlugin to automatically load jQuery and attach it to the global identifiers most often used to invoke it. The prepend method here is defined by Rails Webpacker’s ConfigList and takes a name for the plugin and inserts it at the beginning of the configuration list.

environment.plugins.prepend(
  "Provide",
  new webpack.ProvidePlugin({
    $: "jquery",
    jQuery: "jquery",
    jquery: "jquery",
    "window.jQuery": "jquery",
  })
)

If you need the plugin to be invoked in a particular order, usually because you are adding a plugin that requires or is required by another plugin, you can use the insert method, which takes the same first two arguments, and then a third argument, which is an object of the form {before: key} or {after: key}. So if you wanted the jQuery plugin to be loaded before some other plugin named, it might look like this:

environment.plugins.insert(
  "Provide",
  new webpack.ProvidePlugin({
    $: "jquery",
    jQuery: "jquery",
    jquery: "jquery",
    "window.jQuery": "jquery",
  }, {before: "Dependent"})
)

Similarly, you can add your own loaders. Webpacker already provides an example here for TypeScript. The Rails configuration has it split over two files, but combined, it would look like this:

environment.loaders.prepend('typescript', {
  test: /\.(ts|tsx)?(\.erb)?$/,
  use: [
    {
      loader: 'ts-loader',
      options: PnpWebpackPlugin.tsLoaderOptions()
    }
  ]
})

Again, you have the option of using prepend or insert to specify the order.

In the case of a loader, if the loader is working with a file type that is not already in your configuration, you also need to update the config/webpacker.xml file to add your new extension to the existing list. If you look at that file now, you’ll see that the extensions key has had .ts and .tsx added to it.

What’s next?

With our build system explained, we’re ready to add more complex features to the code. In the next chapter, we’ll talk about communicating with the server and how we can manage communications as part of both our Stimulus and React code.

Get hands-on with 1400+ tech skills courses.