Giter Site home page Giter Site logo

stimulusreflex / stimulus_reflex Goto Github PK

View Code? Open in Web Editor NEW
2.2K 26.0 166.0 5.39 MB

Build reactive applications with the Rails tooling you already know and love.

Home Page: https://docs.stimulusreflex.com

License: MIT License

Ruby 56.20% Shell 0.09% JavaScript 43.69% HTML 0.03%
stimulus reactive server-side-rendering ruby-on-rails actioncable rails stimulusreflex cableready ruby websocket

stimulus_reflex's Introduction

Welcome to StimulusReflex πŸ‘‹

downloads License: MIT Documentation
semantic-release Ruby Code Style JavaScript Code Style
Prettier-Standard StandardRB Tests


πŸŽ‰ An exciting new way to build modern, reactive, real-time apps with Ruby on Rails.

StimulusReflex eliminates the complexity imposed by full-stack frontend frameworks. And, it's fast.

It works seamlessly with the Rails tooling you already know and love.

Our goal is to help small teams do big things with familiar tools.

This project strives to live up to the vision outlined in The Rails Doctrine.

πŸ“š Docs

✨ Demos

πŸ‘©β€πŸ‘©β€πŸ‘§ Discord Community

Please join over 2000 of us on Discord for support getting started, as well as active discussions around Rails, Hotwire, Stimulus, Phlex and CableReady.

Stop by #newcomers and introduce yourselves!

πŸ’™ Support

Your best bet is to ask for help on Discord before filing an issue on GitHub. We are happy to help, and we ask people who need help to come with all relevant code to look at. A git repo is preferred, but Gists are fine, too. If you need a template for reproducing your issue, try this.

Please note that we are not actively providing support on Stack Overflow. If you post there, we likely won't see it.

πŸš€ Installation and upgrading

CLI and manual setup procedures are fully detailed in the official docs.

Rubygem

bundle add stimulus_reflex

JavaScript

There are a few ways to install the StimulusReflex JavaScript client, depending on your application setup.

ESBuild / Webpacker

yarn add stimulus_reflex

Importmaps

# config/importmap.rb

# ...

pin 'stimulus_reflex', to: 'stimulus_reflex.js', preload: true

Rails Asset pipeline (Sprockets):

<!-- app/views/layouts/application.html.erb -->

<%= javascript_include_tag "stimulus_reflex.umd.js", "data-turbo-track": "reload" %>

πŸ™ Contributing

Code of Conduct

Everyone interacting with the StimulusReflex project’s codebases, issue trackers, chat rooms and forum is expected to follow the Code of Conduct.

Coding Standards

This project uses Standard for Ruby code and Prettier-Standard for JavaScript code to minimize bike shedding related to source formatting.

Please run ./bin/standardize prior to submitting pull requests.

View the wiki to see recommendations for configuring your editor to work best with the project.

πŸ“¦ Releasing

  1. Always publish CableReady first!
  2. Update the cable_ready dependency version in stimulus_reflex.gemspec and package.json
  3. Make sure that you run yarn and bundle to pick up the latest.
  4. Bump version number at lib/stimulus_reflex/version.rb. Pre-release versions use .preN
  5. Run rake build and yarn build
  6. Run bin/standardize
  7. Commit and push changes to GitHub
  8. Run rake release
  9. Run yarn publish --no-git-tag-version
  10. Yarn will prompt you for the new version. Pre-release versions use -preN
  11. Commit and push changes to GitHub
  12. Create a new release on GitHub (here) and generate the changelog for the stable release for it

πŸ“ License

StimulusReflex is released under the MIT License.


Originally inspired by Phoenix LiveView. πŸ™Œ

stimulus_reflex's People

Contributors

andrewmcodes avatar assuntaw avatar codingitwrong avatar dark-panda avatar davidalejandroaguilar avatar dependabot[bot] avatar dixpac avatar dlt avatar erlingur avatar excid3 avatar existentialmutt avatar fig avatar github-actions[bot] avatar henrik avatar hopsoft avatar jasoncharnes avatar jonathan-s avatar joshleblanc avatar julianrubisch avatar konnorrogers avatar leastbad avatar marcoroth avatar matt-yorkley avatar nachiket87 avatar pinzonjulian avatar piotrwodz avatar rolandstuder avatar sztheory avatar user073 avatar websebdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stimulus_reflex's Issues

[WIP] AnyCable and Stimulus Reflex

I'm currently trying to get Stimulus Reflex working using AnyCable as a drop-in replacement for ActionCable. I'm running into some nasty worms. Ideas welcomed, especially from @palkan πŸ€“

Worm 1: ApplicationCable::Connection.env returns nil

We merge connection.env with our own constructed hash, resulting in us getting an undefined method 'merge' for nil:NilClass error.

