Unlike Asset Pipeline, Webpack is a tool which exists entirely outside of the Ruby on Rails’ realm. In my humble opinion, the most powerful way to use it is through direct use instead of being pigeonholed into specific and often older versions of dependencies. What happens when you want to use something cutting-edge like Vue CLI 3? There is simply no mechanism in place for doing so. If you just use the Webpacker Vue installer, you certainly won’t be using the Vue CLI and all of the power and flexibility it provides.

One might argue that if you want to use a tool like Vue CLI, you can simply create a standalone project that connects to any backend, including Rails. Ok, I’ll grant you that. Suppose, however (and for whatever reason you deem necessary), that you want all of your code in one place, and that perhaps you want to share assets such as styles and scripts between your Vue application and your Rails application? Then it might make sense to build them into the same project.

As I first stated, I originally sought to connect Ruby on Rails and Webpack without Webpacker. I even created a proof of concept in our application for MobileCause, the company where I work at. I dove into the Webpacker source code to figure out exactly how they were solving certain problems, such as proxying, shared configurations between Rails and Vue, detection of webpack-dev-server, detection of changes to frontend resources, generation of a manifest.json file, etc. I even repurposed small fragments of the Webpacker code in our codebase to enable this integration. As I added more functionality into this integration, I found myself diving deeper and deeper into Webpacker’s source code. Before I did a full-scale reproduction of their source code within our repository, I decided it might just be worth another attempt at using this gem. However, this time, I went into it with the mindset of using Webpacker’s Rails’ side code as much as possible, but doing all of the Webpack configuration myself. What follows is the steps one can follow to do exactly this in your own projects.

Installing Webpacker

To begin with, either generate a new Rails application with Webpack and with Sprockets / Asset Pipeline disabled, or add the webpacker gem into an existing project

// ------ FOR A NEW RAILS APPLICATION --------

// From command line

rails new webpackerapp --skip-sprockets --webpack

// ------------------------------------------- // ------ FOR AN EXISTING RAILS APPLICATION --

// Add to Gemfile:

gem 'webpacker'

// From command line

bundle install

// ------ FOR RAILS >= 5 ---------------------

bundle exec rails webpacker:install

// ------ FOR RAILS < 5 ----------------------

bundle exec rake webpacker:install

// -------------------------------------------

Note: Webpacker requires Rails 4.2 or greater. Running the above install command, you may receive an error attempting to run the above rake command, something along the lines of “No such file or directory — ./bin/rake (LoadError)”. If this is the case, it simply means your project was probably created before binstubs were automatically generated with new Rails application (something which started happening at some point in Rails 4). Simply run “rake rails:update:bin” to generate them and then rerun the install command.

Ripping Out Most Of Webpacker

Now that Webpacker is installed, here comes the fun part: let’s rip most of it out:

rm -rf node_modules/ package.json yarn.lock babel.config.js config/webpack app/javascript .browserslistrc postcss.config.js

In they came, out most of them went. In fact, there should really only be three Webpacker-specific files left:

“config/webpacker.yml”: this file will serve as a means to share configuration data between the Rails app (using the Webpacker gem) and the frontend application where we will be configuring this file to be read in from

“bin/webpack”: the Webpacker gem uses this file to build our Webpack entry files for production. The Webpacker gem modifies the Rake assets:precompile task to also compile our Webpack entry files on our production server when we are deploying

“bin/webpack-dev-server”: we won’t be using this file in any meaningful way; however, the Webpacker gem relies on its existence in order to compile our code, so we keep it around purely for that reason alone.

Virtually everything on the Ruby side of the Webpacker gem relies on the existence of these three files, and we will be putting the first two of these files to good use. But first, let’s create a Vue application using Vue CLI.

Generating A Vue Application With Vue CLI

Please make sure you have all the necessary packages installed for Vue CLI 3. If everything is installed correctly, you’re ready to generate the Vue application. For this demonstration, I’m going to generate the Vue application within the Rails directory “app” in a subdirectory called “frontend”:

// From command line, within the root directory of the project

cd app

vue create frontend

// For my app, I chose "Manually select features",

// then added CSS Preprocessors, dart-scss, and

// ESLint + Standard Configuration, Lint on Save,

// and dedicated config files

cd frontend

Mimicking Webpacker’s Organization And Setup

Ok, now that we have Vue CLI generated files, we’re going to move a bunch of them into our root Rails directory in place of the ones that were installed by Webpacker.

// From command line, within the app/frontend directory

mv node_modules/ yarn.lock package.json babel.config.js ../..

// There may be additional files to move depending on your

// selections when generating the app using Vue CLI

cd ../..

Now, back in the root directory of our Rails application, we’re going to install one of the key dependencies that “@rails/webpacker” would have installed for us (had we not removed it): webpack-assets-manifest. This Webpack plugin will automatically generate a manifest.json file that includes mappings between the Webpack managed assets and their Webpack generated paths:

// From command line, within the root directory of the project

yarn add -D webpack-assets-manifest

Now, let’s make some minor alterations to the Webpacker config file, found in config/webpacker.yml:

Change the “source_path” property to “app/frontend/src” Change the “source_entry_path” to property to an empty string ‘’

This is the directory inside of the above “source_path” specified directory where all of the entry files will be located. By default, Webpacker assumes you want to put all of your entry files in a directory of their own called packs. This is likely just a matter of personal preference but conventions in Vue applications seems to always place these files at the root level of the src directory; hence setting this value as an empty string ensures that this Vue convention is followed.

Let’s also take this opportunity to change how Webpacker builds our entry points. Instead of using Webpacker’s internal setup for compiling, we are going to modify the “bin/webpack” script to build using Yarn and Vue CLI. Open up “bin/webpack” and change the contents to:

#!/usr/bin/env ruby

ENV["NODE_ENV"] ||= "development" Dir.chdir(File.expand_path("..", __dir__)) do

Kernel.exec(ENV, "yarn build")

end

Making these changes will effectively modify the Rake task “webpacker:compile” to build using the package.json “build” task that our Vue CLI application generated. This will also change how the Rake task “assets:precompile” runs when deploying our application to Production.

Sharing Webpacker’s Configuration With Vue CLI

Vue CLI applications may be configured beyond what is provided out of the box by creating a file in the root Rails’ directory called “vue.config.js”. Here’s the annotated configuration file I am using:

Essentially, we read in the YAML configuration file “webpacker.yml” that was included when Webpacker was installed. We use the various configurations from that file to build our Vue Webpack configuration. This includes dynamically determining entry points, configuration for generating the manifest.json file, specifying webpack dev server settings, etc.

Using Webpacker in Rails

Ok, we now have roughly all the pieces in place to start using Webpacker to serve up assets from Webpack Dev Server and configured using Vue CLI. Let’s generate a simple example pulling in all the pieces.

First, let’s generate a simple controller and action

// From command line

rails generate controller pages index

Go into the layout file “app/views/layouts/application.html.erb” and replaces the calls to “stylesheet_link_tag” and “javascript_include_tag” with:

<%= stylesheet_packs_with_chunks_tag 'main' %>

Just before the body tag is closed, add the following line:

<%= javascript_packs_with_chunks_tag 'main' %>

Go into the template file “app/views/pages/index” and replace the contents of the file with:

<div id="app"></div>

Start your server in one tab using rails server and webpack-dev-server in another tab using yarn serve and view your page by visiting http://localhost:3000/pages/index.

If everything is working properly, you should see a page that looks something like this:

Wrapping Up

If your page is rendering correctly, congratulations! You’ve successfully integrated Webpacker with Vue CLI. Go ahead and play around with hot module reloading by changing code in the Vue application, such as modifying “app/frontend/src/App.vue”. You should see changes on the webpage almost immediately.

You can also try quitting webpack-dev-server and hitting the page again. This time, it may take a little longer as it will first need to compile, but subsequent loads should be nearly instantaneous. However, if you make changes to any of the Webpacker managed assets, Webpacker should automatically recompile the next time you reload the page.

When you deploy your application, Webpacker will automatically be injected into the assets:precompile step and should build your code using NODE_ENV production.

There’s a lot more we could probably touch on here such as how to take advantage of prefetch and preload links that are automatically injected by VueCLI but will be lost by Rails, how to render an ERB template from Webpack, how to use history mode with Vue-router in conjunctions with Rails’ router, etc, but I’ll save these for future articles.

I welcome feedback, suggestions, or troubleshooting requests and hope you found this article helpful.