Webpacker in Production & Customizing Webpacker

Let's have a look at "Webpacker in Production" and how to customize it.

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. This task is likely part of our existing deployment script.

If we start a new project without an existing asset pipeline, we 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; we may still need to customize.

One way to customize Webpacker is to change the settings in the config/webpacker.yml file. We can’t add new settings to this file, but we 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, 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, and 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, do any environment-specific tweaks, and then export the resulting webpack configuration.

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

For example, we discussed earlier how Webpacker enables source maps in production. If we’d like to override that choice, we can add the following lines to the config/webpack/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: we 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 we need the plugin to be invoked in a particular order, usually because we are adding a plugin that requires or is required by another plugin, we can use the insert method, which takes the same first two arguments and then a third argument that is an object of the form {before: key} or {after: key}. So, if we wanted the jQuery plugin to be loaded before some other plugin, it might look like this:

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

Similarly, we can add our 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, we 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 our configuration, we also need to update the config/webpacker.xml file to add our new extension to the existing list. If we look at that file now, we’ll see that the extensions key has had .ts and .tsx added to it.

Get hands-on with 1000+ tech skills courses.