Skip to main content

50 Using Webpack in Rails with the Webpacker Gem

Episode 181 · April 10, 2017

Let's take a look at using the Webpacker gem in Rails to implement an additional pipeline for building modern frontend Javascript alongside our Rails application using VueJS.

Javascript VueJS


What's up guys? This episode we're talking about the new rails webpacker gem. webpack, if you aren't familiar with it, is kind of like an asset pipeline that's build in a pure JavaScript, so the JavaScript community tends to use that a lot to be for their build pipelines, for building out vue or react or angular applications like that, it will let you write in ES6 syntax, and then you can take that, compile it down to the JavaScript that your browser can understand and then build out all your modules, install NPM packages and everything like that, and it will handle all of that stuff for you. Rails is adding support for webpack and you will effectively have two asset pipelines now. You'll have the asset pipeline where you'll still write your stylesheets, put your images, all that Jazz, and you'll also write your app like front ends in JavaScript in the webpack section if you want to go ahead and do that. Now you've always been able to do this in the asset pipeline, but it doesn't give you a good experience when you're building that stuff, so what webpack is actually going to allow you to do is module reloading and all kinds of other things, as well as a basic support for babel so you can write things like ES6.

Keep in mind, this gem is actually for rails 4.2, and up, but officially they're only supporting rails 5.1 and higher, so if you're using rails 4.2 or 5.0, you can definitely still use this, and it works great. But ther is a chance, a small chance that they might end up doing something that makes it incompatible with those versions. So keep that in mind as we go. I would wait into the first official release of this before you go and put it into production, but let's take a look at how you can set all this up in a rails 5.1 rc1 app right now, and just give you an idea of how it all works, and how you can put all of this stuff together using a front-end JavaScript framework like VueJs. So we're going to use vuejs, it's my personal favorite, out of all of them for many reason, and we're going to build a small example with tht and then I'm going to follow up with a second video showing you how we can make vuejs actually turbolinks compatible, which is pretty neat. So with webpacker, you're going to need of course webpack installed, which actually is easily done for you. You need to make sure that you have node js installed in your machine, as well as the JavaScript package manager called Yarn. So this is more recently come out as kind of a replacement for the npm command, so Yarn is what we'll use to add vuejs or any other node modules to your rails webpack set up. That is going to be all we really need, so it mentions that here in the prerequisites: Make sure that you install node and yarn, this also applies to production, you're going to need yarn in production as well, so that when you precompile your assets webpack can go ahead and install those packages with yarn and then compile those assets for production. One of the nice things that this gem does is it provides you link tags that are very similar to the asset pipeline tag, which means that when you pre compile you assets, when you deploy, all of that is going to work very very similar to the way that your JavaScript works in the asset pipeline. We don't have to learn a whole lot to use the webpacker set up, we just have to do acouple little set up things and we are good to go. Let's dive into an application and see how this works.

