Rails World 2023

Propshaft and the Modern Asset Pipeline

Propshaft and the Modern Asset Pipeline

by Breno Gazzola

In the video titled "Propshaft and the Modern Asset Pipeline," Breno Gazzola, Co-Founder & CTO of FestaLab, addresses the significant developments introduced in Rails 7 concerning the asset pipeline, particularly focusing on the newly developed Propshaft. The session highlights the transition to a "no-build" frontend development approach and analyzes enhancements in implementing modern technologies for developers, aiming to improve the overall user experience.

Key points discussed include:

- Context of Rails Asset Pipeline: The original asset pipeline aimed to solve critical issues of performance and maintainability in frontend development through techniques such as transpilation, bundling, fingerprinting, and compression. These functions, designed separately, previously relied heavily on Sprockets.
- Major Changes with Rails 7: Modern browsers now support ES6, decreasing the necessity for transpilation. Additionally, the emergence of utility-first CSS frameworks has diminished the reliance on large CSS libraries, while HTTP/2 supports multiple concurrent requests, reducing the need for traditional bundling approaches.
- Propshaft Introduction: Developed to replace Sprockets, Propshaft emerged on September 18, 2021, aiming to streamline asset management while avoiding unnecessary complexity. It simplifies asset handling by automatically configuring itself and removing manual interventions previously required.
- Asset Lifecycle Explanation: Gazzola elaborates on the dynamics of asset management, illustrating the lifecycle—from asset requests in development to how assets are compiled and served in production with Propshaft's automated handling.
- Fingerprinting and Integration: The session addressed fingerprinting requirements due to its significance in modern web applications, advocating for improved methods of digesting assets and seamless integration with existing bundlers without climate-specific gems.
- Final Considerations: Developers are encouraged to evaluate their asset pipeline needs, considering whether to keep using Sprockets or transition to Propshaft based on their preference for Node.js integration.

In conclusion, Gazzola emphasizes Propshaft as a modern solution that simplifies asset management within Rails 7, enhancing developer efficiency and ensuring a better overall user experience as web standards evolve. This progress reflects a decisive shift in Rails development methodology, focusing on leveraging current technologies effectively without unnecessary features.

