diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index d4d2225add..f0a3ee9ade 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -83,8 +83,6 @@ proper prerequisites installed. These include: * Ruby * SQLite3 -* Node.js -* Yarn #### Installing Ruby @@ -121,31 +119,6 @@ $ sqlite3 --version The program should report its version. -#### Installing Node.js and Yarn - -Finally, you'll need Node.js and Yarn installed to manage your application's JavaScript. - -Find the installation instructions at the [Node.js website](https://nodejs.org/en/download/) and -verify it's installed correctly with the following command: - -```bash -$ node --version -``` - -The version of your Node.js runtime should be printed out. Make sure it's greater -than 8.16.0. - -To install Yarn, follow the installation -instructions at the [Yarn website](https://classic.yarnpkg.com/en/docs/install). - -Running this command should print out Yarn version: - -```bash -$ yarn --version -``` - -If it says something like "1.22.0", Yarn has been installed correctly. - #### Installing Rails To install Rails, use the `gem install` command provided by RubyGems: diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index ee975c2e2c..469dcfb949 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -3,561 +3,274 @@ Working with JavaScript in Rails ================================ -This guide covers the built-in Ajax/JavaScript functionality of Rails (and -more); it will enable you to create rich and dynamic Ajax applications with -ease! +This guide covers the options for integrating JavaScript functionality into your Rails application, +including the options you have for using external JavaScript packages and how to use Turbo with +Rails. After reading this guide, you will know: -* The basics of Ajax. -* Unobtrusive JavaScript. -* How Rails' built-in helpers assist you. -* How to handle Ajax on the server side. -* The Turbolinks gem. -* How to include your Cross-Site Request Forgery token in request headers +* How to use Rails without the need for a Node.js, Yarn, or a JavaScript bundler. +* How to create a new Rails application using import maps, esbuild, rollup, or webpack to bundle +your JavaScript. +* What Turbo is, and how to use it. +* How to use the Turbo HTML helpers provided by Rails. -------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -An Introduction to Ajax ------------------------- +Import maps +----------- -In order to understand Ajax, you must first understand what a web browser does -normally. +[Import maps](https://github.com/rails/importmap-rails) let you import JavaScript modules using +logical names that map to versioned files directly from the browser. Import maps are the default +from Rails 7, allowing anyone to build modern JavaScript applications using most NPM packages +without the need for transpiling or bundling. -When you type `http://localhost:3000` into your browser's address bar and hit -'Go', the browser (your 'client') makes a request to the server. It parses the -response, then fetches all associated assets, like JavaScript files, -stylesheets and images. It then assembles the page. If you click a link, it -does the same process: fetch the page, fetch the assets, put it all together, -show you the results. This is called the 'request response cycle'. +Applications using import maps do not need [Node.js](https://nodejs.org/en/) or +[Yarn](https://yarnpkg.com/) to function. If you plan to use Rails with `importmap-rails` to +manage your JavaScript dependencies, there is no need to install Node.js or Yarn. -JavaScript can also make requests to the server, and parse the response. It -also has the ability to update information on the page. Combining these two -powers, a JavaScript writer can make a web page that can update just parts of -itself, without needing to get the full page data from the server. This is a -powerful technique that we call Ajax. +When using import maps, no separate build process is required, just start your server with +`bin/rails server` and you are good to go. -As an example, here's some JavaScript code that makes an Ajax request: +### Adding NPM Packages with importmap-rails -```js -fetch("/test") - .then((data) => data.text()) - .then((html) => { - const results = document.querySelector("#results"); - results.insertAdjacentHTML("beforeend", html); - }); +To add new packages to your import map-powered application, run the `bin/importmap pin` command +from your terminal: + +```bash +$ bin/importmap pin react react-dom ``` -This code fetches data from "/test", and then appends the result to the element -with an id of `results`. - -Rails provides quite a bit of built-in support for building web pages with this -technique. You rarely have to write this code yourself. The rest of this guide -will show you how Rails can help you write websites in this way, but it's -all built on top of this fairly simple technique. - -Unobtrusive JavaScript ----------------------- - -Rails uses a technique called "Unobtrusive JavaScript" to handle attaching -JavaScript to the DOM. This is generally considered to be a best-practice -within the frontend community, but you may occasionally read tutorials that -demonstrate other ways. - -Here's the simplest way to write JavaScript. You may see it referred to as -'inline JavaScript': - -```html -Paint it red +Then, import the package into `application.js` as usual: +```javascript +import React from "react" +import ReactDOM from "react-dom" ``` -When clicked, the link background will become red. Here's the problem: what -happens when we have lots of JavaScript we want to execute on a click? +Adding NPM Packages with JavaScript Bundlers +-------- -```html -Paint it green +Import maps are the default for new Rails applications, but if you prefer traditional JavaScript +bundling, you can create new Rails applications with your choice of +[esbuild](https://esbuild.github.io/), [webpack](https://webpack.js.org/), or +[rollup.js](https://rollupjs.org/guide/en/). + +To use a bundler instead of import maps in a new Rails application, pass the `—javascript` or `-j` +option to `rails new`: +``` +$ rails new my_new_app --javascript=webpack +OR +$ rails new my_new_app -j webpack ``` -Awkward, right? We could pull the function definition out of the click handler, -and turn it into a function: +These bundling options each come with a simple configuration and integration with the asset +pipeline via the [jsbundling-rails](https://github.com/rails/jsbundling-rails) gem. -```js -window.paintIt = function(event, backgroundColor, textColor) { - event.preventDefault(); - event.target.style.backgroundColor = backgroundColor; - if (textColor) { - event.target.style.color = textColor; - } -} +When using a bundling option, use `bin/dev` to start the Rails server and build JavaScript for +development. + +### Installing Node.js and Yarn + +If you are using a JavaScript bundler in your Rails application, Node.js and Yarn must be +installed. + +Find the installation instructions at the [Node.js website](https://nodejs.org/en/download/) and +verify it’s installed correctly with the following command: + +```bash +$ node --version ``` -And then on our page: +The version of your Node.js runtime should be printed out. Make sure it’s greater than `8.16.0`. -```html -Paint it red +To install Yarn, follow the installation instructions at the +[Yarn website](https://classic.yarnpkg.com/en/docs/install). Running this command should print out +the Yarn version: + +```bash +$ yarn --version ``` -That's a little bit better, but what about multiple links that have the same -effect? +If it says something like `1.22.0`, Yarn has been installed correctly. -```html -Paint it red -Paint it green -Paint it blue -``` +Choosing Between Import Maps and a JavaScript Bundler +----------------------------------------------------- -Not very DRY, eh? We can fix this by using events instead. We'll add a `data-*` -attribute to our link, and then bind a handler to the click event of every link -that has that attribute: +When you create a new Rails application, you will need to choose between import maps and a +JavaScript bundling solution. Every application has different requirements, and you should +consider your requirements carefully before choosing a JavaScript option, as migrating from one +option to another may be time-consuming for large, complex applications. -```js -function paintIt(element, backgroundColor, textColor) { - element.style.backgroundColor = backgroundColor; - if (textColor) { - element.style.color = textColor; - } -} +Import maps are the default option because the Rails team believes in import maps' potential for +reducing complexity, improving developer experience, and delivering performance gains. -window.addEventListener("load", () => { - const links = document.querySelectorAll( - "a[data-background-color]" - ); - links.forEach((element) => { - element.addEventListener("click", (event) => { - event.preventDefault(); +For many applications, especially those that rely primarily on the [Hotwire](https://hotwired.dev/) +stack for their JavaScript needs, import maps will be the right option for the long term. You +can read more about the reasoning behind making import maps the default in Rails 7 +[here](https://world.hey.com/dhh/rails-7-will-have-three-great-answers-to-javascript-in-2021-8d68191b). - const {backgroundColor, textColor} = element.dataset; - paintIt(element, backgroundColor, textColor); - }); - }); -}); -``` -```html -Paint it red -Paint it green -Paint it blue -``` +Other applications may still need a traditional JavaScript bundler. Requirements that indicate +that you should choose a traditional bundler include: -We call this 'unobtrusive' JavaScript because we're no longer mixing our -JavaScript into our HTML. We've properly separated our concerns, making future -change easy. We can easily add behavior to any link by adding the data -attribute. We can run all of our JavaScript through a minimizer and -concatenator. We can serve our entire JavaScript bundle on every page, which -means that it'll get downloaded on the first page load and then be cached on -every page after that. Lots of little benefits really add up. +* If your code requires a transpilation step, such as JSX or TypeScript. +* If you need to use JavaScript libraries that include CSS or otherwise rely on +[Webpack loaders](https://webpack.js.org/loaders/). +* If you are absolutely sure that you need +[tree-shaking](https://webpack.js.org/guides/tree-shaking/). +* If you will install Bootstrap, Bulma, PostCSS, or Dart CSS through the +[cssbundling-rails gem](https://github.com/rails/cssbundling-rails). All options provided by this +gem except Tailwind will automatically install `esbuild` for you if you do not specify a different +option in `rails new`. -Built-in Helpers ----------------- +Turbo +----- -### Remote Elements +Whether you choose import maps or a traditional bundler, Rails ships with +[Turbo](https://turbo.hotwired.dev/) to speed up your application while dramatically reducing the +amount of JavaScript that you will need to write. -Rails provides a bunch of view helper methods written in Ruby to assist you -in generating HTML. Sometimes, you want to add a little Ajax to those elements, -and Rails has got your back in those cases. +Turbo lets your server deliver HTML directly as an alternative to the prevailing front-end +frameworks that reduce the server-side of your Rails application to little more than a JSON API. -Because of Unobtrusive JavaScript, the Rails "Ajax helpers" are actually in two -parts: the JavaScript half and the Ruby half. +### Turbo Drive -Unless you have disabled the Asset Pipeline, -[rails-ujs](https://github.com/rails/rails/tree/main/actionview/app/assets/javascripts) -provides the JavaScript half, and the regular Ruby view helpers add appropriate -tags to your DOM. +[Turbo Drive](https://turbo.hotwired.dev/handbook/drive) speeds up page loads by avoiding full-page +teardowns and rebuilds on every navigation request. Turbo Drive is an improvement on and +replacement for Turbolinks. -You can read below about the different events that are fired dealing with -remote elements inside your application. +### Turbo Frames -#### form_with +[Turbo Frames](https://turbo.hotwired.dev/handbook/frames) allow predefined parts of a page to be +updated on request, without impacting the rest of the page’s content. -[`form_with`](https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with) -is a helper that assists with writing forms. To use Ajax for your form you can -pass the `:local` option to `form_with`. +You can use Turbo Frames to build in-place editing without any custom JavaScript, lazy load +content, and create server-rendered, tabbed interfaces with ease. + +Rails provides HTML helpers to simplify the use of Turbo Frames through the +[turbo-rails](https://github.com/hotwired/turbo-rails) gem. + +Using this gem, you can add a Turbo Frame to your application with the `turbo_frame_tag` helper +like this: ```erb -<%= form_with(model: @article, id: "new-article", local: false) do |form| %> - ... +<%= turbo_frame_tag dom_id(post) do %> +