From 5eced91bc07481437728f4e151a56d619ce0e15a Mon Sep 17 00:00:00 2001 From: Pascal Laliberte Date: Mon, 27 Jan 2025 14:21:57 -0500 Subject: [PATCH] Docs: add notes on Turbo's Morphing, Reactivity, Dynamic Forms and Slow Pages (#1009) * docs/javascript: add notes on Turbo Morph, Updatable, scripts in the body * docs/javascript: tweak dynamic forms section * docs/javascript: clarify and re-work new sections --- bullet_train/docs/javascript.md | 40 ++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/bullet_train/docs/javascript.md b/bullet_train/docs/javascript.md index 0a53e1292..ed09921a9 100644 --- a/bullet_train/docs/javascript.md +++ b/bullet_train/docs/javascript.md @@ -2,7 +2,7 @@ Bullet Train leans into the use of [Stimulus](https://stimulus.hotwired.dev) for custom JavaScript. If you haven't read it previously, [the original introductory blog post for Stimulus from 2018](https://medium.com/signal-v-noise/stimulus-1-0-a-modest-javascript-framework-for-the-html-you-already-have-f04307009130) was groundbreaking in its time, and we still consider it required reading for understanding the philosophy of JavaScript in Bullet Train. ## Writing Custom JavaScript -The happy path for writing new custom JavaScript is to [write it as a Stimulus controller](https://stimulus.hotwired.dev/handbook/building-something-real) in `app/javascript/controllers` and invoke it by augmenting the HTML in your views. If you name the file `*_controller.js`, it will be automatically picked up and compiled as part of your application's JavaScript bundle. +The happy path for writing new custom JavaScript is to [write it as a Stimulus controller](https://stimulus.hotwired.dev/handbook/building-something-real) in `app/javascript/controllers` and invoke it by augmenting the HTML in your views. If you name the file `*_controller.js`, it will be automatically picked up and compiled as part of your application's JavaScript bundle. Be careful to [avoid adding scripts to the body of your pages (see below)](#avoid-scripts-in-the-body). ## npm Packages npm packages are managed by [Yarn](https://yarnpkg.com) and any required importing can be done in `app/javascript/application.js`. @@ -16,3 +16,41 @@ The resulting JavaScript bundle is output to the `app/assets/builds` directory w ## React, Vue.js, etc. We're not against the use of front-end JavaScript frameworks in the specific contexts where they're the best tool for the job, but we solidly subscribe to the "heavy machinery" philosophy put forward in [that original Stimulus blog post](https://medium.com/signal-v-noise/stimulus-1-0-a-modest-javascript-framework-for-the-html-you-already-have-f04307009130), and have no interest in actually supporting them. + +## Complex Screen Interactions + +For more complex screen interactions, we do recommend using features of Hotwire's Turbo framework, Turbo Frames in particular. + +Here are some important considerations: + +### Avoid Morphing for Page Refreshes (It Breaks Form Fields) + +We don't recommend using [Turbo's Morphing](https://turbo.hotwired.dev/handbook/page_refreshes) for refreshing whole screens, especially not when the screen contains form fields. That's because Turbo's Morphing works by comparing and modifying the DOM in a way that breaks JavaScript-created elements. Bullet Train's field partials, however, use third-party librairies, like those created by our `super_select`, our `date_field`, and even the Trix rich-text editor, which create their own elements via JavaScript. Use Turbo's Morphing sparingly. + +### Reactive Page Updates with CableReady::Updatable + +Bullet Train's answer to reactive page updates is a lightweight library called [CableReady::Updatable](https://cableready.stimulusreflex.com/guide/updatable.html). Rather than refreshing whole pages, it defines specific page regions that update themselves on model changes, across browser sessions. Look throughout your scaffolded `index` and `show` views for `cable_ready_updates_for` and in your models for the `enable_cable_ready_updates: true` option on `has_many` associations. By default, forms are not defined as updatable regions using CableReady::Updatable, for the same reasons explained above. + +### Dynamic Forms + +For creating dynamically-updated forms, Bullet Train introduces two powerful new patterns: the [_Dependent Fields Pattern_ and the _Dependent Fields Frame_](/docs/field-partials/dynamic-forms-dependent-fields.md). If you use the `address_field` partial, you'll see the pattern in action: changing the country will update the state and zip code fields. You can use these patterns to create complex, dynamically-updated forms. + +## Avoid Scripts in the Body + +If you experience slow Turbo interactions, check for script tags in the body of your pages. Following [Turbo's documentation](https://turbo.hotwired.dev/handbook/building#working-with-script-elements): + +❌ Don't place scripts in the body: + +```html + + + +``` + +✅ Instead, place them in the head with the `defer` attribute: + +```html + + + +``` \ No newline at end of file