I tried to cheat and just pass our constructed env in to ActionDispatch::Request.new() and it came back with Missing rack.input when we tell ActionDispatch to process the request.

I temporarily reverted the sample project to use standard ActionCable and normally rack.input contains an instance of Puma::NullIO. Unfortunately, this is precisely where my troubleshooting capacity tapers off dramatically.

Worm 2: session.id returns undefined method `fetch' for nil:NilClass

Long story short, if I hard-code a session ID from the database for testing purposes, it seems to work fine. So, we don't have access to the session.id when AnyCable is in the picture.

I don't have a lot of experience with other session stores, but I wonder if it's possible to fix this by switching to using Redis instead of cookies?

I did go through the AnyCable Troubleshooting page and reviewed "From Action to Any" but I could find no reference to these particular issues.

So, not quite drop-in yet but I am optimistic that Vladimir will know what to do!

Input field values sometimes remain

Bug Report

When removing a child record from a form, values sometimes remain in an input field.

Describe the bug

I have a form that includes nested child records. Each child record contains a "Remove" button that sets the _destroy attribute on the record to true and then sends serialized form data to the server for validation. The server correctly handles the request, and the html coming back from the server is correct. But input fields sometimes appear with data from the deleted child record still showing.

This seems to be a diffing problem. The HTML coming back from the server is right but is not correctly inserted into the page.

Expected behavior

Replaced HTML should be faithful to the rendered server response.

Screenshots or reproduction

Screen recording input fields

Versions

StimulusReflex

  • Gem: 3.1.3
  • Node package: 3.1.3

External tools

  • Ruby: 2.7
  • Rails: 6.0.2.2

Browser

  • Browser Safari <= Note: I have not been able to reproduce this bug in Chrome
  • Version 13.1

Cannot read property 'stimulusReflexController' of null

Bug Report

Describe the bug

I get the following error using the Generic Lifecycle Methods

beforeReflex
reflexSuccess
reflexError
afterReflex

Error:

stimulus_reflex.js:303 Uncaught TypeError: Cannot read property 'stimulusReflexController' of null
at HTMLDocument. (stimulus_reflex.js:303)
at dispatch (cable_ready.js:17)
at Object.morph (cable_ready.js:53)
at Object.perform (cable_ready.js:184)
at Subscription.received (stimulus_reflex.js:81)
at Subscriptions.notify (action_cable.js:546)
at Connection.message (action_cable.js:381)

The beforeReflex is called correctly, however it doesn't call the other methods (afterReflex and reflexSuccess). It just throws this error.

Because of this, the page spinner invoked in the beforeReflex method never goes away.

The error doesn't happen with selects (drop down list), only with text boxes and date time inputs (Flatpickr). I don't know how that could be related.

To Reproduce

Here's a gist with al the code involved in the issue: https://gist.github.com/LuisDeHaro/63956422dd015cddf1f11856a8f8abdd

Expected behavior

No error in the JavaScript console and the callbacks being called.

Screenshots or reproduction

Filtering:

stimulus_reflex.gif

Versions

StimulusReflex

  • Gem: 2.1.9
  • Node package: 2.1.9

External tools

  • Ruby: 2.5.3
  • Rails: 6.0.2.1
  • Node: v10.4.1

Browser

  • Browser: chrome
  • Version: 80.0.3987.132

Scoped register()?

One thing I learned from this so-so conference talk is that LiveView allows you to scope your MorphDom target to arbitrary elements.

In theory, that means you could have multiple reflex "widgets" going at once on the same page. We already have controller scoped reflexes working (at least in my PR! cough) and it seems like we could pass that context to CableReady instead of assuming that we want to replace the whole body tag.

DHH got everyone obsessed with REST but there's nothing stopping devs from setting up actions that render arbitrary HTML for a widget with render(layout: false).

Integration tests for stimulus-reflex

Since there are quite a few moving parts that gets this working I thought that perhaps it would be a good idea to have integration tests using cypress.io. One good reason for considering cypress.io is that you'll write tests against browser behaviour, which means that you'll see how the javascript and ruby code works together.

I wanted to open this issue to collect ideas on things that would need to get tested, edge cases that should work and perhaps haven't at some point etc.

These are some things that I thought of on top of my mind.

  • All possible actions work together with cable ready.
  • Defining a controller manually works properly
  • Only using html without defining a js controller works.

Docs: Clarify forcing DOM update with authentication

I followed https://docs.stimulusreflex.com/patterns#triggering-custom-events-and-forcing-dom-updates but it took me a while to figure out that since I've set up authentication per https://docs.stimulusreflex.com/authentication#encrypted-session-cookies, no one sees broadcasts to just StimulusReflex::Channel - I need to broadcast to e.g. StimulusReflex::Channel:abc123 where abc123 is a session ID.

But then I'd presumably need to loop over all sessions to broadcast to all users, which seems messy and a bad pattern.

I was going to make a doc PR, but I'm not sure what a good solution is here. I don't know Action Cable nor StimulusReflex well yet. Could it make sense for SR to (provide instructions to) set up both authed and non-authed channels/streams? Or would it be better if the docs said to set up a custom channel outside of SR for broadcasts to all users?

Non-morph operations are not executed by CableReady on errors

The event listener for stimulus-reflex:500 will short-circuit when it receives a broadcast that has no morph operations.

https://github.com/hopsoft/stimulus_reflex/blob/bd4ceb22df5fa18d3a1001afa7ffc25380ee14b7/javascript/stimulus_reflex.js#L58

500s do not return any morph operations, but you would still want CableReady to run the dispatchEvent operation to the error can be trapped.

To Reproduce

Cause an error to be raised by the reflex and attempt to trap it in an error event.

Expected behavior

The error should cause a stimulus-reflex:500 error event to be dispatched.

Versions

StimulusReflex

  • Gem: 3.0.0
  • Node package: 3.0.0

External tools

  • Ruby: 2.6.5
  • Rails: 6.0.2.2
  • Node: 10.19.0

Browser

  • Browser Chrome
  • Version 80.0.3987.163

Scoping when using Stimulus does not work as expected

Feature Request

When using SR with Stimulus, it should be possible to use scoping to return a portion of the page even if there is only one Stimulus controller in use for the entire page.

Is your feature request related to a problem?

I wouldn't call this a bug exactly, but the behavior is unexpected. Say I have a large form with a lot of data, and I want to do server-side validations. I want a single Stimulus controller that will handle field mapping and submission to the validation reflex class, but I don't want to return all the html for the entire form with each validation.

The docs for Scoping indicate that the first place SR looks to determine a root is "Is there a data-reflex-root on the element with the data-reflex?"

But when using Stimulus to talk to the Reflex model, there is no element with a data-reflex to reference. So I am forced to set my root at the element containing the controller, which is at the very top of the form.

Describe the solution you'd like

I would like the logic that determines scoping to allow me to set a data-reflex-root on an html element that doesn't necessarily include a Stimulus controller or a data-reflex action.

Client side call-backs?

I saw the closed issue around server-side callbacks, but I'm surprised nothing has been discussed around client callbacks.

In the todomvc sample, when you click on a todo item to initiate an edit there's no way to set the typing focus on the input that is inserted. You effectively have to click twice; I did try to suppress the autofocus attribute on the create new todo textbox, as I was concerned that having two autofocus textboxes would conflict. Unfortunately, even if the todo you clicked on is the only autofocus element, the browser doesn't seem to take action on it after it's been dynamically inserted.

This suggests that there should be a simple way to specify a callback to handle the sorts of visual effects that make no sense or are impossible to render in a template.

I feel pretty strongly that sending arbitrary JS to execute via websockets is almost certainly a major attack vector, and then haven't we just re-invented RJS? Let's not go there.

That means, to me at least, that it would be nice to be able to do two things:

I would love to be able to async/await a JS call to this.stimulate() in the controller for explicit reflex calls. And I would love to be able to specify a data-callback attribute for declarative reflexes that would execute a controller method with the element passed as a parameter.

This means that element.focus() is easily possible, as is those sexy, sexy yellow pulse glow effects that were all the rage when Basecamp came out in 2004. Gosh, don't you just miss Prototype sometimes? ;)

Install StandardJS linter

After much blinking and head-desking, I finally figured out the linting situation. It wasn't what was happening... it was what isn't happening.

I learned about StandardRB through the actions set up on this project. Not as far along, but promising and I used a post-save hook to set it up to run in VSCode because StandardRB not available as an extension yet. bundle exec standardrb --fix $(file) for great success.

However, I've been thoroughly flummoxed by the JS lint situation, because StandardJS is so opinionated about (no) semi-colons. What I failed to grok until just now is that my brain assumed two incorrect things: that Prettier only tackled column-width and line-breaking, and that we had StandardJS set up in our post-commit and post-pull-request callbacks on GH.

I was wrong about Prettier - it inserts "missing" semi-colons and, well, I wish you could see my face the moment I realized that when GH's Actions interface said "Run Standard Lints" it meant only StandardRB.

πŸ€•

Javascript Standard is a thing of beauty. [I find] Ruby code lends itself to readability, but JS's obsession with using nested object notation (it used to be far, far worse with nested anonymous function hell) makes the Prettier + Standard combo the first thing I set up in any JS project. There are many VS Code plugins; I recommend Prettier-Standard.

Anyhow: can we please, please, pretty please set up StandardJS to run after Prettier? This will, predictably, solve the semi-colon thing.

Would it work with Webhooks updates

Hey not an issue here more of a question.

I was wondering if I could use Reflex to update in realtime my UI when I receive a webhook?

I am working on several Stripe SCA upgrade projects and once the payment is sent then my success page needs to refresh when I receive the Stripe confirmation webhook and that I have fulfilled the order.
Currently, I am doing this with either a simple polling or with action cable.

Would Reflex work for such use case?

Thanks for this promising project

Create Rails generators

Requirements

The generator should support 2 primary objectives.

  1. Setup and prepare the application to use StimulusReflex
  2. Support generating new Reflexes

Setup

bundle exec rails stimulus_reflex:install

This will check for the existence of Stimulus in the project and will also create the following files.

These files will include basic boilerplate and establish some patterns and practices that developers can follow to build their own StimulusReflex features.

Generators

NOTE: Generator args should behave similar to other Rails generators.

bundle exec rails generate stimulus_reflex demo

This above command will generate 2 files.

  • app/javascript/controllers/demo_controller.js
  • app/reflexes/demo_reflex.rb

The files will include basic boilerplate to help developers get started.

Optional Generators

bundle exec rails generate stimulus_reflex:controller demo

This above command will generate 1 file.

  • app/javascript/controllers/demo_controller.js
bundle exec rails generate stimulus_reflex:reflex demo

This above command will generate 1 file.

  • app/reflexes/demo_reflex.rb

Installer fails on fresh Rails 5.2.3 app w/ webpacker 3.6

Bug Report

I have a legacy Rails app running on 5.2.3 that I wanted to try stimulus_reflex on, so I decided to first run a test on a fresh install, but the installer failed.

Describe the bug

The installer fails because no index.js file is present:

Errno::ENOENT: No such file or directory @ rb_sysopen - {...}/stimulus_reflex_test/app/javascript/controllers/index.js
bin/rails:4:in `<main>'

