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!