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

Explain how stream actions can be used within HTML #192

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

radanskoric
Copy link

@radanskoric radanskoric commented May 24, 2024

Resolves: hotwired/turbo#1258
Is paired with: hotwired/turbo#1263

As a consequence of the fundamental way in which Stream actions are implemented, they can also be executed by rendering them within any HTML that's included on the dom.

This can be useful in a variety of situations and I think it's valuable to document it.

Some examples:

Example: Executing side-effects with a Turbo frame response

You might have implemented a very elegant flow using pure Turbo Frames but there is just some small extra thing that needs to happen when the Turbo Frame loads. For example: update a counter or modify a small related piece that's outside the frame.

Depending on the details of your case you could use full page Turbo Morphing. If that won't work, you could refactor everything to just return a turbo streams response. The turbo frame response could become a turbo stream replace action and then you could add more actions.

But sometimes you want to make the minimal change needed to make it work. For that you could render the stream action for the side-effects inside the frame and rely on the feature we are discussing here. You achieve the side-effect with minimal changes and keep the main logic simple.

Example: Updating multiple parts of the page after following a GET link

For GET requests Turbo will not expect a Turbo streams response and if you do return a Turbo stream response (i.e. Content-type of text/vnd.turbo-stream.html instead of text/html), it will not attempt to process it as such. It will simply not work. The assumption is that you're either updating a full page or one frame.

This means that you can't use Turbo streams on get requests to update multiple parts of the page. However, you can insert streams into the primary HTML response to achieve the same.

Be very careful with this and think twice before using it. In most cases you probably don't need it but Ruby and Rails are all about sharp tools given to you to use wisely. This is another one.

Example: Executing JS on Page, Frame or plain AJAX load

In a lot of legacy applications you'll find inline <script> tags with the HTML code to be executed when HTML is loaded.

Stream actions inside HTML can eliminate any need for inline javascript. Anything you would want to do with a custom piece of javascript can be done more elegantly and cleanly with a Turbo Stream Action rendered inside the HTML.

For example, triggering frontend analytics tracking from server side or opening a UI widget (like a modal) on page load. This is not uncommon in legacy applications as sometimes the easiest way to get it working is to just use inline javascript. Instead, you could create a custom Stream Action, implement the logic on it, and then render just the stream action tag. The code will be cleaner and more maintainable.

This will also allow you to easily get to the point where you can configure the script-src Content-Security-Policy rule to disallow inline scripts, which is one of the biggest security wins CSP provides.

Verified

This commit was signed with the committer’s verified signature.
radanskoric Radan Skorić
As a consequence of the fundamental way in which
Stream actions are implemented, they can also be
executed by rendering them within any HTML that's
included on the dom.

This can be useful in a variety of situations.

Some examples:

You might have implemented a very elegant flow using pure Turbo Frames but there is just some small extra thing that needs to happen when the Turbo Frame loads. For example: update a counter or modify a small related piece that's outside the frame.

Depending on the details of your case you could use full page Turbo Morphing. If that won't work, you could refactor everything to just return a turbo streams response. The turbo frame response could become a turbo stream `replace` action and then you could add more actions.

But sometimes you want to make the minimal change needed to make it work. For that you could render the stream action for the side-effects *inside the frame* and rely on the feature we are discussing here. You achieve the side-effect with minimal changes and keep the main logic simple.

For GET requests Turbo will **not** expect a Turbo streams response and if you do return a Turbo stream response (i.e. Content-type of `text/vnd.turbo-stream.html` instead of `text/html`), it will not attempt to process it as such. It will simply not work. The assumption is that you're either updating a full page or one frame.

This means that you can't use Turbo streams on get requests to update multiple parts of the page. However, you can insert streams into the primary HTML response to achieve the same.

Be very careful with this and think twice before using it. In most cases you probably don't need it but Ruby and Rails are all about sharp tools given to you to use wisely. This is another one.

In a lot of legacy applications you'll find inline `<script>` tags with the HTML code to be executed when HTML is loaded.

Stream actions inside HTML can eliminate any need for inline javascript. Anything you would want to do with a custom piece of javascript can be done more elegantly and cleanly with a Turbo Stream Action rendered inside the HTML.

For example, triggering frontend analytics tracking from server side or opening a UI widget (like a modal) on page load. This is not uncommon in legacy applications as sometimes the easiest way to get it working is to just use inline javascript. Instead, you could create a custom Stream Action, implement the logic on it, and then render just the stream action tag. The code will be cleaner and more maintainable.

This will also allow you to easily get to the point where you can configure the [script-src Content-Security-Policy rule to disallow inline scripts](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_inline_script), which is one of the biggest security wins CSP provides.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

The documentation does not mention that Stream Action tags can be rendered inside any HTML
1 participant