To Reproduce

mkdir stimulus_reflex_test
cd stimulus_reflex_test/
echo "source 'https://rubygems.org'" > Gemfile
echo "gem 'rails', '5.2.3'" >> Gemfile
bundle install
bundle exec rails new . --force --skip-bundle
echo "gem 'webpacker', '~> 3.5'" >> Gemfile
bundle update
bundle exec rails webpacker:install
bundle exec rails webpacker:install:stimulus
bundle add stimulus_reflex
bundle exec rails stimulus_reflex:install

Expected behavior

The installer should complete

Versions

Output of bin/rails webpacker:info:

Ruby: ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
Rails: 5.2.3
Webpacker: 3.6.0
Node: v10.15.3
Yarn: 1.19.1

@rails/webpacker:
stimulus_reflex_test@ {...}/stimulus_reflex_test
└── @rails/[email protected]

Is bin/webpack present?: true
Is bin/webpack-dev-server present?: true
Is bin/yarn present?: true

Make the javascript in stimulus-reflex websocket agnostic

Feature Request

I'd like the javascript part of stimulus-reflex to become websocket agnostic. Ie, right now it is coupled with how websockets work for specifically for rails (for good reason, you use rails, and this grew out of that).

I'm primarily working with python and it'd be nice to be able to use the same approach that is used here and use it in the python world.

