How to write Javascript in Rails 6 | Webpacker, Yarn and Sprockets

Do you feel lost with all the changes related to assets and Javascript? Npm, Babel, ES6, Yarn, Webpack, Webpacker, Sprockets, do they all look like complete strangers to you?

If you need a quick, easy to understand topo on how this whole Javascript ecosystem works in a Rails 6 application, this article is what you’re looking for.

I’ll end up this article with a step-by-step section explaining how to add Bootstrap 4 and FontAwesome 5 to a Rails 6 project.

NPM

NPM is a Javascript package manager (NodeJS modules to be precise). It is the Rubygems of Javascript world.

npm install <package>

If you want to install bootstrap for instance:

npm install bootstrap

NPM stores downloaded packages in ./node_modules and keeps a list of these packages in ./package.json.

At this point, I’m not drawing any link between NPM and Rails, keep reading to understand why. More additional info at Ruby On Rails Online Training

Yarn

Yarn is a more recent package manager for Javascript. It fetches packages from the NPM repository but does more than that. It allows you to lock the desired versions of your NPM packages in a yarn.lock autogenerated file (similar to Gemfile.lock), it is much faster than NPM, etc.

In a Rails 6 application, when you need a Javascript library, you:

used to add a gem that provides it, then you required it in app/assets/application.js (which was compiled by Sprockets)

have now to add it through Yarn: yarn add <package>, then you require it (we'll see how later).

Note: NPM has since added a lock feature too through package-lock.json

ES6

ES6 is a new Javascript standard (a new version of Javascript if you will). It comes with new super-handy features such as class definition, destructuring, arrow functions, etc.

Babel

Since all Web browsers don’t understand ES6 yet, you need a tool that reads your ES6 Javascript code and translates it into old ES5 Javascript for it to work on all browsers. Babel is the compiler that does this translation.

Webpack

There is Babel and there is Yarn and their configuration files and there is the need to automate the compilation of your assets and the management of environments and so on.

Because you want to focus on writing code and automate assets precompilation, you will be using Webpack which takes the role of bandmaster. It takes your assets and passes each one of them to the right plugins. The plugins then make the right tool process the input file and give the expected output.

For instance, Webpack can:

take your ES6 Javascript code,

use the babel-loader plugin to make Babel compile ES6 into ES5 Javascript code,

then output the resulting pack in a file that you can include in your HTML DOM (<script type="text/javascript" src="path-to-es5-javascript-pack.js"></script>).

Webpacker

Webpacker is a gem that nicely includes Webpack in your Rails application. It comes with some initial (and sufficient to begin with) configuration files so that you can start by writing actual code without worrying about configuration.

Webpacker’s default configuration says the following:

app/javascript/packs/ shall contain your Javascript packs (for instance: application.js)

You can include a Javascript pack in your views using javascript_pack_tag '<pack_name>' (for instance: <%= javascript_pack_tag 'my_app' %> will include app/javascript/packs/my_app.js)

I’ll give a very clear example of how all of this works at the end of this article, I just need to talk a bit about Sprockets first.

To get in-depth knowledge on Ruby On Rails Course

Note: another default configuration is extract_css: false (config/webpacker.yml), which means that although Webpack knows how to serve CSS packs with stylesheet_pack_tag, you tell it not to. This article is focused on Javascript so I'm not going to say more about this, just keep in mind that it is turned off by default so you won't waste time debugging what is default behavior, not a bug.

Yet another note: when you run rails assets:precompile, you might think that Rails will only precompile what’s in app/assets/. Rails will actually precompile both Webpack app/javascript/ assets and Sprockets app/assets/ assets.

Sprockets 4

Like Webpack, Sprockets is an asset pipeline, which means it takes assets files as input (Javascript, CSS, images, etc.) and processes them to produce an output in the desired format.

As of Rails 6, Webpack(er) replaces Sprockets as the new standard for writing Javascript in your Rails applications. However, Sprockets is still the default way of adding CSS to your applications.

With Sprockets you:

used to list available assets in config.assets.precompile (Sprockets 3, Rails 5)

have now to do that in a manifest file app/assets/config/manifest.js (Sprockets 4, Rails 6)

If you want to include an asset from the Sprockets pipeline, you would:

Write your CSS (for instance: app/assets/stylesheets/my_makeup.css)

Ensure app/assets/config/manifest.js makes it available for stylesheet_link_tag either through a link_tree, link_directory or a link statement (for instance: link my_makeup.css)

Include it in your view using stylesheet_link_tag (<%= stylesheet_link_tag 'my_makeup' %>)

Do not try to use Webpack as you would use Sprockets!

It is essential that you understand the following if you don’t want to waste countless hours rowing against the current. Ideally you should spend some time learning ES6 but meanwhile I can at least say this:

Webpack is different than Sprockets in the sense that it compiles Modules.

ES6 modules to be precise (in the case of Rails 6 with a default configuration). What does that imply? Well, it implies that everything you declare in a module is kind of namespaced because it is not meant to be accessible from the global scope but rather imported then used. Let me give you an example.

You can do the following with Sprockets:

app/assets/javascripts/hello.js:

function hello(name) { console.log("Hello " + name + "!"); }

Pretty simple to understand. How about with Webpacker now?

If you thought you’d simply move these JS files under app/javascript/packs, include them using javascript_pack_tag and be done, let me stop you right there: it would not work.

Why? Because hello() would be compiled as being in a ES6 module (likewise for user_greeting()), which means that as far as user_greeting() function goes, even after both JS files are included in the view, the hello() function does not exist.

Would that work? No. Why? Again, for the same reason: greet_user is not accessible from the view because it is hidden inside a module once it is compiled.

We finally reach the most important point of this section:

With Sprockets: views can interact with what your JS files expose (use a variable, call a function, ..) enroll for live free demo on Ruby Certification

With Webpack: views do NOT have access to what your JS packs contain.

So how would you make a button trigger a JS action? From a pack, you add a behavior to an HTML element. You can do that using vanilla JS, JQuery, StimulusJS, you name it.

Text je součástí Refresher blogu, není redakčním obsahem. Administrátory můžete kontaktovat na blogy@refresher.sk.

Ohodnoť blog
0
Odeslat správu

Chceš vědět, když Sravan Cynixit přidá nový blog?

Zadej svůj mail a dostaneš upozornění. Kdykoliv se můžeš odhlásit.