CrackedRuby logo

CrackedRuby

Asset Pipeline

Overview

The Asset Pipeline processes static files through a compilation system that transforms, combines, and optimizes assets for web delivery. Rails implements this through the Sprockets gem, which provides a Rack-based asset server and compilation environment.

The pipeline operates through three primary stages: preprocessing, concatenation, and compression. During preprocessing, assets written in languages like SCSS, CoffeeScript, or ERB get compiled to their web-ready equivalents. Concatenation combines multiple files to reduce HTTP requests. Compression minifies the resulting files to decrease transfer sizes.

Rails organizes assets in specific directory structures. The app/assets directory contains application-specific assets, while lib/assets holds library code and vendor/assets stores third-party assets. The pipeline searches these paths when resolving asset references.

# config/application.rb
config.assets.paths << Rails.root.join('app', 'assets', 'fonts')
config.assets.precompile += %w( admin.css admin.js )

Asset fingerprinting creates unique filenames based on file content, enabling aggressive caching strategies. When file content changes, the filename changes, forcing browsers to fetch the updated version.

# Development: application.css
# Production: application-a1b2c3d4e5f6.css
Rails.application.assets.find_asset('application.css').digest_path

The pipeline integrates with Rails helpers that generate appropriate HTML tags. These helpers automatically include fingerprinted filenames and handle asset path resolution.

# In views
stylesheet_link_tag 'application'
# Generates: <link rel="stylesheet" href="/assets/application-digest.css">

javascript_include_tag 'application'  
# Generates: <script src="/assets/application-digest.js"></script>

Basic Usage

Asset Pipeline configuration occurs primarily in environment files and the application configuration. The pipeline operates differently between development and production environments to optimize the development experience while ensuring production performance.

In development, the pipeline compiles assets on demand. This allows immediate feedback when modifying stylesheets or JavaScript files. The development server intercepts requests for assets and compiles them if they don't exist or have been modified.

# config/environments/development.rb
config.assets.debug = true
config.assets.digest = false
config.assets.raise_runtime_errors = true

Production environments require asset precompilation before deployment. The rails assets:precompile task generates compiled assets with fingerprinted filenames and writes them to the public/assets directory.

# config/environments/production.rb
config.assets.compile = false
config.assets.digest = true
config.assets.compress = true

Manifest files define asset dependencies and compilation targets. The application manifest typically resides in app/assets/stylesheets/application.css and app/assets/javascripts/application.js.

/*
 *= require_tree .
 *= require_self
 */

/* CSS rules follow */
body { margin: 0; }
//= require jquery
//= require jquery_ujs
//= require_tree .

// JavaScript code follows
$(document).ready(function() {
  console.log('Application loaded');
});

The require_tree directive includes all files in the current directory and subdirectories. The require_self directive includes the current file's content. Specific files can be included using require filename without the extension.

Asset helpers provide path resolution and HTML generation. These helpers respect the current environment's configuration and handle fingerprinting automatically.

asset_path('application.css')
# Development: "/assets/application.css"  
# Production: "/assets/application-a1b2c3d4.css"

asset_url('logo.png')
# Returns full URL including protocol and host

Custom preprocessors can be added to handle specialized file types. The pipeline uses file extensions to determine which preprocessors to apply.

# config/application.rb
config.assets.configure do |env|
  env.register_mime_type 'text/custom', extensions: ['.custom']
  env.register_preprocessor 'text/custom', CustomProcessor
end

Environment-specific asset configurations handle different deployment requirements. Test environments often disable compilation for faster test execution, while staging environments may mirror production settings.

Production Patterns

Production deployment requires careful asset pipeline configuration to ensure optimal performance and reliability. The compilation process generates static files that web servers can deliver efficiently without invoking the Rails application.

Precompilation typically occurs during the deployment process, often as part of a build pipeline or deployment script. The compilation process reads source assets, applies transformations, and writes optimized files to the public directory.

# Deployment script
RAILS_ENV=production bundle exec rails assets:precompile
# config/environments/production.rb
config.assets.compile = false
config.assets.digest = true
config.assets.js_compressor = :terser
config.assets.css_compressor = :sass