I've created this simple application, it's a really basic web app with one scaffold for a model called "Pages" and they have a title in that and that is simply it. All we're caring about is to have a few pages to navigate between so that we can make sure that our JavaScript is working, so that is a really basic application and if you are adding webpacker into your application, you can jump into the Gemfile, dropdown into the bottoma and add webpacker, and you're going to want to do this from the GitHub repository from the webpacker, for now, because that is going to install the latest version but because it hasn't oficially been really released yet, the latest code is always going to be up on GitHub and give you the most stable ad the best features until they release the first version, in which case you can switch to useing that published one. So we'll install this, and run bundle intall to install that. Make sure that you have node and yarn installed around this time, so once that is done, you can run rails webpacker:install. This is how you would install webpacker in any old rails app. There's also a --webpack option that you can use to have it installed by default in any new rails app as well, but we're just going to install it manually in this example. So rails webpacker:install is going to create an app/javascript directory, so not app/assets/javascript this is app/javascript, and that you can see right here. This is effectively the location where all of your webpack javascript is going to live, so all of your front-end javascript is going to live now inside of this now for your react code, or your vue code or angular or whatever, and keep in mind that this is all now requiring us to run a separate process to monitor all of those files. So normally when you do a request in rails, you will have rails load, and then it will hit those assets, and then the asset pipeline precompiles them so that your browser can use them in development. Well, we now have to run webpack separately, so we have the webpack dev server, which is the one I would recommend, but you can also run the webpack watcher in development, and you have to run that side by side with your rails app. So what we can do is after this has installed all the packages, which it creates a bunch of config files and installs this bin stubs, and then it installs yarn add webpack and all of this stuff to your rails app, and installs all of those and you can go back and run your rails server and in another tab, you're going to need to run that bin/webpack-dev-server, so that that can serve up the webpack JavaScript files, and it's going to come from localhost:8080, so you want to make sure nothing else is running on 8080, and your rails app can run on the standard 3000, so you'll still go back to your browser and load up localhost:3000, but in this case, we don't have any of that JavaScript loaded, so one thing when you get to set up is that you have to config the webpack folder. You don't really need to modify any of these configs, but if you want to look at that stuff, you can go ahead and do that, but the key here is that now we have this app/javascript/packs folder with application.js there which is different from the application.js in the asset pipeline. The comments up here show you there's a new JavaScript pack tag rather then the JavaScript include tag that we're used to. This is slightly different, and links to that port 8080 version that comes to webpack. In production it will actually just link to the file, so we need to put this in our layout, if we want to use any of our JavaScript from webpack, so we have to mention these files seprarately than the ones that we want to do with the asset pipeline. So you're going to keep both of those still, and you can load all of the JavaScript like the ujs stuff from rails if you want it. And you'll keep that with your JavaScript include tag, but your webpack stuff will be separate using the JavaScript pack tag. If we save this, this is going to load that application.js in our app, and if we refresh this page, we get "Hello World from Webpacker", so this works, and it's now including that, and it's coming from that localhost:8080 that separate server that we have right here, this is running and serving up that JavaScript file, and inside of here, we can do whatever we want. We can create and reference modules and anything that we would typically do with node modules, our JavaScript modules, we can create a app/javascript/gorails/index.js and here we can export default { gorails: true } and we can import it in our other JavaScript file, so we can say:


import GoRails from 'gorails'

