Asset Pipeline JS Migration
Tags: javascript, tutorial, opensource
Published: 2023-02-01 23:23:59

**Forem has created a [milestone](https://github.com/forem/forem/milestone/13) to migrate Javascript initializers in asset pipeline to pack tags and we need YOUR help!**

In an effort to migrate away from asset pipeline and to more modern JS management, there are various initializers that need to be migrated to pack tags via Webpacker and initialized in the perspective view/page. If you’re looking to contribute to open source, these are great issues (tagged with `ready for dev` in the milestone) to work on :smile: This post will help guide you through them.

## A Little Background

Using [Webpacker](https://github.com/rails/webpacker) in Rails provides several advantages over the traditional asset pipeline. First, Webpacker uses JavaScript [modules](https://dev.to/tylermcginnis/javascript-modules-from-iifes-to-commonjs-to-es6-modules-33p1), which allows for better code organization and improved code reusability. Second, it offers modern frontend build tools, such as [Babel](https://dev.to/adityaj/your-only-guide-to-babel-in-2021-1i4e) and [PostCSS](https://dev.to/puritanic/add-postcss-to-create-react-app--5hj8), for transforming and compiling assets. Third, it provides faster build times and faster runtime performance through code splitting and lazy loading. Fourth, it offers better integration with JavaScript frameworks such as React, Vue, and Angular. Overall, Webpacker offers a more flexible and modern asset management solution for Rails applications. And while Webpacker is being retired, this initiative is to consolidate our code accordingly before moving our bundler to another solution.

## High-Level Summary

As Webpacker is already a current dependency in the application, we can begin by migrating an initializer file from `app/assets/javascript` to `app/javascript`. We will then change the references to your JavaScript files in your views and layouts to use pack tags instead of the traditional asset pipeline tags.

These steps are a high-level summary and may require additional steps or modifications based on your specific requirements and initializer purpose. It's always recommended to thoroughly test any changes to the application before submitting a Pull Request. 

See Forem [Dev Docs](https://developers.forem.com/frontend/javascript-approaches/packs) for further Webpacker references

## Step-by-Step with an Example

In setting out to migrate the `initializeCommentDate` function(`app/assets/javascripts/initializers/initializeCommentDate`), we first create the file under ` 
app/javascript/packs/initializers/` and begin moving the code to the newly created file. While some of the code in asset pipeline makes use of CommonJS standards, Javascript under pack tags makes use of ES6 standards. There may be occasions in which those standards would need to be met (i.e. using `let/const` over `var`, etc.). These corrections/updates can be captured and identified through our linting commands.

```
import { addLocalizedDateTimeToElementsTitles } from "../../utilities/localDateTime";

export function initializeCommentDate() {
  const commentsDates = document
                        .querySelectorAll('.comment-date time');

  if (commentsDates) {
    addLocalizedDateTimeToElementsTitles(commentsDates, 'datetime');
  }
}
```

You would also want to migrate any dependencies in which the initializer makes use of. In this case, we migrated `addLocalizedDateTimeToElementsTitles` from `localDateTime` as a utility function as well.

Next, and one of the most important steps, is determining where to place the reference to the pack tag. Most initializers are global initializers (i.e. `initializeBaseTracking`) meaning they are required throughout the application, thus, we place those tags in the `application.html.erb` file as such:
```
<%= javascript_packs_with_chunks_tag "base", 
"baseInitializers", 
"Search", 
"runtimeBanner", 
"onboardingRedirectCheck", 
"contentDisplayPolicy", defer: true %>
```

But there may be initializers that may only get initialized on Article pages, etc. It would be a good idea to determine what view the initializers are initialized for and add the pack tag reference to that specified view. 

A great, simplistic way of testing locally whether your new pack initializer is being triggered is by logging to the console the initial call and any known or derived variables from the code. In my case, I log `commentsDate` and assure the `localDateTime` is added to a title attribute (See `addLocalizedDateTimeToElementsTitles`). Those are good signs that the initializer is being initialized!

Lastly, remove the asset pipeline references to the initializer and delete the file under `app/assets/javascripts/initializers` and that's all there is to this great long-awaited migration!

![alt_text](https://media.giphy.com/media/3hrLxUpp67IpmpZT1h/giphy.gif)

You can find the code for this example [here](https://github.com/forem/forem/pull/19025).

If you have any questions or feedback, please drop them in the comments below. If you’d like to contribute to this great migration please have a look through the ones that aren’t assigned in this [milestone](https://github.com/forem/forem/milestone/13) and raise your hand on the issue. We look forward to your contributions!