Do you have any thoughts around this?

This seems tangentially related to #46

Unable to register the ActionCable Consumer

Bug Report

I was using StimulusReflex successfully, but it has suddenly started giving me this error in console: "StimulusReflex was unable to register the ActionCable consumer. Don't worry, everything should still work."

I'm worried. Any idea what's going on here?

ActionCable npm package renamed

Bug Report

Rails 6.0 renamed the actioncable npm package to @rails/actioncable. We experience errors in production when precompiling our assets due to conflicts between these two versions of ActionCable.

Describe the bug

The npm package name for ActionCable needs to be updated. Not sure how this is done when it comes to renaming npm packages, as you may want compatibility with both the new @rails/actioncable package as well as the older actioncable package.

To Reproduce

Use Rails 6 and @rails/actioncable instead of actioncable.

Expected behavior

Shouldn't bomb out.

Screenshots or reproduction

N/A

Versions

StimulusReflex

  • Gem: 2.2.3
  • Node package: 2.2.3

External tools

  • Ruby: 2.6.5
  • Rails: 6.0.2.2
  • Node: 10.19.0

Browser

  • Browser Chrome
  • Version 80.0.3987.149

TypeScript typing support

Feature Request

Is your feature request related to a problem?

Hi πŸ‘‹!

Stimulus supports TypeScript, but it appears that StimulusReflex does not. Offering officially supported types would be really great.

I'm creating this issue as a conversation about how involved the library maintainers would want to be in supporting TypeScript.