This is going to reference that javascript/gorails directory, and it's automatically going to run or load up that index.js, so we're effectively assigning a local variable here called GoRails that imports that stuff that it exports, which is going to be this gorails: true, so we could console.log(Gorails), and if we save that, we can go back into the browser, and we see that Object {gorails: true} so we have imported code from that other file and loaded that into our application.js, something to note here is that if you comment this out, and you say: "Hello from Gorails", and hit save, so you don't have to do anything and you can go back to your browser, and it's already caught that change, recompiled the JavaScript and it's actually reloaded it in your browser which is really nice because if you were going development of heavy JavaScript stuff, you need to be reloading that pretty regularly, you can get those new changes, I'm sure you're familiar with that process of hitting refresh constantly, this takes that away from you and does that automatically so that you don't have to worry about it, so it's pretty nice and convinient when you're building your front-end like that when you want to make sure that you make changes whenever you save those files. This is pretty cool, it allows you to then go build out your modules inside the app/javascript folder, organize it however you want, and then you can do your importing and everythign between those modules just like you would including modules and ruby or referencing other classes and things. This is all self-congtained inside of that app/javascript folder and you can add other dependencies that you want using yarn, and one thing I didn't point out, is that now you have this package.json. This is pretty much the same thing as your Gemfile, you reference the packages that you depend upon and their versions, and then when yarn is run, it will install all of these, so then you can add packages to this list once yarn is run you can update the yarn.lock which is of course pretty much the same thing as the gemfile.lock it locks down the versions that you have run and then it makes sure that when you update this for production you end up getting the exact same versions so you don't get anything unexpected when you deploy to production and maybe accidentally got two new versions, so this takes care of your JavaScript dependecies, pretty much the same way that the bundler library does that for your ruby dependency so that is really nice as well. Now I know I mentioned I was going to install ujs here, well one thing that we can do is we can use rails webpacker:install:vue to install a vue application, so it's very very simple, but we can install that in our rails app by running this command, which is also an option for react and for angular that will give you a very basic example that gives you a place to start and think about how you want to organize your front-end. The view one also comes with this really cool, so if we go into the view stuff there's hello_vue.js and app.vue which is actually a single file component, so this single file contains the template as well as the JavaScript for that component, and then it also includes some scope styles for as well, which is really nifty, because this is going to be a single file that includes all of the things that are related to that component, so it's fully modular and you're not putting your template in one place and you're not putting your template inside of your JavaScript for the component, and you're also not putting your styles in a totally different place or anything like that, so it's all organized nicely inside of this, and separated into their different sections here, so this hello_vue.js is actually what requires vue, so one of the things that it did when it ran that command was that it actually did yar add vue vue-loader vue-template-compiler, and that actually goes and tells yarn to add that to you local packages.json so now our packages.json has vue, vue-loader, vue-template-compiler and that is added to that, so you can either use yarn to add dependencies, or you can use this file directly and edit it, and then run yarn to install it. So it's usually easier to run yarn add, and we'll go ahead and do that for you, so we now have this hello_vue.js which is the actual location that we want to insert into the browser so if we were to go back to our layout/application.html.erb, rather than doing our application.js as the include, we could do <%= javascript_pack_tag 'hello_vue' %> as the include, and this is going to include that, and then compile it and then run that in the browser, so if we hit refresh, we're going to get an error this time, because that hello_vue.js isn't in a manifest.json , so inside that manifest.json, it says which files are available. In this case, we needed to restart the webpack dev server because when you use those helpers, they actually configu those webpack loaders, so that needs to be restarted so that it picks up that config change, and then if we refresh this page, we get "Hello Vue" at the bottom, and we can see that we're running a view in development mode and everything is working, so we now have a vue app, but unfortunately, if we navigate to another page, it does not include vue, and you can see that it disappeared because turbolinks cached that version and it didn't re run it, so one of those things that we could do is change the event listener to turbolinks:load the same thing as we do with all of our other JavaScripts, this simple inserts an element at the very end of the body, and then tells vue to initialize on that element. This is pretty straightforward how that works, but of course if we want to run that in every page, we need to run that when turbolinks loads, so if we hit Show, turbolinks runs the load event which triggers vue to render here, and if we hit back, that all works, except the browser back button actually does weird things, so it's going to do something kind of unexpected, and the reason for this is because that turbolinks is actually caching the final html on the page because we are dynamically rendering stuff with vuejs. That is not actually the html that rails would have given us, which we really want to cache, this is actually rails plus ujs's html, and we don't really want turbolinks to actually cache that, so we have built a vuejs mix-in which will make it turbolinks compatible which I will talk about in the next episode. So webpacker is a pretty straight forward implementation with rails, it gives you a lot of nice integrations that are familiar so that javascript pack tag in our layout is very familiar with what we're normally doing. We do have to run that additional process here in the terminal. So things like Foreman where you can set it up to say: Well we need a web process, we need a webpack process we need maybe a sidekick process, and it can manage and run all of those, and then shut them all down when you want to stop doing development, that can be very useful when you're using something like webpack now with your applications, because you have to manage rails, webpack, sidekiq maybe some other things like elasticsearch, I don't know, depends on your application, but if you add that, it now has an additional process which can be conveniently managed by Foreman, we'll talk about Foreman in the future, but if you want to learn anything more about webpacker their README is very good, it goes into a lot of the configuration stuff as well, if you wanted to include maybe some Sass styles inside of your JavaScript modules here, you can also use the style sheet pack tag, and it talks about how you can use require instead of the import like I did, and you just need to learn a lot more about how the modern JavaScript staff works if you want to dive into a lot more of this deeply. This README is still work in progress, but one thing I want to mention before we go is that the deployment process is no different that what you're normally used to, so that's really nice, so this gem is actually designed so that when it sees that the asset precompile command runs, it's actually going to insert webpacker compile right afterwards automatically, so the only change on your server is that you're going to need node and yarn installed. You probably already have node intalled, so that you could compile the asset pipeline, and so yarn is the only real dependency that you would need to install this time. So that is really nice, and gives you webpack with very little changes to the way that your normal workflow works, so that is great. You can also link the sprockets assets as well, so if you had any images in the asset pipeline that you want to link to inside of your webpack stuff you can go ahead and use erb is the extention in your JavaScript file inside of the webpack folder and you would just go. So there's the instructions here for react, angular with typescript, and vuejs as well. Feel free to add more as a pull request, this is still in active development, so things are bound to change, but for the most part, the way that you interact with this gem is probably going to stat exactly the same, they're just going to be building out little additional features and customizable things. That is a quick introduction to webpacker, we're going to be using it more in the future. I'm going to follow up this episode with an episode on that JavaScript mix-in for vuejs to make it turbolinks compatible. I'll explain more abou what the real problem with it is, and how we fix it, but for the most part it's a very simple solution, and it works really nicely and we've got a node module that you can use, and we'll show you how to use that in that episode as well. So until then, I will talk to you later. Peace v

Transcript written by Miguel