Buh-Bye Webpack and Node.js, Hello Rails and Import Maps

John VesterJohn Vester
6 min read

I enjoy spending time learning new technologies. However, often the biggest drawback of working with new technologies are the inevitable pain points that come with early adoption. I saw this quite a bit when I was getting up to speed with Web3 in “Moving From Full-Stack Developer To Web3 Pioneer.”

As software engineers, we’re accustomed to accepting these early-adopter challenges when giving new tech a test drive. What works best for me is to keep a running list of notes and commands I’ve executed, since seemingly illogical steps don’t remain in my memory.

Aside from Web3, I also found this challenge in the JavaScript space, with the semi-standard requirements of using Node.js and Webpack. I wanted to identify a solution where I can just use JavaScript as is, without toiling away with Node.js and Webpack. I recently read how the Rails 7 release addressed this very situation. So, that’s the use case I’ll be covering in this article.

About Rails

To be fully transparent, my experience with Ruby and Ruby on Rails is little to none. I remember watching someone issue some commands to create a fully-functional service years ago, and I thought “Wow, that looks awesome.” But I’ve never spent time playing around with this approach to building services and applications.

I’m pretty sure I saw that demo in early 2006, because Rails first emerged in late 2005. Like I saw in the demonstration, the end result was a service that supported the model-view-controller (MVC) design pattern, a pattern that I was familiar with through my early use of the Spring, Struts, JSF, and Seam frameworks.

Rails maintains a promise to keep things straightforward while adhering to DRY (don’t repeat yourself) practices. To help honor this promise, Ruby uses Gems for engineers to introduce shared dependencies into their projects.

Version 7 Highlights

In late 2021, the seventh major version of Rails introduced some exciting features:

  • Asynchronous querying – getting away from running queries serially

  • Encrypted database layer – securing data between the service and persistence layers

  • Comparison validator – allows object validation before persistence

  • Import maps – no longer require Node.js and Webpack for JavaScript libraries

That last feature is what drove me to write this article.

How Do Import Maps Work?

At a high level, the importmaps-rails Gem allows developers to import maps into their applications. The use of /bin/importmap allows engineers to update, pin, or unpin dependencies as needed. This is similar to how Maven and Gradle work in Java-based projects.

This eliminates needing to deal with the complexities related to bundling packages and transpiling ES6 and Babel. Goodbye Webpack! Goodbye Node.js!

Let’s Build Something

Since I hadn’t even touched Ruby on Rails in almost two decades, the first thing I needed to do was follow this guide to install Ruby 3.3 on my MacBook Pro. Once installed, I just needed to install the Ruby plugin as part of my IntelliJ IDEA IDE.

Then, I created a new Ruby on Rails project in IntelliJ called import-map and specified the use of Importmap for the JavaScript framework:

With the project created, I first wanted to see how easy it would be to use a local JavaScript library. So, I created a new JavaScript file called /public/jvc_utilities.js with the following contents:

export default function() {
    console.log('*****************');
    console.log('* jvc-utilities *');
    console.log('* version 0.0.1 *');
    console.log('*****************');
}

The default function simply echoes some commands to the JavaScript console.

Next, I created an HTML file (/public/jvc-utilities.html) with the following contents:

<!DOCTYPE html>
<html>
    <head>
        <title>jvc-utilities</title>
    </head>

    <script type="importmap">
        { "imports": { "jvc_utilities": "./jvc_utilities.js"} }
    </script>
    <script type="module">
        import JvcUtilities from "jvc_utilities";

        JvcUtilities();
    </script>

    <h3>jvc-utilities.html</h3>

    <p>Open the console to see the output of the 
       <code>JvcUtilities()</code> function.
    </p>
</html>

This example demonstrates how a local JavaScript file can be used with a public HTML file— without any additional work.

Next, I created a new controller called Example:

bin/rails generate controller Example index