Describe the solution you'd like

Here is a summary of the options that I've seen other open source projects explore, based on the general TypeScript community's preference:

  1. Library is officially written in TypeScript and the types are built in (this is what Stimulus does)
  2. Officially supported types for the existing JS code are included in the package so it can "just work" for TS users
  3. Official support from library maintainers in writing DefinitelyTyped community types - users can install @types/stimulus_reflex
  4. Library maintainers are completely hands off, don't care about TypeScript at all, and it's up to the community to sort it out.

Thoughts?

Custom Stimulus schema breaks Reflex

Describe the bug

Reflex ignores the schema set in Stimulus. It assumes Stimulus will always use the default schema.

Line 220 in javascript/stimulus_reflex.js

 if (actionValue) element.setAttribute('data-action', actionValue)

Hardcodes the 'data-action' attribute.

In our project we use a custom schema as follows:

const application = Application.start(document.documentElement, {
  controllerAttribute: 'data-controller',
  actionAttribute: 'data-do',
  targetAttribute: 'data-target'
});

Because we had a conflict with another plugin, cropperjs.

Feedback would be appreciated.

Reflex not binding to ajax loaded content

Describe the bug

Reflex not binding to Ajax loaded content that is loaded onto page from Rails UJS remote call.

To Reproduce

  • Use remote UJS call to load html onto page
  • New html content has data-reflex attribute
  • Reflex is not binding

Expected behavior

Reflex should bind to ajax loaded content

Versions

StimulusReflex

  • stimulus_reflex 3.1.3

External tools

  • Ruby: 2.6.3
  • Rails: 6.0.2
  • Turbolinks 5.2.1

Browser

  • Chrome

Cannot read property 'removeEventListener' of undefined after updating to 3.1.0

Bug Report

NOTE: I am no JS pro, so I may perfectly well be missing something obvious.

Describe the bug

After updating my code from stimulus_reflex 3.0.0 to 3.1.0 in both the gem & node, I am getting errors on a page that used to work.

To Reproduce

I do not have a clean repro case yet, just stack trace that appears to be entirely in the JS:

TypeError: can't access property "removeEventListener", socket is undefined consumer.js:38
    registerConsumer consumer.js:38
    createSubscription stimulus_reflex.js:78
    register stimulus_reflex.js:191
    StimulusReflexController stimulus_reflex.js:214
    construct self-hosted:1871
    Controller definition.js:43
    Context context.js:9
    fetchContextForScope module.js:55
    connectContextForScope module.js:37
    scopeConnected router.js:100
    elementMatchedValue scope_observer.js:55
    tokenMatched value_list_observer.js:54
    tokenMatched token_list_observer.js:82
    tokensMatched token_list_observer.js:69
    forEach self-hosted:225
    tokensMatched token_list_observer.js:68
    elementMatchedAttribute token_list_observer.js:49
    elementMatched attribute_observer.js:59
    addElement element_observer.js:151
    processAttributeChange element_observer.js:84
    processMutation element_observer.js:67
    processMutations element_observer.js:60
    mutationObserver element_observer.js:12
    (Async: MutationCallback)
    ElementObserver element_observer.js:11
    AttributeObserver attribute_observer.js:9
    TokenListObserver token_list_observer.js:8
    ValueListObserver value_list_observer.js:7
    ScopeObserver scope_observer.js:11
    Router router.js:10
    Application application.js:159
    start application.js:163
    js index.js:8
    Webpack 5

The Stimulus Reflex code on the page is very close to the Gravatar example in Expo (just modified to use Libravatar instead). No custom controller involved.

Versions

StimulusReflex

  • Gem: 3.1.0
  • Node package: 3.1.0

External tools

  • Ruby: 2.6.4
  • Rails: 6.0.2
  • Node: 13.12.0

Browser

  • Browser Firefox
  • Version 77
  • Browser Chrome
  • Version 80

(Repros in both)

Time for introducing a develop branch?

As the project continues to pick up steam, I suspect that it will become increasingly difficult to manage the flurry of feature, release and hotfix branches without some kind of agreed-upon structure.

I was re-reading the classic A successful Git branching model and would like to propose that we move towards adopting this model, starting with a develop branch. Feature branches are created from develop and merged back into it.

One of the first motivations I have is around our evolving documentation efforts. Right now, GitBook is connected and making commits directly on master. Those commits are live immediately, which causes chronology issues for features that haven't been publicly released yet.

Possibly making the question rhetorical... the best idea I had was to create a 2nd GitBook project and point it to the develop branch. We could continue to do our modifications using the GitBook UI and the results would be a preview of what is soon to be released (hopefully) to master. Of course, once develop is merged into master, GitBook should now reflect up-to-date documentation for the now-current new release.

Anyhow, @hopsoft @andrewmcodes what do you folks feel about this?

Webpack compilation fails with rails/webpacker 3.6

Bug Report

Before you go on reading: I'm not even sure stimulus_reflex is intended to be backwards compatible. If that isn't so, feel free to close.

With the temporary fix mentioned in #81 and #82 I was able to install stimulus_reflex,
but the pack couldn't be compiled.

Describe the bug

Apparently babel-plugin-transform-object-rest-spread doesn't like the line

controller.StimulusReflex = { ...options, channel, room }

Output of bin/rails webpacker:compile

ERROR in ./node_modules/stimulus_reflex/stimulus_reflex.js
Module parse failed: Unexpected token (168:32)
You may need an appropriate loader to handle this file type.
|   const channel = 'StimulusReflex::Channel'
|   const room = options.room || controller.element.dataset.room || ''
|   controller.StimulusReflex = { ...options, channel, room }
|   extendStimulusController(controller)
|   createSubscription(controller)
 @ ./app/javascript/packs/application.js 14:0-45

To Reproduce

Set up a rails 5.2 application as outlined here: #81 and try to bin/rails webpacker:compile

Expected behavior

The pack should compile.

Versions

Ruby: ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
Rails: 5.2.3
Webpacker: 3.6.0
Node: v10.15.3
Yarn: 1.19.1

@rails/webpacker:
stimulus_reflex_test@ {...}/stimulus_reflex_test
└── @rails/[email protected]

Is bin/webpack present?: true
Is bin/webpack-dev-server present?: true
Is bin/yarn present?: true

Add GH templates

With 150+ stars on this projects it may be worth adding the following to help adoption and maintenance:

  • Issue templates
  • PR template
  • Code of Conduct

Thoughts? Happy to open a PR to add some or all of the above for review.

Testing Integrations

Feature Request

As we all know, the most important part of developing things the right way is proper testing! From what I could find in the docs, this library doesn't add any test helpers or examples of testing a Reflex.

  1. Are there any helpers with testing that reflexes are doing what they should?
  2. If not should we build some?

Describe the solution you'd like

I think both test/unit and rspec integrations would be useful to and cover the majority of the community

If not, at least some examples in the docs of how to test

Allow extractElementAttributes to use a checkbox list

Feature Request

extractElementAttributes for the moment returns multiple values for select tags with multiple: true:

https://github.com/hopsoft/stimulus_reflex/blob/480ee76dccf4ddc212602d1c3dee01216b6369ab/javascript/attributes.js#L37

A common scenario is to use a checkbox list for an association collection, as in collection_check_boxes:

https://devdocs.io/rails~6.0/actionview/helpers/formoptionshelper#method-i-collection_check_boxes

It would be nice if SR supported that out of the box.

Describe the solution you'd like

The hidden complexity lies in the fact that we'd have to consider multiple elements in extractElementAttributes, not just the one triggering the reflex. Still I think a library such as SR should take on that complexity instead of imposing it on the back end developer.

Specifically, I discovered this shortage when working on the permalink expo example and trying to employ a button group: https://github.com/hopsoft/stimulus_reflex_expo/pull/26/files#diff-23c58647594fccfb30d0b54554851d59R15

Server signing salt

One thing I noticed that Phoenix LiveView has implemented is a signed salt to verify the authenticity of requests and prevent bad actors.

https://github.com/phoenixframework/phoenix_live_view/#installation

This seems like something handled by ActionCable, but if not, it's probably a good idea to consider something like this, given that many actions could trigger destructive changes via CRUD-like reflexes.

Trying to get this working in Rails 6

In Rails 6, there is no app/assets/javascripts folder, so I can't figure out how to get the dependency on stimulus_reflex properly referenced. What's the best way to import/require from within a gem? I checked and it doesn't seem like there is a stimulus_reflex package on npm, which might be the magic solution.

I could grab the js from the gem and include it directly, but that seems super gauche.

If you have even a single line of require() syntax (including the .start() call, if any) I would be indebted.

out-of-band Reflex updates

I want to demonstrate triggering the delivery of a Reflex payload from outside of the request loop. That could be in a few milliseconds or an arbitrary amount of time later. The key detail is that it's generated in response to an external event such as a webhook or notification.

I figured that a good teaching vehicle would be an ActionJob. I can send in the same parameters that are used to call channel.receive() + the stream_name.

Except, wait... you hit logical flaw number one: when you create an instance of StimulusReflex::Channel, you need to pass it a Connection so that the render_page method has a valid ActionDispatch::Request object.

Huh! Okay, what are my other options? Well, I could make use of the new ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message }) thing and then call ActionCable.server.broadcast directly.

The problem there is that I'd have to call both the reflex action AND the controller action in order to properly replicate the instance variables for the template. eff that

Which brings me full circle to questioning my original premise for wait_for_it. However, maybe the fact that it could serve literally the wrong page (if the user has navigated away) is a sign that this is Not The Right Way To Do This.

Where I landed was a different idea altogether. We're already talking about adding the capacity to do a Turbolinks/classic browser redirect operation. What if we used [the same or a similar mechanism] to send a message to the client that says: hey, if you're still on URL X, there is a potentially newer version of the page which you could refresh.

The advantages of this approach are that it gives implementation flexibility to the developer in terms of handling how/when/if they want to handle out-of-band updates, but also that a request coming from the client over the existing connection is going to have a valid connection + stream_name and all of the other important details otherwise absent.

The only other idea I had was that perhaps there is a unique ID attached to each connection object, and that this ID could be passed into the ActionJob and later used to obtain a reference to the connection for purposes of instantiating a new StimulusReflex::Channel.

Alright, I'm spent. Who has opinions?! 😈

Setup & Quick Start guide from scratch results in showstopping error

Bug Report

Describe the bug

Following the "Setup" and "Quick Start" guide process exactly results in breaking socket is undefined error in the JS console in Firefox, and Uncaught TypeError: Cannot read property 'removeEventListener' of undefined` in Chrome (both raised by same line of code).

It looks like StimulusReflex is looking for something on the ActionCable JS object that doesn't exist. Is this because of #132 maybe? Or is there another dependency or import missing from the instructions?

To Reproduce

Following the setup guide exactly and then using the sample code results in socket is undefined in the JavaScript console.

# these are the setup instructions
rails new myproject --webpack=stimulus # Rails 6.0.2.2
cd myproject
bundle add stimulus_reflex
bundle exec rails stimulus_reflex:install
# make a controller
bin/rails g controller pages index

Add the sample code from the quickstart guide to the pages/index.html.erb.

bin/webpack-dev-server
bin/rails s

Finally, load localhost:3000/pages/index and observe that the JavaScript console says socket is undefined in Firefox (or the Chrome error).

Expected behavior

There's no error and it loads fine.

Versions

StimulusReflex

  • Gem: 3.1.0
  • Node package: 3.1.0

External tools

  • Ruby: ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]
  • Rails: 6.0.2.2
  • Node: v10.15.3

Browser

  • Browser: Firefox 74.0.1
  • Browser: Chrome 79.0.3945.130

Formatting issues on README

Bug Report

Describe the bug

Looks like there are some formatting issues on the README.

ex:

{% code-tabs %} {% code-tabs-item title="app/javascript/controllers/index.js" %}

Proposed Solution

Maybe we should pull some stuff out of the README now that we are using gitbook. We can move a lot of this into the docs/ folder, which would make updating the gitbook updates easier.

Thoughts @hopsoft?

SR cannot re-render authenticated devise routes

Failed to re-render URL undefined method 'authenticate' for nil:NilClass

Also reports of issues with the validated? method.

To Reproduce

Attempt to use SR on a URL that is access-controlled by an authenticated route:

# routes.rb
authenticated :user, lambda { |u| u.has_role? :admin } do
  get "doh", to: "home#doh"
end

Expected behavior

SR should be able to work with devise authenticated routes.

Screenshots or reproduction

https://docs.stimulusreflex.com/setup#devise

Versions

StimulusReflex

  • Gem: 2.1.5

External tools

  • Ruby: 2.6.5
  • Rails: 6.0.1

routing reflexes to controllers

Recently I have been intensely focused on building a series of increasingly more sophisticated example StimulusReflex applications (hopefully) destined for the Expo site. Aside from (hopefully) being instructive and fun to make, it's very important for library builders to play the role of end-users and dogfood everything on a regular basis. Sometimes you surface issues in the mouthfeel of the API.

One of the most powerful recent additions to StimulusReflex is the callback system. @hopsoft and I worked very hard to make everything behave in a rational, predictable manner even while behind the scenes some aspects of this goal were tricky to implement.

The problem I keep running into starts with good intentions. I'll be designing an interface that has multiple widgets in play, and instead of wrapping the whole body in a giant Stimulus controller, I'll put data-controller on the parent elements of the appropriate widgets.

Here's the thing: if a data-reflex occurs inside of the child hierarchy of the parent element that has the data-controller attribute, you have the opportunity to write callbacks which fire when those reflex events are triggered. But if you want to put a data-reflex for a controller elsewhere on your interface, StimulusReflex doesn't currently have any mechanism for firing callbacks.

What I've found, as a library user, is that first I'll spend time trying to find an elegant solution; then I'll end up with two separate controllers that, over time, gain more and more identical functionality; finally, I'll just move the controller to the highest point of the DOM I can access and consolidate the code into one controller. I've now created a single working (yay) controller that is likely to only work on a single interface (sigh), instead of two relatively flexible controllers that I can reuse on many pages.

I'm wondering if there's a way that we could opt-in to callbacks even if we're not under the hierarchy of the data-controller by pointing to an element via a CSS selector. For example:

<div id="example" data-controller="example">
  <button data-reflex="click->ExampleReflex#no_problem">No Problem!</button>
</div>

<button data-reflex="click->ExampleReflex#hear_me" data-reflex-controller="#example">I'm a real boy!</button>

Scoped onClick event

Just found out about this wonderful gem; I'm having some issues understanding how scoping works

this example works perfectly., but given the following :

<div data-controller="example" data-reflex-root=".btn,.output">
  <a
      href="#" class='btn'
      data-count="<%= @count.to_i %>"
      data-step="1" data-reflex="click->ExampleReflex#do_stuff">
      Increment
  </a>
  <div class='output' ><%= @count.to_i %></div>
</div>

The expected change happens only once : the .output div content get from 0 to 1 at first click.
Clicking further, the data-count params remains at 0. I'm having hard time understanding how to get it to work; is there an obvious error to correct ?


Going a bit further, how should things be set to make elements independent ? Given this example :

<a href="#" class='btn' data-count="<%= @count1.to_i %>" data-step="1" data-reflex="click->ExampleReflex#counter1">
  <%= @count1.to_i %>
</a>

<a href="#" data-count="<%= @count2.to_i %>" data-step="1" data-reflex="click->ExampleReflex#counter2">
  <%= @count2.to_i %>
</a>

and without further setup, a click on one element would reset the other, and vice versa. Is such approach available in the context your provide in this gem ? Is persistence the only way to go ? Does it requires extra js setup ?

thx a lot in case you have time claryfying a bit how to use it all

ActiveJob integration example

Can anyone provide example of integration activejob in reflex flow? Something as simple as possible. e.g. re-render template in job?

Error during install: "File unchanged! The supplied flag value not found! app/javascript/packs/application.js"

Hi,

Getting this:

15:21:49 henrik@devbox remit  master*$ bundle exec rails stimulus_reflex:install
/home/henrik/.devbox/code/remit/gems/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/stack.rb:37: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/home/henrik/.devbox/code/remit/gems/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/static.rb:110: warning: The called method `initialize' is defined here
/home/henrik/.devbox/code/remit/gems/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/stack.rb:37: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/home/henrik/.devbox/code/remit/gems/gems/actionpack-6.0.2.1/lib/action_dispatch/middleware/static.rb:110: warning: The called method `initialize' is defined here
Appending Stimulus setup code to /Users/henrik/Projects/barsoom/remit/app/javascript/packs/application.js
File unchanged! The supplied flag value not found!  app/javascript/packs/application.js
Creating controllers directory
       exist  app/javascript/controllers

This is a freshly generated Rails 6.0.2 app on Ruby 2.7.0 (thus the warnings…).

Running on an Ubuntu VM inside macOS.

I may have run the install command more than once if that has any relevance.

too many afterReflex/reflexSuccess callbacks

Bug Report

Describe the bug

If a reflex is scoped to update multiple selectors, the reflexSuccess and afterReflex callbacks are being executed once per morph operation instead of once per cable_ready payload.

To Reproduce

Ensure afterReflex writes to the console log. Call a reflex that is scoped to two or more selectors.

Expected behavior

Each reflex action should fire callbacks one time.

Versions

StimulusReflex

  • Gem: 2.1.2

External tools

  • Ruby: 2.6.4
  • Rails: 6.0.0

Browser

  • Chrome 77

Pass element tagname in reflex

Feature Request

it would be feasible to access the tagname of the DOM element that triggered the reflex (and potentially other properties as well?)

Is your feature request related to a problem?

in some context it occured to me that it would be feasible not only to have checked, selected and value(s) attributes, but also to be able to discern between SELECT, OPTGROUP etc. etc.

Describe the solution you'd like

Pass the element tagname through the ActionCable connection up to the reflex

Additional context

If anyone could point me to the relevant parts of the source, I'd be happy to prepare a PR

Slack Community

Feature Request

Please create a Slack Community. Would love to join in this wonderful community.

Best Regards
Andrew

Consider removing Nokogiri as a dependency

I'm curious if removing Nokogiri and the code that parses the body before wire transfer is actually worth it. It may be faster to simply send everything, including the HEAD, back over the wire rather than parse the DOM tree simply to extract the body. I want to test this to see which approach is actually faster.

Move ActionCable room configuration to controller registration

Feature Request

Problem

Holding ActionCable room configuration in the DOM is problematic and may pose a security risk.

Solution

Remove the ability to configure rooms via data attributes in the DOM and make this one of the options supported by register.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.