00:00:20.750
Okay, so this is not going to be a very long talk. Hopefully, it'll be useful. I'm Danielle, and I'm a software engineer at a company called Nipt based in Boston.
00:00:24.090
I'm actually going to start this talk by changing the title. Originally, I decided to call it "Webpacker versus the Asset Pipeline," but as I continued to do research for this talk, I realized that it's not really just Webpacker versus the Asset Pipeline. It's more like Webpacker versus no Webpacker or Webpacker versus the Asset Pipeline plus some other real stuff.
00:00:34.650
Honestly, what this talk is really about is discussing what it's like to use a Rails app with Webpacker and without it. It's honestly not a straightforward comparison because I don't think there's going to be a clear winner at the end. It's more about personal preference, and I really want you to see what to expect when you choose one over the other.
00:00:55.350
Webpacker is a wrapper around Webpack, which is something you use with JavaScript applications. I decided to use UJS, so we’re going to see a lot of examples that use .vue files. A typical .vue file will look like this. I know it may be really small, and you don’t necessarily need to read it; I just want you to understand that a .vue file can consist of three different parts.
00:01:18.140
You’re going to have your template part, which is just HTML. You’re going to have your JavaScript part, and you’ll have your CSS part. And of course, the order of this does not matter; this is just the order I happened to put it in.
00:01:41.459
Now, what is the Asset Pipeline? When you go to the Ruby guide, it states that the Asset Pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. We’ve all started a new Rails app, right? And we’ve seen something similar to this in our application.js file. This is where we are just importing either sub-trees or folders or importing another file and concatenating it into this current file, all of which is handled by Sprockets, the gem that implements the Asset Pipeline.
00:02:06.569
Similarly, in our Sass files, we’ve seen these import statements where we concatenate other CSS files to our current Sass file. We’ve also seen fingerprinting, where our assets have fingerprinting added so that it can make caching easier. It’s important to note that while Sprockets can handle this, you may not know that Sprockets can be extended.
00:02:28.909
We can extend it by adding processors, transformers, or compressors. There are many resources I used to research some of this, and I urge you to look at that URL down there; it will provide you with more information. For now, let's focus on the three types of extensions we can use.
00:03:04.150
There's also one more type of extension called exporters, which just writes the files to the file system, but we won't discuss that much. We’ll start with transformers. Transformers change one file type into another. For example, a CoffeeScript file, a .coffee file, will be transformed into a JavaScript file. If you ever get the chance to look at different source codes, such as the TypeScript source code, you can see where it's registering MIME types.
00:03:21.340
For instance, it registers text/typescript with the .ts extension and a transformer that changes the TypeScript file to a JavaScript file using the TypeScript Rails transformer. Essentially, that's what a transformer does: it changes one file into different file types. In the case of Sass files, their default transformer converts them into CSS files.
00:03:39.040
After transformers, we have processors. There are two types of processors: pre-processors and post-processors. Pre-processors run when the file is loaded, while post-processors run after transformers. If you recall the lines I mentioned in application.js, that is handled by a preprocessor called the directive processor. It is responsible for loading files and concatenating them.
00:04:15.510
An example of a post-processor is Autoprefixer, which takes CSS like this and expands it into more compatible code for various browsers. So, we’ve reviewed three types of processors, and then we have compressors. Compressors do exactly what their name implies; they reduce the size of your files. For example, UglifyJS is a process that acts as a compressor by removing whitespace to minimize the file size.
00:04:55.110
We’ve seen how we can extend Sprockets by adding processors, transformers, and compressors. Now, let's look at Webpack. As mentioned earlier, Webpacker is a Rails wrapper around Webpack. If you visit the Webpack website, they describe Webpack as a static module bundler for modern JavaScript applications.
00:05:02.310
However, this definition doesn’t quite illustrate what it does. What helped me understand Webpack better was the diagram on their homepage. You can see that you have JS files dependent on Vue files, which in turn depend on other Vue files, and Sass files that depend on image files. Webpacker takes all of these and compiles them into simple static assets. That’s essentially what Webpacker does; it manages all of your dependencies for you.
00:05:53.610
All you need to do is specify that your file depends on these things, along with which other files depend on those, and Webpacker will manage all those dependencies and create simple static files from them.
00:06:18.270
In using Webpack, you'll encounter import statements like these. One of the cool things about Webpack is that you can import almost any type of file into your JavaScript files. You can import classes, functions, and objects from other JavaScript files and even images and CSS into your JavaScript files.
00:06:35.830
When configuring Webpack, you want to start with an entry point. Your entry point is the file or files that you will compile down. These are typically located in your app’s JavaScript pack folder. Any file within that folder is an entry point, including .vue files, .js files, Sass files, CSS files, and even image files. From here, we pass them through loaders.
00:07:21.180
Loaders, like Sprockets’ transformers, processors, and compressors, encompass similar functionalities. Here’s an example of a loader that works with a Sass file. The great thing about loaders is that you can specify a regex for them. For instance, you can indicate that you want any file ending with .sass to be processed. Note that loaders run in reverse order; unlike the intuitive top-down processing, they work bottom-up.
00:07:46.160
For instance, the Sass loader compiles the .sass file into a .css file, then that gets passed to a CSS loader to interpret the import statements, followed by a style loader that adds the CSS to the DOM. In this way, Sprockets’ Sass loader acts as a Sprocket transformer, and if you wanted to, you could put an Autoprefixer at the top to run last.
00:08:24.510
Right now, we are using a Vue loader, which will convert that Vue file, with the .vue extension, into corresponding JavaScript and CSS files. Therefore, with loaders such as Vue loader, Sass loader, and CSS loader, we finally arrive at our outputs.
00:09:00.600
By default, output will direct to your public packs folder, where all your minimized and compressed files will reside. For your .vue and .js files, you'll have .js files, and for your Sass files, you'll have .css files. Additionally, you'll also obtain source map files, which are incredibly useful for debugging JavaScript in production.
00:09:39.640
These source map files allow you to map the minified JavaScript back to the original code, giving you insight into what's occurring. We now understand how Sprockets works, how we can extend it, and how Webpack works. Now we can ask more questions, such as where assets are located, how we create components, how we bundle files, and how we manage CSS.
00:10:02.330
By default, all your files for entry points will be placed in app/javascript. The entire application.js file serves as the area to place all your entries while using Webpack. Even image files that you import into a JavaScript file would still reside in your app/javascript folder.
00:10:46.130
This may feel a bit odd compared to the Asset Pipeline, where everything is in app/assets. Similarly, compiled and fingerprinted files with Webpack will end up in public/packs, whereas with the Asset Pipeline, they would be in public/assets.
00:11:20.280
Now that we know where our files are and where they will end up, how do we create components? Recalling the Vue file we mentioned earlier, that Vue file conveniently contains our template, JavaScript, and CSS. Webpack manages this for you seamlessly. However, Sprockets can't handle this due to its limitation with .vue files.
00:11:58.410
You can extend it with a transformer. If you happen to find that Vue transformer, it enables transforming a .vue file to a JavaScript file or a CSS file. And of course, for every Ruby programmer, there’s probably a gem for it. Indeed, there is a Rails view loader gem available that allows you to utilize this compilation.
00:12:27.820
But what happens if a Sprocket transformer isn't available, or you prefer not to create one due to time constraints? In that case, you can utilize Rails view partials. While some may feel uneasy about mixing JavaScript with HTML, it is achievable with script tags.
00:12:55.460
There is usually a performance hit when continually importing Rails view partials, but you can use caching to alleviate this. Caching is manageable since it doesn’t depend on user data; it's purely static HTML and JavaScript.
00:13:24.040
Now we know how to create our components, but how do we bundle everything properly? At the top level, including your JavaScript and CSS links is quite similar to doing it with Sprockets. Instead of using a JavaScript include tag, you would use a JavaScript pack tag. Likewise, while using a stylesheet link tag, you'll use a stylesheet pack tag.
00:13:52.050
Suppose we are utilizing a Vue Sprocket transformer. In that case, it’s essential to note that even though that Vue Sprocket transformer is in play, you still need to add the Vue file to any JavaScript file carrying that JavaScript logic. Additionally, ensure to add the component's Vue file to your CSS file, necessitating an import statement in both locations.
00:14:26.460
If you only add it in one place, say, to your JavaScript file, but neglect to do the same in your CSS or Sass file, you will miss out on getting any of the relevant styles. Webpack, however, does not require this dual inclusion; it simplifies things significantly by allowing you to import any type of object swiftly into a JavaScript object.
00:15:02.460
As a brief overview of import and export: if you do not export something from a JavaScript file, you cannot use it in another file. To export an entire file, you can enclose it within export brackets. Moreover, you can export multiple items using named exports.
00:15:37.370
For instance, if you have a main JavaScript file that imports one or more files, Webpack builds a dependency graph of everything in your static files. Therefore, it includes each code snippet from imported files just once, greatly optimizing the compilation process. In contrast, Sprockets concatenates the imports, which can lead to duplicate entries if not handled carefully.
00:16:02.400
This presents an advantage for Webpack, as it ensures you include unique dependencies, while Sprockets risks unnecessary repetition.
00:16:34.820
With that, we have explored various aspects of file bundling. Now, how do we handle CSS? CSS management within Webpack is relatively straightforward because you can add CSS directly to the entry points. Should you wish to include global CSS, you can incorporate it into any JavaScript file as needed.
00:17:07.450
In summary, adding CSS using Webpack aligns with traditional methods and allows for Sass import statements even in .vue files, ensuring seamless integration with existing methodologies.
00:17:36.690
At Nipt, we've opted for the Rails view partial method due to the static nature of many of our pages, which suit our needs well. While opting for a full single-page application (SPA) may appeal to some, using Webpack can certainly be beneficial for handling dependencies, particularly with JavaScript applications. However, I believe there is no right or wrong approach to this.
00:17:57.750
Ultimately, I hope this talk has been useful to you, and I welcome any questions you may have. Thank you.