$ show opal/opal-rails
opal-rails is a Rails engine that integrates the Opal Ruby-to-JavaScript compiler into the Rails asset pipeline. It provides a build-based workflow where Opal entrypoints (Ruby files) are compiled into JavaScript assets via Rake tasks (`opal:build`, `opal:watch`, `opal:clobber`), replacing the older Sprockets request-time compilation. The gem includes generators for initial setup and asset scaffolding, a template handler for `.js.opal` views with optional controller assigns, and Haml/Slim filters for inline Opal code. It hooks into Rails' `assets:precompile` and test preparation tasks to ensure Opal assets are built automatically. The architecture is centered around a `BuilderRunner` that wraps `Opal::Builder`, an `OutputsManifest` that tracks built files, and a `WatchRunner` that uses the `listen` gem for incremental rebuilds during development. The codebase is well-structured with clear separation of concerns, dependency injection, and comprehensive test coverage, making it a solid example of a Rails engine that extends the asset pipeline.
The LLM identified 5 files worth highlighting for reuse:
Encapsulates the Opal build process: configures Opal compiler options from Rails config, builds each entrypoint using Opal::Builder, appends source map URLs, and writes outputs to the build directory. It snapshots and restores Opal global config to avoid side effects, and returns a dependency map for incremental rebuilds. This component is self-contained (only depends on Opal and FileUtils) and could be reused in any Ruby project that needs to compile Opal files programmatically.
Manages a JSON manifest file (`.opal-build-manifest.json`) that tracks which files in the build directory are owned by Opal. Provides methods to read, write (atomically via Tempfile), prune stale outputs, and clobber all tracked files. Includes path traversal protection by verifying that output paths stay within the build directory. This is a standalone utility that could be extracted for any build system needing to track and clean generated artifacts.
Orchestrates the development watch mode: performs an initial full build, then listens for file changes and rebuilds only affected entrypoints using a reverse dependency map. Handles full rebuilds when Opal core files change or files are added/removed. Uses dependency injection for resolver, builder runner, manifest, and file watcher, making it testable and adaptable. Demonstrates a robust pattern for incremental compilation in a watch loop.
Resolves configured entrypoints into a hash of logical names to relative source files. Supports both explicit hash mappings and `:all` mode (discovers top-level `.rb` files in the entrypoints directory). Validates that the entrypoints path exists and that referenced files are present, raising descriptive errors for missing or duplicate entries. This is a clean, reusable configuration resolver pattern.
Wraps the `listen` gem to watch a set of files and directories, normalizing paths and collapsing parent directories to avoid redundant watches. Accepts a callback that receives lists of modified, added, and removed files. Provides start/stop lifecycle. This is a simple but well-factored abstraction that could be reused in any Ruby project needing file system watching.