Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
More atrubyonrails.org:

The Asset Pipeline

This guide explains how to handle essential asset management tasks.

After reading this guide, you will know:

  • What is an asset pipeline.
  • The main features of Propshaft, and how to set it up.
  • How to migrate from Sprockets to Propshaft.
  • How to use other libraries for more advanced asset management.

1. What is an Asset Pipeline?

The Rails Asset Pipeline is a library designed for organizing, caching, andserving static assets, such as JavaScript, CSS, and image files. It streamlinesand optimizes the management of these assets to enhance the performance andmaintainability of the application.

The Rails Asset Pipeline is managed byPropshaft. Propshaft is built for anera where transpilation, bundling and compression are less critical for basicapplications, thanks to better browser support, faster networks and HTTP/2capabilities.

Propshaft focuses on essential asset management tasks and leaves more complextasks, such as JavaScript and CSS bundling and minification, to specializedtools likejsbundling-rails andcssbundling-rails, which can beadded separately to your application. Propshaft focuses onfingerprinting andemphasizes generating digest-based URLs for assets, allowing browsers to cachethem, thus minimizing the need for intricate compilation and bundling.

ThePropshaft gem is enabled by default innew applications. If, for some reason, you want to disable it during setup, youcan use the--skip-asset-pipeline option:

$railsnew app_name--skip-asset-pipeline

Before Rails 8, the asset pipeline was powered bySprockets. You can read about theSprockets AssetPipeline in previousversions of the Rails Guides. You can also explore theevolution of assetmanagement techniques to see how theRails Asset Pipeline has evolved over time.

2. Propshaft Features

Propshaft expects that your assets are already in a browser-ready format—likeplain CSS, JavaScript, or preprocessed images (like JPEGs or PNGs). Its job isto organize, version, and serve those assets efficiently. In this section, we’llcover the main features of Propshaft and how they work.

2.1. Asset Load Order

With Propshaft, you can control the loading order of dependent files byspecifying each file explicitly and organizing them manually or ensuring theyare included in the correct sequence within your HTML or layout files. Thisensures that dependencies are managed and loaded without relying on automateddependency management tools. Below are some strategies for managingdependencies:

  1. Manually include assets in the correct order:

    In your HTML layout (usuallyapplication.html.erb for Rails apps) you canspecify the exact order for loading CSS and JavaScript files by includingeach file individually in a specific order. For example:

    <!-- application.html.erb --><head><%=stylesheet_link_tag"reset"%><%=stylesheet_link_tag"base"%><%=stylesheet_link_tag"main"%></head><body><%=javascript_include_tag"utilities"%><%=javascript_include_tag"main"%></body>

    This is important if, for instance,main.js relies onutilities.js to beloaded first.

  2. Use Modules in JavaScript (ES6)

    If you have dependencies within JavaScript files, ES6 modules can help. Byusing import statements, you can explicitly control dependencies withinJavaScript code. Just make sure your JavaScript files are set up as modulesusing<script type="module"> in your HTML:

    // main.jsimport { initUtilities } from "./utilities.js";import { setupFeature } from "./feature.js";initUtilities();setupFeature();

    Then in your layout:

    <script type="module" src="main.js"></script>

    This way, you can manage dependencies within JavaScript files withoutrelying on Propshaft to understand them. By importing modules, you cancontrol the order in which files are loaded and ensure dependencies are met.

  3. Combine Files when necessary

    If you have several JavaScript or CSS files that must always load together,you can combine them into a single file. For example, you could create acombined.js file that imports or copies code from other scripts. Then,just includecombined.js in your layout to avoid dealing with individualfile ordering. This can be useful for files that always load together, likea set of utility functions or a group of styles for a specific component.While this approach can work for small projects or simple use cases, it canbecome tedious and error-prone for larger applications.

  4. Bundle your JavaScript or CSS using a bundler

    If your project requires features like dependency chaining or CSSpre-processing, you may want to consideradvanced assetmanagement alongside Propshaft.

    Tools likejsbundling-railsintegratesBun,esbuild,rollup.js, orWebpackinto your Rails application, whilecssbundling-rails can beused to process stylesheets that useTailwindCSS,Bootstrap,Bulma,PostCSS, orDartSass.

    These tools complement Propshaft by handling the complex processing, whilePropshaft efficiently organizes and serves the final assets.

2.2. Asset Organization

Propshaft organizes assets within theapp/assets directory, which includessubdirectories likeimages,javascripts, andstylesheets. You can placeyour JavaScript, CSS, image files, and other assets into these directories, andPropshaft will manage them during the precompilation process.