Web server configuration serves precompiled assets directly, bypassing the Rails application entirely. Nginx and Apache can deliver static files more efficiently than application servers.

# nginx.conf
location ~ ^/(assets|images|javascripts|stylesheets|system)/ {
  expires 1y;
  add_header Cache-Control public;
  add_header ETag "";
  break;
}

CDN integration requires proper asset host configuration. The asset pipeline generates URLs pointing to the CDN rather than the application server.

# config/environments/production.rb
config.action_controller.asset_host = 'https://cdn.example.com'

Error handling during compilation prevents failed deployments. The precompilation task exits with a non-zero status when compilation fails, allowing deployment scripts to detect problems.

# Custom compilation task
namespace :assets do
  task :precompile_with_fallback do
    begin
      Rake::Task['assets:precompile'].invoke
    rescue StandardError => e
      Rails.logger.error "Asset compilation failed: #{e.message}"
      raise
    end
  end
end

Asset versioning strategies handle cache invalidation across deployments. The fingerprinting system automatically handles individual file changes, but application-wide asset changes may require additional cache busting.

# config/application.rb
config.assets.version = ENV['DEPLOYMENT_VERSION'] || '1.0'

Deployment verification ensures assets compiled correctly and are accessible. Health checks can verify critical assets exist and load properly.

# Health check endpoint
def assets_health
  critical_assets = ['application.css', 'application.js']
  missing_assets = critical_assets.reject do |asset|
    Rails.application.assets.find_asset(asset)
  end
  
  if missing_assets.empty?
    render json: { status: 'ok' }
  else
    render json: { status: 'error', missing: missing_assets }, status: 500
  end
end

Zero-downtime deployments require careful coordination between asset compilation and application deployment. Strategies like symlinked releases ensure new assets are available before the application switches to use them.

# Capistrano deployment
before 'deploy:symlink:release', 'deploy:compile_assets'
after 'deploy:publishing', 'deploy:cleanup_assets'

Performance & Memory

Asset Pipeline performance directly impacts application load times and server resource consumption. Optimization strategies focus on reducing compilation time, minimizing asset sizes, and efficient caching.

Compilation performance depends on asset complexity and dependency trees. Complex SCSS files with deep nesting and extensive imports require more processing time. Monitoring compilation duration helps identify bottlenecks.

# Measure compilation time
def time_asset_compilation
  start_time = Time.current
  Rails.application.assets.find_asset('application.css')
  compilation_time = Time.current - start_time
  Rails.logger.info "Asset compilation took #{compilation_time}s"
end

Memory consumption during compilation can become significant with large asset sets. The pipeline loads entire dependency trees into memory, which may exceed available memory on constrained systems.

# Monitor memory usage during compilation
require 'objspace'

ObjectSpace.trace_object_allocations_start
Rails.application.assets.find_asset('application.css')
allocations = ObjectSpace.trace_object_allocations_stop

Rails.logger.info "Objects allocated: #{allocations}"

Caching strategies reduce redundant compilation work. The pipeline maintains internal caches that persist compiled results between requests in development and across compilation runs in production.

# config/environments/development.rb
config.assets.cache_store = :file_store, Rails.root.join('tmp', 'cache', 'assets')

File watching in development environments triggers recompilation when source files change. Efficient file watching reduces CPU overhead while maintaining responsive asset updates.

# config/environments/development.rb
config.assets.logger = Logger.new('/dev/null')  # Reduce log noise
config.file_watcher = ActiveSupport::EventedFileUpdateChecker

Asset size optimization reduces transfer times and bandwidth consumption. The pipeline provides multiple compression strategies for different asset types.

# config/environments/production.rb
config.assets.js_compressor = Terser.new(
  compress: { 
    drop_console: true,
    drop_debugger: true 
  }
)

config.assets.css_compressor = SassC::Compressor.new(
  style: :compressed
)

Selective compilation prevents processing unused assets. The precompile array specifies which assets to compile, avoiding unnecessary work on unused files.

# config/application.rb
config.assets.precompile = %w[
  application.css
  application.js
  admin/application.css
  admin/application.js
]

