실무 프로덕트는 Rails 환경 내에서 webpack 설정을 사용할 수 있게 해주는 Webpacker 라는 빌드 시스템 래퍼를 사용하고 있어요.
하지만 Webpacker는 공식적으로 지원이 중단 되었습니다.
Webpacker has served the Rails community for over five years as a bridge to compiled and bundled JavaScript. This bridge is no longer needed for most people in most situations following the release of Rails 7. We now have three great default answers to JavaScript in 2021+, and thus we will no longer be evolving Webpacker in an official Rails capacity.
https://github.com/rails/webpacker?tab=readme-ov-file#webpacker-has-been-retired-
Rails 7 버전 이후 부터는 Webpacker 없이 최신 자바스크립트를 구현할 수 있게 되었기 때문입니다.
현재 프로덕트는 Rails 5 버전을 사용하고 있고, 프로덕트 전체 버전을 업그레이드 하는 것은 전사적인 동의와 많은 리소스가 필요하기 때문에 다른 대안을 찾아야 합니다.
Rails 자체 기능만으로 구성된 간단한 통합 레이어 입니다. 선택한 번들러로 빌드하여 app/assets/builds/에 출력하고, Sprockets가 이를 제공하는 방식이라고 합니다.
| 항목 | Webpacker | jsbundling-rails |
|---|---|---|
| 번들러 선택 | Webpack만 | Webpack, esbuild, rollup, bun 중 선택 |
| 뷰 헬퍼 | 커스텀 헬퍼 (javascript_pack_tag) | 표준 Rails 헬퍼 (javascript_include_tag) |
| HMR | 지원 | 지원 안 함 |
| Code Splitting | 자동 최적화 | 수동 관리 필요 |
| 설정 파일 | Webpacker 추상화 레이어 | 번들러 표준 설정 직접 사용 |
| Asset Pipeline | 대체 가능 | Sprockets와 함께 작동 |
최신 프론트엔드 빌드 도구 Vite를 Rails에 통합했습니다. 개발 시 네이티브 ESM 활용으로 빠른 HMR을 제공하며, 프로덕션에서는 Rollup 기반 최적화가 되어있습니다.
| 항목 | Webpacker | Vite Ruby |
|---|---|---|
| 개발 서버 속도 | 보통 (Webpack dev server) | 매우 빠름 (ESM 기반) |
| HMR | 지원 | 지원 |
| 빌드 도구 | Webpack | Vite (개발: ESM, 프로덕션: Rollup) |
| 설정 방식 | webpacker.yml + webpack config | config/vite.json + vite.config.ts |
| Auto-build | 없음 | Dev 서버 미실행 시 자동 빌드 |
| Import 문법 | 확장자 생략 가능 | 확장자 필수 (.js, .jsx 명시) |
Vite Ruby로 마이그레이션하는 방안을 골랐습니다.
이유는 아래와 같습니다.
개발 경험 우선: 현재 프로젝트는 React 18 기반의 모던 프론트엔드를 가지고 있습니다. HMR은 React 개발에서 필수적인 기능이며, jsbundling-rails는 이를 제공하지 않습니다.
Webpacker에서 사용 중인 HMR, code splitting 등의 기능을 모두 유지하면서도 더 빠른 경험을 제공합니다.
미래 지향적: Vite는 프론트엔드 생태계의 표준으로 자리잡고 있으며, 지속적인 발전이 기대됩니다.
React 프로젝트에 최적: React Fast Refresh, JSX 지원 등이 내장되어 있어 추가 설정 없이 바로 사용 가능합니다.
jsbundling-rails 에서 HMR을 지원하지 않고, code splitting을 수동으로 설정해야하는 단점과,
Vite Ruby 선택 시얻는 빠른 HMR 로 인한 개발 경험 향상과 Vite의 지속 가능성 등이 다소 번거로운 마이그레이션 과정이 있는 단점을 상쇄한다고 판단하여 Vite Ruby를 선택했습니다.
기존 Webpacker를 유지한 채로 Vite Ruby를 추가합니다.
# Gemfile
gem 'vite_rails'
bundle install
bundle exec vite install
config/vite.json, vite.config.ts, 그리고 app/javascript/entrypoints 디렉토리가 생성됩니다.
Webpacker에서 사용하던 설정을 Vite 형식으로 옮깁니다.
Import Alias 설정
// vite.config.ts
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [RubyPlugin(), react()],
resolve: {
alias: {
'@': '/app/javascript',
'@Atom': '/app/javascript/component/Atom',
'@Molecule': '/app/javascript/component/Molecule',
'@Organism': '/app/javascript/component/Organism',
'@Page': '/app/javascript/component/Page',
},
},
})
Webpacker의 packs 디렉토리에서 Vite의 entrypoints 디렉토리로 파일을 하나씩 옮깁니다.
# Before (Webpacker)
app/javascript/packs/application.js
...
# After (Vite)
app/javascript/entrypoints/application.js
...
테스트를 위해 application 이전에 레거시 부터 옮기도록 합니다.
Vite는 ESM 표준을 따르므로 import 문법 변경이 필요합니다.
파일 확장자 명시
// Before
import Button from '@Atom/Button'
// After
import Button from '@Atom/Button.jsx'
require.context 대체
// Before (Webpack)
const images = require.context('../images', true)
// After (Vite)
const images = import.meta.glob('../images/**/*', { eager: true })
ERB 파일에서 헬퍼 태그를 교체합니다.
<%# Before (Webpacker) %>
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
<%# After (Vite) %>
<%= vite_client_tag %>
<%= vite_javascript_tag 'application' %>
<%= vite_stylesheet_tag 'application' %>
점진적 마이그레이션 중에는 페이지별로 다른 헬퍼를 사용할 수 있습니다. 특정 페이지만 먼저 Vite로 전환하고, 안정성을 확인한 후 나머지를 전환하도록 합니다.
https://vite-ruby.netlify.app/guide/migration.html#webpacker-%F0%9F%93%A6
모든 entrypoint 이전이 완료되면 Webpacker를 제거합니다.
# Gemfile에서 제거
# gem 'webpacker'
# 관련 파일 정리
rm -rf config/webpacker.yml
rm -rf config/webpack/
rm -rf bin/webpack
rm -rf bin/webpack-dev-server
Sentry 등 외부 서비스 연동
Webpack 플러그인을 사용하던 서비스들은 Vite 플러그인으로 교체해야 합니다.
@sentry/webpack-plugin 대신 @sentry/vite-plugin을 사용합니다.
CSS 처리 방식
Vite는 CSS를 자동으로 처리하지만, CSS Modules 파일명 규칙(.module.scss)은 동일하게 유지됩니다.
환경 변수
process.env 대신 import.meta.env를 사용합니다. 클라이언트에 노출할 변수는 VITE_ 접두사가 필요합니다.
// Before
process.env.API_URL
// After
import.meta.env.VITE_API_URL
개발 워크플로우 변화
마이그레이션 후 개발 서버 실행 방식이 달라집니다.
# Before
bin/webpack-dev-server
# After
bin/vite dev
bin/dev를 사용하면 Rails 서버와 Vite 개발 서버를 동시에 실행할 수 있습니다. 첫 실행 시 node_modules 사전 번들링이 진행되며, 이후부터는 수 초 내에 개발 서버가 준비됩니다.
현재 프로덕트에서 Vite ruby 가 필요한 이유를 확인하고, 마이그레이션 전략과 주의할 점에 대해 알아보았습니다.
점진적으로 진행해보고, 추후 결과에 대해 정리하는 시간을 가져보겠습니다.
🔗 참고 문서 및 아티클
Webpacker - https://edgeguides.rubyonrails.org/webpacker.html
Rails 7에서 자바스크립트를 적용하는 방법 - https://world.hey.com/dhh/rails-7-will-have-three-great-answers-to-javascript-in-2021-8d68191b
jsbundling-rails - https://github.com/rails/jsbundling-rails/blob/main/docs/comparison_with_webpacker.md
Vite Ruby - https://vite-ruby.netlify.app/guide/
관련 포스트 - ESM 이해하기
https://velog.io/@dev_choco/ESMECMAScript-Modules-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0