You can also specify additional asset paths for Propshaft to search by modifyingconfig.assets.paths in yourconfig/initializers/assets.rb file. For example:

# Add additional assets to the asset load path.Rails.application.config.assets.paths<<Emoji.images_path

Propshaft will make all assets from the configured paths available for serving.During the precompilation process, Propshaft copies these assets into thepublic/assets directory, ensuring they are ready for production use.

Assets can bereferenced through their logicalpaths using helpers likeasset_path,image_tag,javascript_include_tag, and other asset helper tags. After runningassets:precompile in production, these logical references areautomatically converted into their fingerprinted paths using the.manifest.json file.

It is possible to exclude certain directories from this process, you can read moreabout it in theFingerprintingsection.

2.3. Fingerprinting: Versioning with digest-based URLs

In Rails, asset versioning uses fingerprinting to add unique identifiers toasset filenames.

Fingerprinting is a technique that makes the name of a file dependent on itscontent. A digest of the file's content is generated and appended to thefilename. This ensures that when the file content changes, its digest—andconsequently its filename—also changes. This mechanism is crucial for cachingassets effectively, as the browser will always load the updated version of anasset when its content changes, thereby improving performance. For static orinfrequently changed content, this provides an easy way to tell whether twoversions of a file are identical, even across different servers or deploymentdates.

2.3.1. Asset Digesting

As mentioned in theAsset Organization section, inPropshaft, all assets from the paths configured inconfig.assets.paths areavailable for serving and will be copied into thepublic/assets directory.

When fingerprinted, an asset filename likestyles.css is renamed tostyles-a1b2c3d4e5f6.css. This ensures that ifstyles.css is updated, thefilename changes as well, compelling the browser to download the latest versioninstead of using a potentially outdated cached copy.

2.3.2. Manifest Files

In Propshaft, the.manifest.json file is automatically generated during theasset precompilation process. This file maps original asset filenames to theirfingerprinted versions, ensuring proper cache invalidation and efficient assetmanagement. Located in thepublic/assets directory, the.manifest.json filehelps Rails resolve asset paths at runtime, allowing it to reference the correctfingerprinted files.

The.manifest.json includes entries for main assets likeapplication.js andapplication.css as well as other files, such as images. Here's an example ofwhat the JSON might look like:

{"application.css":"application-6d58c9e6e3b5d4a7c9a8e3.css","application.js":"application-2d4b9f6c5a7c8e2b8d9e6.js","logo.png":"logo-f3e8c9b2a6e5d4c8.png","favicon.ico":"favicon-d6c8e5a9f3b2c7.ico"}

When a filename is unique and based on its content, HTTP headers can be set toencourage caches everywhere (whether at CDNs, at ISPs, in networking equipment,or in web browsers) to keep their own copy of the content. When the content isupdated, the fingerprint will change. This will cause the remote clients torequest a new copy of the content. This is generally known as cache busting.

2.3.3. Digested Assets in Views

You can reference digested assets in your views using standard Rails assethelpers likeasset_path,image_tag,javascript_include_tag,stylesheet_link_tag and others.

For example, in your layout file, you can include a stylesheet like this:

<%=stylesheet_link_tag"application",media:"all"%>

If you're using theturbo-rails gem(which is included by default in Rails), you can include thedata-turbo-trackoption. This causes Turbo to check if an asset has been updated and, if so,reload it into the page:

<%=stylesheet_link_tag"application","data-turbo-track":"reload"%>

You can access images in theapp/assets/images directory like this:

<%=image_tag"rails.png"%>

When the asset pipeline is enabled, Propshaft will serve this file. If a fileexists atpublic/assets/rails.png, it will be served by the web server.

Alternatively, if you are using fingerprinted assets (e.g.,rails-f90d8a84c707a8dc923fca1ca1895ae8ed0a09237f6992015fef1e11be77c023.png),Propshaft will also serve these correctly. The fingerprint is automaticallyapplied during the precompilation process.

Images can be organized into subdirectories, and you can reference them byspecifying the directory in the tag:

<%=image_tag"icons/rails.png"%>

Finally, you can reference an image in your CSS like:

background:url("/bg/pattern.svg");

Propshaft will automatically convert this to:

background:url("/assets/bg/pattern-2169cbef.svg");

If you're precompiling your assets (seethe Productionsection), linking to an asset that doesn't exist will raise anexception in the calling page. This includes linking to a blank string. Becareful when usingimage_tag and other helpers with user-supplied data. Thisensures that the browser always fetches the correct version of the asset.