00:00:15.160 Hello everyone! One of the major new features of Rails 7 is the asset pipeline, which introduced a no-build frontend development approach. At the same time, it improved integration with the Node ecosystem. That's great for us developers, as we are always looking for ways to enhance our development experience and build better user experiences.
00:00:22.480 However, the introduction of multiple new gems, some of which have overlapping features, has led to confusion about how to take full advantage of everything that Rails 7 has to offer. It's crucial to ensure that when creating your next application or updating an existing one, you make the correct choices without having to redo significant portions of your frontend.
00:00:40.559 To make informed decisions, we need to understand what makes the new asset pipeline so different from the previous one. We will first explore the problems that the original asset pipeline was attempting to solve, then examine the advancements in technology over the past decade that have rendered many of those features unnecessary, and finally take a look at Propshaft and why it's at the heart of the new asset pipeline.
00:00:54.120 When I refer to the asset pipeline, I mean a collection of features and techniques that answer two important questions about frontend development: how do I make my pages load faster, and how do I make my code more maintainable? For the original asset pipeline, these questions were addressed through transpilation, bundling, fingerprinting, and compression.
00:01:15.040 Transpilation involves converting source code from one language to another, while bundling combines many small files into a larger one. Fingerprinting ensures the file name changes when its content changes, and compression reduces the file size delivered to the user. These features used to be implemented individually, which is why for many years Sprockets and the asset pipeline were synonymous.
00:01:37.360 But why was transpilation necessary? When the original asset pipeline was released, support for CSS 2.1 was barely present, and it didn't include support for important features like imports, variables, or nesting, which make CSS more maintainable. Moreover, CSS 3, which came later, still lacked support for nesting, prompting the use of SASS to address these limitations.
00:01:58.559 Turning to JavaScript, the situation was even worse. We were several years away from ES6 being widely supported, and ES5 had not yet been fully adopted. This gap led many developers to use SASS or CoffeeScript to simplify their development experience. Thus, transpilation became a necessity for effective frontend development.
00:02:18.480 Next, let's discuss bundling, which serves both maintainability and performance. Bundling allows developers to work with manageable files rather than a single file that could be thousands of lines long. Having too many small files increases the number of HTTP requests, which can introduce latency, especially with HTTP/1's limitation of one request per connection.
00:02:40.360 The obvious solution used to be to open multiple connections, but with modern practices and tools, this has become less efficient. Moreover, since CSS and JavaScript are render-blocking, loading multiple small files can lead to users waiting on a blank page while their browser processes all the requests. By bundling CSS and JavaScript into a single file respectively, we can eliminate excess round trips and boost performance.
00:03:03.960 Fingerprinting is another performance-related feature. The basic rule of thumb is that browsers shouldn't download assets every time a page is loaded. Instead, cache control headers should inform the browser whether it has already downloaded a file, preventing unnecessary downloads. This works well for assets that rarely change, such as logos, but not for dynamic resources like CSS and JavaScript, which require frequent updates.
00:03:32.760 To properly manage this, the best practice is to change the file name whenever the content changes, often achieved by utilizing a digest of the content. However, assets like CSS files frequently reference images and fonts that could change names, requiring additional considerations. This is where asset helpers were introduced to support Sprockets in adjusting asset names.
00:03:50.480 Lastly, we encounter compression, which started with minification and moved toward gzipping files before sending them to clients. These measures drastically reduce file sizes, which is crucial given the network capabilities available back then, particularly for mobile devices on 3G networks. So, this is how the original asset pipeline operated.
00:04:11.280 Now, what changes with Rails 7? Well, ES6 support has become ubiquitous among modern browsers, mitigating the need for transpilation in many cases. At the same time, we've witnessed the rise of utility-first CSS frameworks, which provide hundreds of utility classes instead of complete component libraries. This makes it easier for developers to compose their designs without needing deep CSS knowledge.
00:05:00.840 HTTP/2 has also removed the limitations of HTTP/1, allowing multiple requests over a single connection. Consequently, bundling becomes less essential, and in fact, it can be considered an anti-pattern now. For example, when changing a file, avoiding bundling ensures that only the modified files are downloaded by the client.
00:05:20.280 Fingerprinting, however, remains necessary, particularly with the rise of single-page applications. JavaScript code references assets in various ways, making it essential to have a reliable method of fingerprinting. Previously we introduced Webpacker to integrate with the Node ecosystem while still facilitating fingerprinting.
00:05:36.960 With the fast-paced evolution of the JavaScript community, we found a single gem bundler approach inadequate. Thus, we needed to find a more efficient way to accomplish fingerprinting without hindering development processes. CDNs like Cloudflare now offer automatic compression services, choosing the best version of assets based on what the browser can support.
00:05:55.480 In summary, the new asset pipeline drops unnecessary features like transpiling and bundling. We keep fingerprinting, but make it more efficient while eliminating asset helpers. Instead, we want the integration of npm packages to work out of the box and find new ways to handle JavaScript fingerprinting, whether through Port Maps or by allowing bundlers to manage it.
00:06:09.440 Now, regarding the introduction of Propshaft, we had to make a decision that many developers face: whether to keep updating Sprockets or start anew. Although Sprockets served us well, it carried 15 years of history and many unnecessary features. Ultimately, on September 18, 2021, Propshaft was born.
00:06:29.560 In each commit of Propshaft, you can see how it evolved step by step as a modern Rails gem. This presents an excellent learning opportunity as you can view design decisions made over time by reading the commit messages and understanding their motivations.
00:06:49.520 Propshaft replaced Sprockets in a production application and is now responsible for serving thousands of assets to millions of users every month. At its core, when your application boots, Propshaft automatically configures itself and assigns an instance of its essential class, the assembly.
00:07:10.520 The assembly allows access to all Propshaft features, including the load path that contains paths to all assets. Unlike Sprockets, which relies on a manually created manifest file, Propshaft automatically detects the locations of your asset files.
00:07:30.440 The core responsibilities are handled through various components: a resolver that finds the asset files during development, a processor for cleaning tasks, and compilers that process CSS and JavaScript files, updating references as necessary.
00:07:53.360 The most effective way to comprehend how these parts work together is to examine the lifecycle of an asset. For example, when a view asks Rails for a stylesheet link tag, it relies on Propshaft to manage the asset lookup dynamically.
00:08:07.840 In development mode, Propshaft provides a dynamic resolver that works with the load path to find the requested asset. The load path functions like a hash table that maps asset names to their instances, optimizing the asset lookup process.
00:08:28.480 To build this hash, Propshaft iterates through the project's asset directories. These directories were added to the asset path during its configuration when Propshaft reviewed the application's structure, specifically looking for any 'assets' folders.
00:08:51.120 With asset references available, the system retrieves the digested name, which reflects the current content of the associated file. So, when a view requests an asset, it successfully checks the digest along with the standard asset naming convention.
00:09:10.000 In production, the asset resolution approach will slightly change, as the system moves to utilize a static resolver. This static resolver does not use the load path but instead relies on a manifest that is generated by Propshaft.
00:09:32.600 The next phase in the asset lifecycle occurs when the application requires the asset upon being booted. Again, Propshaft ensures everything is in place to deliver assets efficiently. The server class assigned to the asset's route processes requests, performing essential tasks.
00:09:52.720 The asset server performs functions such as separating the asset's name from its digest, reaching out to the load path to locate the asset. Once it has been identified, the process compiles it smoothly, seamlessly adapting file references accordingly.
00:10:14.080 Propshaft automates the handling of asset helpers, and thus developers avoid manual interventions entirely. The asset server serves the asset with appropriate headers, ensuring a smooth delivery experience.
00:10:34.560 In development mode, when developers add a new asset, Propshaft monitors the changes and ensures that everything is updated correctly. A callback is registered so that whenever a page reloads or changes, it checks for any alterations and clears the cache if changes are detected.
00:10:55.760 The final step in an asset's lifecycle is the precompile operation. Propshaft ensures the public assets folder is available before writing a manifest that the static resolver will utilize, then transfers all relevant assets to that folder.
00:11:15.840 While doing this, Propshaft compiles the necessary files, optimizing them for production use. It is vital to ensure that all output is correctly set up in the right locations as the application prepares for deployment.
00:11:36.440 In summary, Propshaft generates all your assets, handles them in development, and compiles them for production. This efficient management ensures that all your assets are available when needed and are processed effectively.
00:12:00.640 There are three additional features I want to discuss. First, we made the decision to eliminate asset helpers entirely. Instead, the CSS compiler scans each method of asset referencing, ensuring everything gets addressed correctly.
00:12:27.960 With comprehensive testing, Propshaft can detect and manage all sorts of asset behaviors without further manual involvement. This includes simplified integrations for popular frameworks, allowing them to work effortlessly.
00:12:51.040 We also discussed JavaScript fingerprinting. There are two approaches: allowing bundlers to manage the digesting of assets or utilizing Import Maps to streamline how assets are referenced. The latter offers a simple hash mapping asset names to their respective inclusion points.
00:13:14.440 Lastly, we investigated improving integration with various bundlers without needing to create an individual gem for each. This is where the notion of bundling gems comes in, offering support for different tools like esbuild, Rollup, and PostCSS.
00:13:37.840 Integrating Propshaft with your preferred bundler can be achieved not through manual setups but simply by running specific commands. This allows you to monitor file changes and automate the build process.
00:13:58.120 As we reach our conclusion, we revisit the central question: What do you want from your asset pipeline? It comes down to whether you desire to incorporate Node into your development workflow.
00:14:16.120 If your response is no, you should continue using Sprockets and Import Maps. However, if you want to leverage Node, the bundler gems will be the right route to take while seamlessly integrating Propshaft.
00:14:40.040 Once Propshaft is released, replacing Sprockets in your application becomes a straightforward and efficient process. Thank you, everyone!