I wanted to use the Lodash library for this example, so I used the following command to add the library to my import-map project:

bin/importmap pin lodash

To add some JavaScript-based functionality to the controller, I updated javascript/controllers/example_controller.js to look like this:

import { Controller } from "@hotwired/stimulus"
import _ from "lodash"

export default class extends Controller {
  connect() {
    const array = [1, 2, 3]
    const doubled = _.map(array, n => n * 2)
    console.log('array', array)  // Output: [1, 2, 3]
    console.log('doubled', doubled)  // Output: [2, 4, 6]
    this.element.textContent = `array=${array} doubled=${doubled.join(', ')}`
  }
}

This logic establishes an array of three values, and then it doubles the values. I use the Lodash map() method to do this.

Finally, I updated views/example/index.html.erb to contain the following:

<h3>Example Controller</h3>

<div data-controller="example"></div>

At this point, the following URIs are now available:

  • /jvc-utilities.html

  • /example/index

Let’s Deploy and Validate

Rather than run the Rails service locally, I thought I would use Heroku instead. This way, I could make sure my service could be accessible for other consumers.

Using my Heroku account, I followed the “Getting Started on Heroku with Ruby” guide. Based upon my project, my first step was to add a file named Procfile with the following contents:

web: bundle exec puma -C config/puma.rb

Next, I used the Heroku CLI to create a new application in Heroku:

heroku login
heroku create

With the create command, I had the following application up and running:

Creating app... done, ⬢ lit-basin-84681
https://lit-basin-84681-3f5a7507b174.herokuapp.com/ | https://git.heroku.com/lit-basin-84681.git

This step also created the Git remote that the Heroku ecosystem uses.

Now, all I needed do was push my latest updates to Heroku and deploy the application:

git push heroku main

With that, my code was pushed to Heroku, which then compiled and deployed my application. In less than a minute, I saw the following, letting me know that my application was ready for use:

remote: Verifying deploy... done.
To https://git.heroku.com/lit-basin-84681.git
   fe0b7ad..1a21bdd  main -> main

Then, I navigated to the /example/index page using my Heroku URL (which is unique to my application, but I have since taken it down): https://lit-basin-84681-3f5a7507b174.herokuapp.com/example/index

This is what I saw:

And when I viewed the JavaScript console in my browser, the following logs appeared:

Navigating to /jvc-utilities.html, I saw the following information:

When I viewed the JavaScript console in my browser, I saw the the following logs:

Success. I was able to use a self-contained JavaScript library and also the public Lodash JavaScript library in my Rails 7 application—all by using Import Maps and without needing to deal with Webpack or Node.js. Buh-bye, Webpack and Node.js!

Conclusion

My readers may recall my personal mission statement, which I feel can apply to any IT professional:

“Focus your time on delivering features/functionality that extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”

— J. Vester

In this article, I dove head-first into Rails 7 and used Import Maps to show how easily you can use JavaScript libraries without the extra effort of needing to use Webpack and Node.js. I was quite impressed by the small amount of time that was required to accomplish my goals, despite it being over two decades since I had last seen Rails in action.

From a deployment perspective, the effort to deploy the Rails application onto the Heroku platform consisted of the creation of a Procfile and three CLI commands.

In both cases, Rails and Heroku adhere to my mission statement by allowing me to remain laser-focused on delivering value to my customers and not get bogged down by challenges with Webpack, Node.js, or even DevOps tasks.

While I am certain we will continue to face not-so-ideal pain points when exploring new technologies, I am also confident that in time we will see similar accomplishments like I demonstrated in this article.

As always, my source code can be found on GitLab here.

Have a really great day!

0
Subscribe to my newsletter

Read articles from John Vester directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

John Vester
John Vester

Information Technology professional with 30+ years expertise in application design and architecture, feature development, project management, system administration and team supervision. Currently focusing on enterprise architecture/application design utilizing object-oriented programming languages and frameworks.