2.3.4. Digested Assets in JavaScript

In JavaScript, you need to manually trigger the asset transformation using theRAILS_ASSET_URL macro. Here’s an example:

exportdefaultclassextendsController{init(){this.img=RAILS_ASSET_URL("/icons/trash.svg");}}

This will transform into:

exportdefaultclassextendsController{init(){this.img="/assets/icons/trash-54g9cbef.svg";}}

This ensures that the correct, digested file is used in your JavaScript code.

If you’re using bundlers likeWebpack oresbuild, you should let the bundlers handle thedigesting process. If Propshaft detects that a file already has a digest in thefilename (e.g.,script-2169cbef.js), it will skip digesting the file again toavoid unnecessary reprocessing.

For managing assets withImport Maps, Propshaft ensures thatassets referenced in the import map are appropriately handled and mapped totheir digested paths during the precompilation process.

2.3.5. Bypassing the Digest Step

If you need to reference files that refer to each other—like a JavaScript fileand its source map—and want to avoid the digesting process, you can pre-digestthese files manually. Propshaft recognizes files with the pattern-[digest].digested.js as files that have already been digested and willpreserve their stable file names.

2.3.6. Excluding Directories from Digestion

You can exclude certain directories from the precompilation and digestionprocess by adding them toconfig.assets.excluded_paths. This is useful if, forexample, you’re usingapp/assets/stylesheets as input to a compiler likeDartSass, and you don’t want these files to be part of theasset load path.

config.assets.excluded_paths=[Rails.root.join("app/assets/stylesheets")]

This will prevent the specified directories from being processed by Propshaftwhile still allowing them to be part of the precompilation process.

3. Working with Propshaft

From Rails 8 onwards, Propshaft is included by default. To use Propshaft, youneed to configure it properly and organize your assets in a way that Rails canserve them efficiently.

3.1. Setup

Follow these steps for setting up Propshaft in your Rails application:

  1. Create a new Rails application:

    $railsnew app_name
  2. Organize your assets:

    Propshaft expects your assets to be in theapp/assets directory. You canorganize your assets into subdirectories likeapp/assets/javascripts forJavaScript files,app/assets/stylesheets for CSS files, andapp/assets/images for images.

    For example, you can create a new JavaScript file inapp/assets/javascripts:

    // app/assets/javascripts/main.jsconsole.log("Hello, world!");

    and a new CSS file inapp/assets/stylesheets:

    /* app/assets/stylesheets/main.css */body{background-color:red;}
  3. Link assets in your application layout

    In your application layout file (usuallyapp/views/layouts/application.html.erb), you can include your assets usingthestylesheet_link_tag andjavascript_include_tag helpers:

    <!-- app/views/layouts/application.html.erb --><!DOCTYPE html><html><head><title>MyApp</title><%=stylesheet_link_tag"main"%></head><body><%=yield%><%=javascript_include_tag"main"%></body></html>

    This layout includes themain.css stylesheet andmain.js JavaScript filein your application.

  4. Start the Rails server:

    $bin/railsserver
  5. Preview your application:

    Open your web browser and navigate tohttp://localhost:3000. You shouldsee your Rails application with the included assets.

3.2. Development

Rails and Propshaft are configured differently in development than inproduction, to allow rapid iteration without manual intervention.

3.2.1. No Caching

In development, Rails is configured to bypass asset caching. This means thatwhen you modify assets (e.g., CSS, JavaScript), Rails will serve the mostup-to-date version directly from the file system. There's no need to worry aboutversioning or file renaming because caching is skipped entirely. Browsers willautomatically pull in the latest version each time you reload the page.

3.2.2. Automatic Reloading of Assets

When using Propshaft on its own, it automatically checks for updates to assetslike JavaScript, CSS, or images with every request. This means you can editthese files, reload the browser, and instantly see the changes without needingto restart the Rails server.

When using JavaScript bundlers such asesbuild orWebpack alongside Propshaft, the workflow combinesboth tools effectively:

  • The bundler watches for changes in your JavaScript and CSS files, compilesthem into the appropriate build directory, and keeps the files up to date.
  • Propshaft ensures that the latest compiled assets are served to the browserwhenever a request is made.

For these setups, running./bin/dev starts both the Rails server and the assetbundler's development server.

In either case, Propshaft ensures that changes to your assets are reflected assoon as the browser page is reloaded, without requiring a server restart.

3.2.3. Improving Performance with File Watchers

In development, Propshaft checks if any assets have been updated before eachrequest, using the application's file watcher (by default,ActiveSupport::FileUpdateChecker). If you have a large number of assets, youcan improve performance by using thelisten gem and configuring the followingsetting inconfig/environments/development.rb:

config.file_watcher=ActiveSupport::EventedFileUpdateChecker

This will reduce the overhead of checking for file updates and improveperformance during development.

3.3. Production

In production, Rails serves assets with caching enabled to optimize performance,ensuring that your application can handle high traffic efficiently.

3.3.1. Asset Caching and Versioning in Production

As mentioned in theFingerprintingsection when the filecontent changes, its digest also changes, thus the browser uses the updatedversion of the file. Whereas, if the content remains the same, the browser willuse the cached version.

3.3.2. Precompiling Assets

In production, precompilation is typically run during deployment to ensure thatthe latest versions of the assets are served. Propshaft was explicitly notdesigned to provide full transpiler capabilities. However, it does offer aninput -> output compiler setup that by default is used to translateurl(asset)function calls in CSS tourl(digested-asset) instead and source mappingcomments likewise.

To manually run precompilation you can use the following command:

$RAILS_ENV=productionrailsassets:precompile

After doing this, all assets in the load path will be copied (or compiled whenusingadvanced asset management) in theprecompilation step and stamped with a digest hash.

Additionally, you can setENV["SECRET_KEY_BASE_DUMMY"] to trigger the use of arandomly generatedsecret_key_base that’s stored in a temporary file. This isuseful when precompiling assets for production as part of a build step thatotherwise does not need access to the production secrets.

$RAILS_ENV=productionSECRET_KEY_BASE_DUMMY=1railsassets:precompile

By default, assets are served from the/assets directory.

Running the precompile command in development generates a marker filenamed.manifest.json, which tells the application that it can serve thecompiled assets. As a result, any changes you make to your source assets won'tbe reflected in the browser until the precompiled assets are updated. If yourassets stop updating in development mode, the solution is to remove the.manifest.json file located inpublic/assets/. You can use therailsassets:clobber command to delete all your precompiled assets and the.manifest.json file. This will force Rails to recompile the assets on the fly,reflecting the latest changes.

Always ensure that the expected compiled filenames end with.js or.css.

3.3.2.1. Far-future Expires Header

Precompiled assets exist on the file system and are served directly by your webserver. They do not have far-future headers by default, so to get the benefit offingerprinting you'll have to update your server configuration to add thoseheaders.

For Apache:

# The Expires* directives require the Apache module# `mod_expires` to be enabled.<Location /assets/># Use of ETag is discouraged when Last-Modified is presentHeaderunset ETagFileETagNone# RFC says only cache for 1 yearExpiresActiveOnExpiresDefault "access plus 1 year"</Location>

For NGINX:

location~^/assets/{expires1y;add_headerCache-Controlpublic;add_headerETag"";}

3.3.3. CDNs

CDN stands forContent DeliveryNetwork, they areprimarily designed to cache assets all over the world so that when a browserrequests the asset, a cached copy will be geographically close to that browser.If you are serving assets directly from your Rails server in production, thebest practice is to use a CDN in front of your application.

A common pattern for using a CDN is to set your production application as the"origin" server. This means when a browser requests an asset from the CDN andthere is a cache miss, it will instead source the file from your server and thencache it. For example if you are running a Rails application onexample.comand have a CDN configured atmycdnsubdomain.fictional-cdn.com, then when arequest is made tomycdnsubdomain.fictional-cdn.com/assets/smile.png, the CDNwill query your server once atexample.com/assets/smile.png and cache therequest. The next request to the CDN that comes in to the same URL will hit thecached copy. When the CDN can serve an asset directly the request never touchesyour Rails server. Since the assets from a CDN are geographically closer to thebrowser, the request is faster, and since your server doesn't need to spend timeserving assets, it can focus on serving application code.

3.3.3.1. Set up a CDN to Serve Static Assets

To set up CDN, your application needs to be running in production on theinternet at a publicly available URL, for exampleexample.com. Next you'llneed to sign up for a CDN service from a cloud hosting provider. When you dothis you need to configure the "origin" of the CDN to point back at your websiteexample.com. Check your provider for documentation on configuring the originserver.

The CDN you provisioned should give you a custom subdomain for your applicationsuch asmycdnsubdomain.fictional-cdn.com (note fictional-cdn.com is not avalid CDN provider at the time of this writing). Now that you have configuredyour CDN server, you need to tell browsers to use your CDN to grab assetsinstead of your Rails server directly. You can do this by configuring Rails toset your CDN as the asset host instead of using a relative path. To set yourasset host in Rails, you need to setconfig.asset_host inconfig/environments/production.rb:

config.asset_host="mycdnsubdomain.fictional-cdn.com"

You only need to provide the "host", this is the subdomain and rootdomain, you do not need to specify a protocol or "scheme" such ashttp:// orhttps://. When a web page is requested, the protocol in the link to your assetthat is generated will match how the webpage is accessed by default.

You can also set this value through anenvironmentvariable to make running astaging copy of your site easier:

config.asset_host=ENV["CDN_HOST"]

You would need to setCDN_HOST on your server tomycdnsubdomain.fictional-cdn.com for this to work.

Once you have configured your server and your CDN, asset paths from helpers suchas:

<%=asset_path('smile.png')%>

Will be rendered as full CDN URLs likehttp://mycdnsubdomain.fictional-cdn.com/assets/smile.png (digest omitted forreadability).

If the CDN has a copy ofsmile.png, it will serve it to the browser, and theorigin server won't even know it was requested. If the CDN does not have a copy,it will try to find it at the "origin"example.com/assets/smile.png, and thenstore it for future use.

If you want to serve only some assets from your CDN, you can use custom:hostoption for your asset helper, which overwrites the value set inconfig.action_controller.asset_host.

<%=asset_path'image.png',host:'mycdnsubdomain.fictional-cdn.com'%>
3.3.3.2. Customize CDN Caching Behavior

A CDN works by caching content. If the CDN has stale or bad content, then it ishurting rather than helping your application. The purpose of this section is todescribe general caching behavior of most CDNs. Your specific provider maybehave slightly differently.

CDN Request Caching

While a CDN is described as being good for caching assets, it actually cachesthe entire request. This includes the body of the asset as well as any headers.The most important one beingCache-Control, which tells the CDN (and webbrowsers) how to cache contents. This means that if someone requests an assetthat does not exist, such as/assets/i-dont-exist.png, and your Railsapplication returns a 404, then your CDN will likely cache the 404 page if avalidCache-Control header is present.

CDN Header Debugging

One way to check the headers are cached properly in your CDN is by usingcurl. Youcan request the headers from both your server and your CDN to verify they arethe same:

$curl-I http://www.example/assets/application-d0e099e021c95eb0de3615fd1d8c4d83.cssHTTP/1.1 200 OKServer: CowboyDate: Sun, 24 Aug 2014 20:27:50 GMTConnection: keep-aliveLast-Modified: Thu, 08 May 2014 01:24:14 GMTContent-Type: text/cssCache-Control: public, max-age=2592000Content-Length: 126560Via: 1.1 vegur

Versus the CDN copy:

$curl-I http://mycdnsubdomain.fictional-cdn.com/application-d0e099e021c95eb0de3615fd1d8c4d83.cssHTTP/1.1 200 OK Server: Cowboy Last-Modified: Thu, 08 May 2014 01:24:14 GMT Content-Type: text/cssCache-Control:public, max-age=2592000Via: 1.1 vegurContent-Length: 126560Accept-Ranges:bytesDate: Sun, 24 Aug 2014 20:28:45 GMTVia: 1.1 varnishAge: 885814Connection: keep-aliveX-Served-By: cache-dfw1828-DFWX-Cache: HITX-Cache-Hits:68X-Timer: S1408912125.211638212,VS0,VE0

Check your CDN documentation for any additional information they may providesuch asX-Cache or for any additional headers they may add.

CDNs and the Cache-Control Header

TheCache-Control header describes how a request can be cached. When noCDN is used, a browser will use this information to cache contents. This is veryhelpful for assets that are not modified so that a browser does not need tore-download a website's CSS or JavaScript on every request. Generally we wantour Rails server to tell our CDN (and browser) that the asset is "public". Thatmeans any cache can store the request. Also we commonly want to setmax-agewhich is how long the cache will store the object before invalidating the cache.Themax-age value is set to seconds with a maximum possible value of31536000, which is one year. You can do this in your Rails application bysetting

config.public_file_server.headers={"Cache-Control"=>"public, max-age=31536000"}

Now when your application serves an asset in production, the CDN will store theasset for up to a year. Since most CDNs also cache headers of the request, thisCache-Control will be passed along to all future browsers seeking this asset.The browser then knows that it can store this asset for a very long time beforeneeding to re-request it.

CDNs and URL-based Cache Invalidation

Most CDNs will cache contents of an asset based on the complete URL. This meansthat a request to

http://mycdnsubdomain.fictional-cdn.com/assets/smile-123.png

Will be a completely different cache from

http://mycdnsubdomain.fictional-cdn.com/assets/smile.png

If you want to set far futuremax-age in yourCache-Control (and you do),then make sure when you change your assets that your cache is invalidated. Forexample when changing the smiley face in an image from yellow to blue, you wantall visitors of your site to get the new blue face. When using a CDN with theRails asset pipelineconfig.assets.digest is set to true by default so thateach asset will have a different file name when it is changed. This way youdon't have to ever manually invalidate any items in your cache. By using adifferent unique asset name instead, your users get the latest asset.

4. Sprockets to Propshaft

4.1. Evolution of Asset Management Techniques

Within the last few years, the evolution of the web has led to significantchanges that have influenced how assets are managed in web applications. Theseinclude:

  1. Browser Support: Modern browsers have improved support for new featuresand syntax, reducing the need for transpilation and polyfills.
  2. HTTP/2: The introduction of HTTP/2 has made it easier to serve multiplefiles in parallel, reducing the need for bundling.
  3. ES6+: Modern JavaScript syntax (ES6+) is supported by most modernbrowsers, reducing the need for transpilation.

Therefore, the asset pipeline powered by Propshaft, no longer includestranspilation, bundling, or compression by default. However, fingerprintingstill remains an integral part. You can read more about the evolution of assetmanagement techniques and how they directed the change from Sprockets toPropshaft below.

4.1.1. Transpilation ❌

Transpilation involves converting code from one language or format to another.

For example, converting TypeScript to JavaScript.

constgreet=(name:string):void=>{console.log(`Hello,${name}!`);};

After transpilation, this code becomes:

constgreet=(name)=>{console.log(`Hello,${name}!`);};

In the past, pre-processors likeSass andLess were essential for CSS features such as variablesand nesting. Today, modern CSS supports these natively, reducing the need fortranspilation.

4.1.2. Bundling ❌

Bundling combines multiple files into one to reduce the number of HTTP requestsa browser needs to make to render a page.

For example, if your application has three JavaScript files:

  • menu.js
  • cart.js
  • checkout.js

Bundling will merge these into a single application.js file.

// app/javascript/application.js// Contents of menu.js, cart.js, and checkout.js are combined here

This was crucial with HTTP/1.1, which limited 6-8 simultaneous connections perdomain. With HTTP/2, browsers fetch multiple files in parallel, making bundlingless critical for modern applications.

4.1.3. Compression ❌

Compression encodes files in a more efficient format to reduce their sizefurther when delivered to users. A common technique isGzipcompression.

For example, a CSS file that's 200KB may compress to just 50KB when Gzipped.Browsers automatically decompress such files upon receipt, saving bandwidth andimproving speed.

However, with CDNs automatically compressing assets, the need for manualcompression has decreased.

4.2. Sprockets vs. Propshaft

4.2.1. Load Order

In Sprockets, you could link files together to ensure they loaded in the correctorder. For example, a main JavaScript file that depended on other files wouldautomatically have its dependencies managed by Sprockets, ensuring everythingloaded in the right sequence. Propshaft, on the other hand, does notautomatically handle these dependencies, and insteadlets you manage the assetload order manually.

4.2.2. Versioning

Sprockets simplifies asset fingerprinting by appending a hash to filenameswhenever assets are updated, ensuring proper cache invalidation. With Propshaft,you’ll need to handle certain aspects manually. For example, while assetfingerprinting works, you might need to use a bundler or trigger transformationsmanually for JavaScript files to ensure filenames are updated correctly. Readmore aboutfingerprinting inPropshaft.

4.2.3. Precompilation

Sprockets processed assets that were explicitly included in a bundle. Incontrast, Propshaft automatically processes all assets located in the specifiedpaths, including images, stylesheets, JavaScript files, and more, withoutrequiring explicit bundling. Read more aboutassetdigesting.

4.3. Migration Steps

Propshaft is intentionally simpler thanSprockets, which may make migratingfrom Sprockets a fair amount of work. This is especially true if you rely onSprockets for tasks like transpilingTypeScript orSass,or if you're using gems that provide this functionality. In such cases, you'lleither need to stop transpiling or switch to a Node.js-based transpiler, such asthose provided byjsbundling-rails orcssbundling-rails. Read moreabout these in theAdvanced Asset Managementsection.

