Why we write this guide
There are several reasons:
- The official guide provides very little info.
- We underestimated the effort to do this. This long post explains our similar experience.
- Yet, that long post doesn't give a brief step-by-step guide. So, we decide to fill the gap.
1. Add Webpacker to Gemfile
We recommend you to leave the sprockets gem in your Gemfile if it's still needed. Or, if you plan to move gradually. Don't worry because both of them won't interfere with each other.
In our project, we do use both because we can't migrate all the javascript libs we use for various reasons we can't disclose.
At the last of this step, make sure you've run the bundle install command.
2. Configure the webpacker gem
There are many configurations on the webpacker documentation. Here, we'll focus on these three, to make you easier to start:
- config/webpack/loader/custom_loader.js
- config/webpack/loader/erb.js
- config/webpack/production.js
Let's start with custom_loader.js. In this file, we use json-loader and yaml-loader as an example.
Then, since we also use js.erb files in our old app/assets/javascript folder, we add another loader called rails-erb-loader. We saved it in erb.js like this:
We believe other Rails projects will need this rails-erb-loader too.
The last one is production.js. Well, you can only use production.js or development.js here. Here's why: basically, webpacker is a wrapper for Webpack. Webpack only accepts production or development. Don't expect NODE_ENV to follow rules that RAILS_ENV follows.
Here, the production.js will inherit the configurations defined on config/webpack/environment.js
3. Create a new folder called javascript under app folder
Add a new folder under this app/ folder. Give this new folder name /app/javascript. That's all for this step.
4. Create packs and vendors folder under that app/javascript
Under the new app/javascript folder, add the following folders:
- packs - We use this folder to store application.js and other javascript we've written ourselves.
- vendor - We use this folder to store the third-party javascript like jquery, jquery-UI, and other third-party libraries.
5. Create application.js under app/javascript/packs folder
Add a new application.js and place it inside the app/javascript/packs we've added earlier.
There, we call the rails-ujs and Rails Activestorage.
Why rails-ujs? In our case, and it must be the case for other Rails apps too, Rails will have a CSRF problem without rails-ujs.
It's also important to make sure you include this line in application.js
require("@rails/ujs").start()
Based on our experience, removing that line will cause the CSRF token security problem. On the surface, you may not notice it. But, you'll see it when you open up the browser's javascript console. It will show the error there.
This kind of error is easily overlooked because the tests won't detect this by default. If we're looking at the Rails codes on github, Rails disable CSRF token by default on test mode.
If your Rails project is still using jquery-ujs, you'll need to migrate to rails-ujs first. We'll cover this in another article "How to migrate from jquery-ujs to rails-ujs".
6. Migrate javascript files in app/assets/javascript
Here, you and your team need to decide:
- which javascript files can migrate there
- which ones should stay in the existing app/assets/javascript
It will vary among projects. For simple projects, it's possible to migrate all of them.
We recommend migrating the javascript files you write yourself to packs folder.
Then, migrate the third party javascript files like jquery and others to the vendor folder.
7. Set up the global variables if your app needs it
Unlike sprockets, we need to define the global variables on Webpacker.
Suppose you have two javascript files in the app/javascript/packs folder:
- example1.js
- example2.js
There is a variable called example1 in example1.js.
Then, you need to call it on example2.js. It isn't straightforward. You'll need something like these:
8. Call those migrated files in application.js
Use the "require" syntax for this.
9. Call this new application.js on the application.html.erb
We must use the "javascript_pack_tag" instead of the usual "javascript_include_tag" for this.
10. Make sure everything works correctly
In our projects, we have integration tests with a capybara. Besides them, we also do thorough manual testing after the migration to Webpacker.
Final Notes
- Migration from Sprocket to Webpacker requires quite an effort. Don't underestimate it.
- If you don't have integration tests to make sure the javascript that served UX is working correctly after migration, it's better to build them first. Otherwise, your app will mess up without anyone in the team realize it's happening.
- While it's tempting to migrate all of the javascript to webpacker, in some cases, this may not be possible. For example, one of the javascript libraries you used isn't available in the npm. Even in our case, we still use sprocket along with webpacker.
- Fortunately, we can run both sprocket and webpacker gem in a Rails app, without causing any problem.