Parallel compilation can reduce total compilation time on multi-core systems. However, this increases memory usage as multiple compilation processes run simultaneously.

# Custom parallel compilation
require 'parallel'

assets_to_compile = %w[application.css admin.css mobile.css]
Parallel.each(assets_to_compile, in_threads: 4) do |asset_name|
  Rails.application.assets.find_asset(asset_name)
end

Profile-guided optimization identifies expensive operations within the compilation process. Profiling tools can reveal which preprocessors or assets consume the most resources.

# Profile asset compilation
require 'ruby-prof'

RubyProf.start
Rails.application.assets.find_asset('application.css')
result = RubyProf.stop

File.open('compilation_profile.html', 'w') do |file|
  RubyProf::GraphHtmlPrinter.new(result).print(file)
end

Reference

Configuration Options

Option Type Default Description
config.assets.enabled Boolean true Enable/disable asset pipeline
config.assets.paths Array [] Additional asset load paths
config.assets.precompile Array %w[application.css application.js] Assets to precompile
config.assets.prefix String "/assets" URL prefix for assets
config.assets.digest Boolean true in production Enable asset fingerprinting
config.assets.debug Boolean true in development Concatenate assets or serve individually
config.assets.compile Boolean true in development Compile assets on demand
config.assets.compress Boolean true in production Enable asset compression
config.assets.css_compressor Symbol/Object nil CSS compression engine
config.assets.js_compressor Symbol/Object nil JavaScript compression engine
config.assets.gzip Boolean true Generate gzipped versions
config.assets.logger Logger Rails.logger Asset pipeline logger
config.assets.cache_store Symbol/Object Default cache store Asset compilation cache
config.assets.version String "1.0" Asset version for cache busting

Asset Helper Methods

Method Parameters Returns Description
asset_path(source, **options) source (String), options (Hash) String Returns asset path
asset_url(source, **options) source (String), options (Hash) String Returns full asset URL
stylesheet_link_tag(*sources, **options) sources (Array), options (Hash) String Generates CSS link tags
javascript_include_tag(*sources, **options) sources (Array), options (Hash) String Generates JS script tags
image_tag(source, **options) source (String), options (Hash) String Generates image tags
audio_tag(source, **options) source (String), options (Hash) String Generates audio tags
video_tag(source, **options) source (String), options (Hash) String Generates video tags

Manifest Directives

Directive Usage Description
require //= require filename Include specific file
require_directory //= require_directory path Include files in directory (non-recursive)
require_tree //= require_tree path Include files in directory tree (recursive)
require_self //= require_self Include current file content
stub //= stub filename Exclude file from compilation
depend_on //= depend_on filename Mark dependency without inclusion
depend_on_asset //= depend_on_asset filename Mark asset dependency

Compression Engines

Engine Type Configuration
:terser JavaScript config.assets.js_compressor = :terser
:closure JavaScript config.assets.js_compressor = :closure
:yui JavaScript config.assets.js_compressor = :yui
:sass CSS config.assets.css_compressor = :sass
:yui CSS config.assets.css_compressor = :yui

File Extension Processing

Extension Processor Output Format
.scss Sass CSS
.sass Sass CSS
.less Less CSS
.coffee CoffeeScript JavaScript
.ts TypeScript JavaScript
.erb ERB Original format
.slim Slim HTML
.haml Haml HTML

Rake Tasks

Task Description
rails assets:precompile Compile all assets for production
rails assets:clean Remove compiled assets
rails assets:clobber Remove all compiled assets and cache
rails assets:environment Load asset environment

Environment Variables

Variable Description Example
RAILS_ASSETS_CACHE_PATH Asset cache directory /tmp/cache/assets
RAILS_ASSETS_QUIET Suppress asset logs true
SECRET_KEY_BASE Required for asset compilation abc123...

Common MIME Types

Extension MIME Type Processing
.css text/css CSS processing
.js application/javascript JavaScript processing
.png image/png Image optimization
.jpg image/jpeg Image optimization
.gif image/gif Image optimization
.svg image/svg+xml SVG optimization
.woff font/woff Font serving
.ttf font/ttf Font serving