However, if you're already using a Node-based setup to bundle JavaScript andCSS, Propshaft should integrate smoothly into your workflow. Since you won’tneed an additional tool for bundling or transpiling, Propshaft will primarilyhandle asset digesting and serving.

Some key steps in the migration include:

  1. Remove some gems using the following:

    bundle remove sprocketsbundle remove sprockets-railsbundle remove sass-rails
  2. Delete theconfig/assets.rb andassets/config/manifest.js files from yourproject.

  3. If you've already upgraded to Rails 8, then Propshaft is already included inyour application. Otherwise, install it usingbundle add propshaft.

  4. Remove theconfig.assets.paths << Rails.root.join('app', 'assets') linefrom yourapplication.rb file.

  5. Migrate asset helpers by replacing all instances of asset helpers in your CSSfiles (e.g.,image_url) with standardurl() functions, keeping in mindthat Propshaft utilizes relative paths.For example,image_url("logo.png") may becomeurl("/logo.png").

  6. If you're relying on Sprockets for transpiling, you'll need to switch to aNode-based transpiler like Webpack, esbuild, or Vite. You can use thejsbundling-rails andcssbundling-rails gems to integrate these tools intoyour Rails application.

For more information, you can read thedetailed guide on how to migrate fromSprockets toPropshaft.

5. Advanced Asset Management

Over the years, there have been multiple default approaches for handling assets,and as the web evolved, we began to see more JavaScript-heavy applications. InThe Rails Doctrine we believe thatThe Menu IsOmakase, so Propshaft focuses ondelivering a production-ready setup with modern browsers by default.

There is no one-size-fits-all solution for the various JavaScript and CSSframeworks and extensions available. However, there are other bundling librariesin the Rails ecosystem that should empower you in cases where the default setupisn't enough.

5.1.jsbundling-rails

jsbundling-rails is a gem thatintegrates modern JavaScript bundlers into your Rails application. It allows youto manage and bundle JavaScript assets with tools likeBun,esbuild,rollup.js, orWebpack, offering a runtime-dependent approach fordevelopers seeking flexibility and performance.

5.1.1. Howjsbundling-rails Works

  1. After installation, it sets up your Rails app to use your chosen JavaScriptbundler.
  2. It creates abuild script in yourpackage.json file to compile yourJavaScript assets.
  3. During development, thebuild:watch script ensures live updates to yourassets as you make changes.
  4. In production, the gem ensures that JavaScript is built and included duringthe precompilation step, reducing manual intervention. It hooks into Rails'assets:precompile task to build JavaScript for all entry points duringdeployment. This integration ensures that your JavaScript is production-readywith minimal configuration.

The gem automatically handles entry-point discovery - identifying the primaryJavaScript files to bundle by following Rails conventions, typically looking indirectories likeapp/javascript/ and configuration. By adhering to Railsconventions,jsbundling-rails simplifies the process of integrating complexJavaScript workflows into Rails projects.

5.1.2. When Should You Use It?

jsbundling-rails is ideal for Rails applications that:

  • Require modern JavaScript features like ES6+, TypeScript, or JSX.
  • Need to leverage bundler-specific optimizations like tree-shaking, codesplitting, or minification.
  • UsePropshaft for asset management and need a reliable way to integrateprecompiled JavaScript with the broader Rails asset pipeline.
  • Utilize libraries or frameworks that depend on a build step. For example,projects requiring transpilation—such as those usingBabel,TypeScript,or React JSX—benefit greatly fromjsbundling-rails. These tools rely on abuild step, which the gem seamlessly supports.

By integrating with Rails tools likePropshaft and simplifying JavaScriptworkflows,jsbundling-rails allows you to build rich, dynamic front-ends whilestaying productive and adhering to Rails conventions.

5.2.cssbundling-rails

cssbundling-rails integratesmodern CSS frameworks and tools into your Rails application. It allows you tobundle and process your stylesheets. Once processed, the resulting CSS isdelivered via the Rails asset pipeline.

5.2.1. Howcssbundling-rails Works

  1. After installation, it sets up your Rails app to use your chosen CSSframework or processor.
  2. It creates abuild:css script in yourpackage.json file to compile yourstylesheets.
  3. During development, abuild:css --watch task ensures live updates to yourCSS as you make changes, providing a smooth and responsive workflow.
  4. In production, the gem ensures your stylesheets are compiled and ready fordeployment. During theassets:precompile step, it installs allpackage.json dependencies viabun,yarn,pnpm ornpm and runs thebuild:css task to process your stylesheet entry points. The resulting CSSoutput is then digested by the asset pipeline and copied into thepublic/assets directory, just like other asset pipeline files.

