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

CableReady installer #179

Closed
wants to merge 3 commits into from
Closed

CableReady installer #179

wants to merge 3 commits into from

Conversation

julianrubisch
Copy link
Contributor

@julianrubisch julianrubisch commented Jan 31, 2022

I've taken a first stab at the new unified CableReady Installer, and borrowed heavily from https://github.com/hotwired/turbo-rails/blob/main/lib/tasks/turbo_tasks.rake

Let me break it down for you a bit:

  • basically we have 2 install tasks, cable_ready:install:importmap, and cable_ready:install:node, where the main cable_ready:install task switches on the presence of an importmap.rb file
  • both installers do a sanity check if Redis and ActionCable are available, and optionally asks the user if Redis should be installed (https://github.com/stimulusreflex/cable_ready/pull/179/files#diff-e469da9bc01523658da7d880f0c454118061110611e92e21c3d69e0232ae983aR8)
  • the installers then do their pin/yarn add actions
  • finally, initializing CableReady in the application's entrypoint. I've taken my own experience as a heuristic here:
    1. `import CableReady from "cable_ready"
    2. if a ./channels/index.js is present, we're likely in a webpacker setup. Use that consumer to initialize CR.
    3. if no such channels index is present, we can fall back on using the cable module exposed by @hotwired/turbo-rails.
    4. else ask the user to do it manually.

I've tested many scenarios locally, but doing a bit of testing certainly wouldn't hurt 🙏

@julianrubisch julianrubisch marked this pull request as ready for review February 1, 2022 08:56
@Matt-Yorkley
Copy link
Contributor

Matt-Yorkley commented Feb 2, 2022

Hey 👋

I've been playing with CR and SR on a greenfield app that's using Vite and ran into a couple of issues with some of the install tasks for both. I took some rough notes:

The helpers_generator here fails with Vite:

main_folder = defined?(Webpacker) ? Webpacker.config.source_path.to_s.gsub("#{Rails.root}/", "") : "app/javascript"
filepath = [
"#{main_folder}/controllers/index.js",
"#{main_folder}/controllers/index.ts",
"#{main_folder}/packs/application.js",
"#{main_folder}/packs/application.ts"
]
.select { |path| File.exist?(path) }
.map { |path| Rails.root.join(path) }
.first

It assumes the main_folder is "app/javascript" and the entrypoint directory is named "packs".

A slight adjustment makes it work for either:

    main_folder = defined?(Webpacker) ? Webpacker.config.source_path.to_s.gsub("#{Rails.root}/", "") : "app/javascript"
++  main_folder = "app/frontend" if defined? ViteRuby

    filepath = [
      "#{main_folder}/controllers/index.js",
      "#{main_folder}/controllers/index.ts",
      "#{main_folder}/packs/application.js",
      "#{main_folder}/packs/application.ts",
++    "#{main_folder}/entrypoints/application.js",
++    "#{main_folder}/entrypoints/application.ts"
    ]

There are some similar install tasks in SR that also break in Vite but just need a very slightly different path. And there's this Webpacker-specific line that gets added during setup:

StimulusReflex.debug = process.env.RAILS_ENV === 'development'

which throws an error with Vite. It works with a slight (Vite-specific) adjustment:

--StimulusReflex.debug = process.env.RAILS_ENV === 'development'
++StimulusReflex.debug = import.meta.env.DEV

I'm wondering if these could be generalised a bit. I haven't tried with jsbundling-rails, but it also uses ESBuild so I assume it would be similar to Vite in regards to default paths..?

@Matt-Yorkley
Copy link
Contributor

Obviously it's annoying AF having to cater to Webpacker / Shakapacker(!) / Importmaps / jsbundling-rails / Vite, but from the DX side of things it's really nice if the install tasks Just Work™ without any issues 🤷‍♂️

@julianrubisch
Copy link
Contributor Author

Yeah, so this PR is about the main CR installer (which even doesn’t exist yet!)

shall we pull out your comment into an issue?

@julianrubisch
Copy link
Contributor Author

Closing in favor of #233

marcoroth added a commit that referenced this pull request Feb 13, 2023
This PR is the CableReady counterpart to stimulusreflex/stimulus_reflex#610.

I'm not going to rehash everything discussed in the SR installer; it is a modified subset of the same system. There are some small differences but great pains have been taken to keep everything consistent. **It is possible to install CableReady, and then add StimulusReflex to the project and install StimulusReflex at a later date.** Note that if you try to run the CableReady installer when StimulusReflex is in your project, it will exit and tell you to run the SR installer; 

It supports all major bundlers in their default configuration:

Rails 6.1: webpacker 5.4.3, shakapacker, vite
Rails 7: importmap, esbuild, shakapacker, vite

I've adapted the `cable_ready:channel` generator to work with the new installer. The `cable_ready:initializer` generator has been removed in favor of the installer.

```bash
rails cable_ready:install # fully automatic detections, with prompts
rails cable_ready:install esbuild # specify a bundler
rails cable_ready:install entrypoint=app/frontend webpacker # install with webpacker 5.4.3 in app/frontend
rails cable_ready:install:step action_cable yarn bundle # re-run one or more steps
rails cable_ready:install:restart # wipe state and restart install

rails cable_ready:install uncomment=true # uncomment any necessary includes that have been commented
rails cable_ready:install spring=false # do not remove spring (equivalent to answering `n`)
rails cable_ready:install trace=true # debug install process with full stack trace

rails cable_ready:install:step mrujs # install mrujs
rails cable_ready:install:step compression # monkey patch Action Cable to compress WS traffic with deflate

# full fat install with zero interactive prompts, suitable for scripting
rails cable_ready:install esbuild entrypoint=app/javascript uncomment=true spring=true
```

## Why should this be added

We really need to up our installation and integration game to overcome the emotional barrier people often feel when comparing us against a built-in solution. The more we can make installing CR feel like ordering a Big Mac combo, the less water "golden path" arguments hold.

Closes #179 with massive kudos to @julianrubisch for showing me how to structure an installer.
Closes #180 with apologies to @Matt-Yorkley for the delay
Fixes #130 with a hat-tip to @julianrubisch 
Fixes #131

-----

Co-authored-by: Marco Roth <marco.roth@intergga.ch>
Co-authored-by: Julian Rubisch <julian@julianrubisch.at>
marcoroth added a commit to stimulusreflex/stimulus_reflex that referenced this pull request Feb 19, 2023
With sincere and genuine apologies for how long this has been in the
oven, here is my best attempt at providing a luxe, single-command
install task for SR. It builds directly on the techniques and outputs of
preceding foundational efforts by both
[Julian](stimulusreflex/cable_ready#179) and
[Marco](https://github.com/stimulusreflex/stimulus_reflex/tree/v3.5-installer).

It supports all major bundlers in their default configuration:

Rails 6.1: webpacker 5.4.3, shakapacker, vite
Rails 7: importmap, esbuild, shakapacker, vite

The installer is divided into steps which are designed to be either
generic or highly specific to one of the bundlers.

The installer uses temporary files to maintain state; one of the major
wins is that it means the setup process can fail, they can fix an issue,
and task is smart enough to resume where they left off. It will also
survive a reboot, which is something you cannot say about environment
variables.

One of the things I'm most excited about is the new `example` the
install task offers to generate. Instead of just a Reflex class and
Stimulus controller, I realized that there's huge value in creating
something that people can just run out of the box. This creates a
controller, fully self-contained view and root. Right now, it's super
minimalist, but I talk more in the Why section below about my vision for
this.

I stash an MD5 hash of `Gemfile` so that we only need to run `bundle` if
something changes. Likewise, I actually dynamically rebuild
`package.json` based on added dependencies, development dependencies and
removed dependencies. This allows us to run the dreaded, slow AF `yarn`
build process 0 or 1 times, instead of 3 times since there is no way to
combine these three operations on the command line.

I make efforts to create or modify most files in-place, but for files
like the `{entrypoint}/controllers/index.js` where it's likely they made
changes, it copies the existing file to `.bak`, generates a "perfect"
new file, and then gives them a list of such replacements at the end.

```bash
rails stimulus_reflex:install # fully automatic detections, with prompts
rails stimulus_reflex:install esbuild # specify a bundler
rails stimulus_reflex:install entrypoint=app/frontend webpacker # install with webpacker 5.4.3 in app/frontend
rails stimulus_reflex:install:step action_cable yarn bundle # re-run one or more steps
rails stimulus_reflex:install:restart # wipe state and restart install

rails stimulus_reflex:install uncomment=true # uncomment any necessary includes that have been commented
rails stimulus_reflex:install spring=false # do not remove spring (equivalent to answering `n`)
rails stimulus_reflex:install example=true # create an example page and route
rails stimulus_reflex:install trace=true # debug install process with full stack trace

rails stimulus_reflex:install:step mrujs # force install mrujs
rails stimulus_reflex:install:step compression # monkey patch Action Cable to compress WS traffic with deflate

# full fat install with zero interactive prompts, suitable for scripting
rails stimulus_reflex:install esbuild entrypoint=app/javascript uncomment=true example=true
```

## Why should this be added

First, we really need to up our installation and integration game to
overcome the emotional barrier people often feel when comparing us
against a built-in solution. The more we can make installing SR/CR feel
like ordering a Big Mac combo, the less water "golden path" arguments
hold.

Second, I am convinced that one of the most powerful things we can do to
advance the adoption of this stack is to put as much energy into the
onboarding experience as we can, and to that end, I want to develop the
built-in `example` to showcase as many core concepts and
*differentiating* features as we can on one page. I'm picturing an
engaging "long scroll" that alternates between live demos with code
examples, short lists of compelling features and maybe even a few
testimonials, like a microsite.

---

The CableReady version now lives at
stimulusreflex/cable_ready#233.

Co-authored-by: Marco Roth <marco.roth@intergga.ch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants