How to migrate from webpacker to jsbundling-rails (esbuild)
Tags: rails, webpack, esbuild, javascript
Published: 2021-10-16 14:12:40

1. [Install jsbundling-rails](#1-install-jsbundlingrails)
2. [Swap pack_tag for include_tag](#2-swap-packtag-for-includetag)
3. [Import stimulus controllers](#3-import-stimumulus-controllers)
4. [Migrate JS entrypoint](#4-migrate-js-entrypoint)
5. [Remove webpack](#5-remove-webpack)
6. [Github Actions](#6-github-actions)
7. [Heroku](#7-heroku)

---

## 1. Install jsbundling-rails
Add to gemfile:
```rb
gem 'jsbundling-rails'
```

In the terminal, run:
```bash
bundle install
rails javascript:install:esbuild
```

---

## 2. Swap pack_tag for include_tag

The __jsbundling:install__ command inserts a `javascript_include_tag` tag above the </head> tag in your `application.html.erb` file. This tag wil include the new javascript entrypoint `javascript/application.js` for your build script to be included in your application.

Remove webpack's legacy `stylesheet_pack_tag`:

```erb
# old
<%= javascript_pack_tag 'application', 'data-turbo-track': 'reload' %>

# new
<%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
```

If your app render multiple layouts, be sure to remove any `javascript_pack_tag` there too.

---

## 3. Import stimulus controllers

Even when you already installed stimulus, run the install command again in your terminal and overwrite any confliction changes. This will import all your existing stimulus controller correctly.
```bash
rails stimulus:install
```

Now, after adding or removing a new stimulus controller you can use a command which will auto-generate the `controllers/index.js` file.
```bash
rails stimulus:manifest:update
```

---

## 4. Migrate JS entrypoint
Move the content from `javascript/packs/application.js` to
`javascript/application.js`. After migrating the file, delete the javascript/packs folder which was used by Webpacker.

Make sure to import directories in the __javascript__ folder with a relative path.

```javascript
// old
require("channels")

//new
import "./channels"
import "./controllers"
```

---

## 5. Remove webpack
Webpack and its tentacles can finally be removed from the application.

### A. Remove webpacker gem
```rb
gem 'webpacker', '~> 5.4'
```

### B. Remove webpack packages
Webpack packages and plugins that accumulated over time can be removed too. For me, this included:
- @rails/webpacker
- webpack
- webpack-cli
- webpack-cli/serve
- webpack-dev-server
- clean-webpack-plugin
- @hotwired/stimulus-webpack-helpers

### C. Remove webpack files
Finally, remove all config and start-up files:
- bin/webpack
- bin/webpack-dev-server
- config/webpacker.yml
- config/webpack (directory)

---

## 6. Github Actions

If you use Github Actions as a CI/CD make sure to add in an additional build step to run yarn build. Yarn build will trigger the build step defined in your `package.json` file: `"build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds"`. All javascript files need to be bundled before running the tests in your workflow file.

```yml
- name: Build Esbuild
  run: yarn build
```

---

## 7. Heroku

__UPDATE__ this is step is redundant now as mentioned by @jrochkind in the comments. See https://devcenter.heroku.com/changelog-items/2284.

If you use heroku to deploy your application, Heroku will __NOT__ automatically install yarn as it does for Webpack!**

Therefore, we need to explicitly set a node buildpack before ruby. You can do this in the terminal or the Heroku Dashboard.

- Terminal
```bash
heroku buildpacks:clear
heroku buildpacks:set heroku/nodejs
heroku buildpacks:add heroku/ruby
```
- Dashboard
![Heroku Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evxrzrn2dsvf3zy94b4p.png)

---

Resources:
- ** Thanks to [Rob] (https://twitter.com/robzolkos) for blogging about the [yarn missing step](https://world.hey.com/robzolkos/rails-7-fix-yarn-missing-on-heroku-04509d23)
- [How to use ESBuild with JS Bundling in Rails](https://www.youtube.com/watch?v=qOptalp8zUY)