DEV Community

Cover image for Goodbye Webpack: The Zen of Rails Importmaps
Zil Norvilis
Zil Norvilis

Posted on

Goodbye Webpack: The Zen of Rails Importmaps

The Javascript Fatigue

We have all been there.
You want to start a new project. You run npm install. You wait. You see 84 vulnerabilities found. You try to configure Webpack, but the config format changed since version 4. You add Babel. You add PostCSS.

Three hours later, you haven't written a single line of business logic. You have just been configuring a build pipeline.

For a team of 20 frontend engineers, these tools are necessary. They need tree-shaking, minification, and code-splitting to shave off kilobytes.

But for the One-Person Team? This is pure friction.

Enter the "No-Build" Era

Browser technology has finally caught up. Modern browsers (Chrome, Firefox, Safari, Edge) now support ES Modules natively. They understand import React from "react" without needing a bundler to stitch it all together first.

Rails 7 (and now 8) embraced this with Importmaps.

The premise is simple: What if you just didn't have a build step?
What if you saved a file, hit refresh, and the browser just loaded it?

How Importmaps Work

Instead of bundling 500 files into one massive application.js blob, Importmaps rely on a simple JSON map inside your HTML <head>.

It looks like this:

<script type="importmap">
{
  "imports": {
    "application": "/assets/application.js",
    "lodash": "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js",
    "stimulus": "https://ga.jspm.io/npm:@hotwired/stimulus@3.2.1/dist/stimulus.js"
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

When you write import _ from "lodash" in your Javascript, the browser looks at the map, sees the URL, and fetches it.

The Benefits for the Solo Dev

1. No node_modules Black Hole

You don't need yarn, npm, or pnpm. You don't have a 500MB folder on your disk. You don't have to wait for CI to "install dependencies" before running tests. Your repository is cleaner and lighter.

2. Instant Feedback Loop

Because there is no "transpiling" or "bundling" process, the moment you save a file, it is ready.

  • Old way: Save -> Wait for Webpack Compiler (2.4s) -> Refresh.
  • New way: Save -> Refresh.

3. CDNs do the Heavy Lifting

Rails uses jspm or jsdelivr to fetch libraries. These CDNs are incredibly fast, optimized, and often cached in the user's browser from other sites.

How to use it in Rails

It is ridiculously easy.

Want to add a library? Say, canvas-confetti?

bin/importmap pin canvas-confetti
Enter fullscreen mode Exit fullscreen mode

That's it. Rails finds the CDN URL, adds it to config/importmap.rb, and you can immediately use it in your controller:

// app/javascript/controllers/confetti_controller.js
import JSConfetti from 'canvas-confetti'

export default class extends Controller {
  connect() {
    const jsConfetti = new JSConfetti()
    jsConfetti.addConfetti()
  }
}
Enter fullscreen mode Exit fullscreen mode

"But what about Performance?"

The critique is that HTTP/2 requests for many small files are slower than one big bundled file.
While technically true for massive applications, for 95% of SaaS apps, it does not matter.

Network speeds are fast. HTTP/2 and HTTP/3 multiplexing allow browsers to download many small files in parallel. The imperceptible performance difference is worth the massive gain in developer happiness and velocity.

When should you NOT use it?

If you are using React (JSX) or Vue (SFC) heavy flows, you still need a build step (to transpile JSX to JS). In that case, use esbuild or vite.

But if you are following the Rails "Omakase" way - using Hotwire, Turbo, and Stimulus - you are writing standard Javascript. You do not need a bundler.

Summary

The future of development is usually about removing layers of abstraction, not adding them.
Importmaps remove the most fragile, frustrating layer of modern web development: the build pipeline.

Stop debugging config files. Start shipping features.


Have you ditched the build step yet? Share your experience below! 👇

Top comments (0)