This integration simplifies the process of preparing production-ready styleswhile ensuring all your CSS is managed and processed efficiently.

5.2.2. When Should You Use It?

cssbundling-rails is ideal for Rails applications that:

  • Use CSS frameworks likeTailwind CSS,Bootstrap, orBulma thatrequire processing during development or deployment.
  • Need advanced CSS capabilities such as custom preprocessing withPostCSS orDart Sassplugins.
  • Require seamless integration of processed CSS into the Rails asset pipeline.
  • Benefit from live updates to stylesheets during development with minimalmanual intervention.

NOTE: Unlikedartsass-rails ortailwindcss-rails, which usestandalone versions ofDart Sass andTailwindCSS,cssbundling-rails introduces a Node.jsdependency. This makes it a good choice for applications already relying on Nodefor JavaScript processing with gems likejsbundling-rails. However, if you'reusingimportmap-rails forJavaScript and prefer to avoid Node.js, standalone alternatives likedartsass-rails ortailwindcss-rails offer asimpler setup.

By integrating modern CSS workflows, automating production builds, andleveraging the Rails asset pipeline,cssbundling-rails enables developers toefficiently manage and deliver dynamic styles.

5.3.tailwindcss-rails

tailwindcss-rails is a wrappergem that integratesTailwind CSS into your Railsapplication. By bundling Tailwind CSS with astandaloneexecutable, it eliminates the needfor Node.js or additional JavaScript dependencies. This makes it a lightweightand efficient solution for styling Rails applications.

5.3.1. Howtailwindcss-rails Works

  1. When installed, by providing--css tailwind to therails new command, thegem generates atailwind.config.js file for customizing your Tailwind setupand astylesheets/application.tailwind.css file for managing your CSS entrypoints.
  2. Instead of relying on Node.js, the gem uses a precompiled Tailwind CSSbinary. This standalone approach allows you to process and compile CSSwithout adding a JavaScript runtime to your project.
  3. During development, changes to your Tailwind configuration or CSS files areautomatically detected and processed. The gem rebuilds your stylesheets andprovides awatch process to automatically generate Tailwind output indevelopment.
  4. In production, the gem hooks into theassets:precompile task. It processesyour Tailwind CSS files and generates optimized, production-readystylesheets, which are then included in the asset pipeline. The output isfingerprinted and cached for efficient delivery.

5.3.2. When Should You Use It?

tailwindcss-rails is ideal for Rails applications that:

  • Want to useTailwind CSS without introducing aNode.js dependency or JavaScript build tools.
  • Require a minimal setup for managing utility-first CSS frameworks.
  • Need to take advantage of Tailwind's powerful features like custom themes,variants, and plugins without complex configuration.

The gem works seamlessly with Rails' asset pipeline tools, like Propshaft,ensuring that your CSS is preprocessed, digested, and efficiently served inproduction environments.

5.4.importmap-rails

importmap-rails enables aNode.js-free approach to managing JavaScript in Rails applications. It leveragesmodern browser support forESModulesto load JavaScript directly in the browser without requiring bundling ortranspilation. This approach aligns with Rails' commitment to simplicity andconvention over configuration.

5.4.1. Howimportmap-rails Works

  • After installation,importmap-rails configures your Rails app to use<script type="module"> tags to load JavaScript modules directly in thebrowser.
  • JavaScript dependencies are managed using thebin/importmap command, whichpins modules to URLs, typically hosted on CDNs likejsDelivr that host pre-bundled, browser-readyversions of libraries. This eliminates the need fornode_modules or apackage manager.
  • During development, there’s no bundling step, so updates to your JavaScriptare instantly available, streamlining the workflow.
  • In production, the gem integrates with Propshaft to serve JavaScript files aspart of the asset pipeline. Propshaft ensures files are digested, cached, andproduction-ready. Dependencies are versioned, fingerprinted, and efficientlydelivered without manual intervention.

NOTE: While Propshaft ensures proper asset handling, it does not handleJavaScript processing or transformations —importmap-rails assumes yourJavaScript is already in a browser-compatible format. This is why it works bestfor projects that don't require transpiling or bundling.

By eliminating the need for a build step and Node.js,importmap-railssimplifies JavaScript management.

5.4.2. When Should You Use It?

importmap-rails is ideal for Rails applications that:

  • Do not require complex JavaScript features like transpiling or bundling.
  • Use modern JavaScript without relying on tools likeBabel.


Back to top
[8]ページ先頭

©2009-2025 Movatter.jp