Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch 2 #95

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ _public
_site
node_modules
tmp
package-lock.json
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.7.0
16
1 change: 0 additions & 1 deletion .ruby-version

This file was deleted.

20 changes: 20 additions & 0 deletions MIT-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2022 Basecamp

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ This repository backs the website living at https://turbo.hotwired.dev.

To work on it locally:

1. `npm install`
1. `npm run serve`
1. `yarn install`
1. `yarn serve`

## Copyright

Expand Down
13 changes: 9 additions & 4 deletions _source/handbook/01_introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,24 @@ description: "Turbo bundles several techniques for creating fast, modern web app

Turbo bundles several techniques for creating fast, modern, progressively enhanced web applications without using much JavaScript. It offers a simpler alternative to the prevailing client-side frameworks which put all the logic in the front-end and confine the server side of your app to being little more than a JSON API.

With Turbo, you let the server deliver HTML directly, which means all the logic for checking permissions, interacting directly with your domain model, and everything else that goes into programming an application can happen more or less exclusively within your favorite programming language. You're no longer mirroring logic on both sides of a JSON divide. All the logic lives on the server, and the browser deals just with the final HTML.
With Turbo, you let the server deliver HTML directly, which means all the logic for checking permissions, interacting directly with your domain model, and everything else that goes into programming an application can happen more or less exclusively within your favorite programming language. **You're no longer mirroring logic on both sides of a JSON divide**. All the logic lives on the server, and the browser deals just with the final HTML.

You can read more about the benefits of this HTML-over-the-wire approach on the <a href="https://hotwired.dev/">Hotwire site</a>. What follows are the techniques that Turbo brings to make this possible.
You can read more about the benefits of this HTML-over-the-wire approach on the [Hotwire site](https://hotwired.dev/). What follows are the techniques that Turbo brings to make this possible.

## Turbo Drive: Navigate within a persistent process

A key attraction with traditional single-page applications, when compared with the old-school, separate-pages approach, is the speed of navigation. SPAs get a lot of that speed from not constantly tearing down the application process, only to reinitialize it on the very next page.

Turbo Drive gives you that same speed by using the same persistent-process model, but without requiring you to craft your entire application around the paradigm. There's no client-side router to maintain, there's no state to carefully manage. The persistent process is managed by Turbo, and you write your server-side code as though you were living back in the early aughts – blissfully isolated from the complexities of today's SPA monstrosities!
**Turbo Drive gives you that same speed by using the same persistent-process model**, but without requiring you to craft your entire application around the paradigm. There's no client-side router to maintain, there's no state to carefully manage. The persistent process is managed by Turbo, and **you write your server-side code as though you were living back in the early aughts** – blissfully isolated from the complexities of today's SPA monstrosities!

This happens by intercepting all clicks on `<a href>` links to the same domain. When you click an eligible link, Turbo Drive prevents the browser from following it, changes the browser’s URL using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/History">History API</a>, requests the new page using <a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch">`fetch`</a>, and then renders the HTML response.

Same deal with forms. Their submissions are turned into `fetch` requests from which Turbo Drive will follow the redirect and render the HTML response.

During rendering, Turbo Drive replaces the current `<body>` element outright and merges the contents of the `<head>` element. The JavaScript window and document objects, and the `<html>` element, persist from one rendering to the next.

**Basically, it watches for link clicks and form submissions, performs them in the background, and updates the page without doing a full reload which makes navigation almost instant**.

While it's possible to interact directly with Turbo Drive to control how visits happen or hook into the lifecycle of the request, the majority of the time this is a drop-in replacement where the speed is free just by adopting a few conventions.


Expand Down Expand Up @@ -110,5 +112,8 @@ See the <a href="https://github.com/hotwired/turbo-ios">Turbo Native: iOS</a> an

## Integrate with backend frameworks

You don't need any backend framework to use Turbo. All the features are built to be used directly, without further abstractions. But if you have the opportunity to use a backend framework that's integrated with Turbo, you'll find life a lot simpler. [We've created a reference implementation for such an integration for Ruby on Rails](https://github.com/hotwired/turbo-rails).
You don't need any backend framework to use Turbo.

All the features are built to be used directly, without further abstractions. But if you have the opportunity to use a backend framework that's integrated with Turbo, you'll find life a lot simpler.

[We've created a reference implementation for such an integration for Ruby on Rails](https://github.com/hotwired/turbo-rails) and you also will find one for [Symfony](https://symfony.com/bundles/ux-turbo/current/index.html).
2 changes: 1 addition & 1 deletion _source/handbook/02_drive.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ By default, link clicks send a `GET` request to your server. But you can change

The link will get converted into a hidden form next to the `a` element in the DOM. This means that the link can't appear inside another form, as you can't have nested forms.

You should also consider that for accessibility reasons, it's better if use actual forms and buttons for anything that's not a GET.
You should also consider that for accessibility reasons, it's better to use actual forms and buttons for anything that's not a GET.


## Disabling Turbo Drive on Specific Links or Forms
Expand Down
13 changes: 10 additions & 3 deletions _source/handbook/03_frames.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Turbo Frames decompose pages into independent contexts, which can

# Decompose with Turbo Frames

Turbo Frames allow predefined parts of a page to be updated on request. Any links and forms inside a frame are captured, and the frame contents automatically updated after receiving a response. Regardless of whether the server provides a full document, or just a fragment containing an updated version of the requested frame, only that particular frame will be extracted from the response to replace the existing content.
Turbo Frames allow predefined parts of a page to be updated on request. **Any links and forms inside a frame are captured, and the frame contents automatically updated after receiving a response**. Regardless of whether the server provides a full document, or just a fragment containing an updated version of the requested frame, **only that particular frame will be extracted from the response to replace the existing content**.

Frames are created by wrapping a segment of the page in a `<turbo-frame>` element. Each element must have a unique ID, which is used to match the content being replaced when requesting new pages from the server. A single page can have multiple frames, each establishing their own context:

Expand Down Expand Up @@ -105,8 +105,15 @@ Note that the `<turbo-frame>` on `/emails/set_aside` does not contain a `src` at

## Lazy-Loading Frames

Frames that aren't visible when the page is first loaded can be marked with `loading="lazy"` such that they don't start loading until they become visible. This works exactly like the `lazy=true` attribute on `img`. It's a great way to delay loading of frames that sit inside `summary`/`detail` pairs or modals or anything else that starts out hidden and is then revealed.
Frames that aren't visible when the page is first loaded can be marked with `loading="lazy"` such that they don't start loading until they become visible thanks to [IntersectionObservers](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).

This works exactly like the `loading="lazy"` attribute on `img`. It's a great way to delay loading of frames that sit inside `summary`/`detail` pairs or modals or anything else that starts out hidden and is then revealed.

```html
<turbo-frame id="set_aside_tray" src="/emails/set_aside" loading="lazy">
<img src="/icons/spinner.gif">
</turbo-frame>
```

## Cache Benefits to Loading Frames

Expand Down Expand Up @@ -195,7 +202,7 @@ transforms navigations into ["advance" Actions][advance]:
Clicking the `<a rel="next">` element will set _both_ the `<turbo-frame>`
element's `[src]` attribute _and_ the browser's path to `/articles?page=2`.

**Note:** when render the page after refreshing the browser, it is _the
**Note:** when rendering the page after refreshing the browser, it is _the
application's_ responsibility to render the _second_ page of articles along with
any other state derived from the URL path and search parameters.

Expand Down
Loading