Giter Site home page Giter Site logo

Comments (11)

tleish avatar tleish commented on July 28, 2024 1

Do explore that in Turbo

The dynamic loading of the stimulus controllers occurs in the stimulus-loading.js
library in this codebase. Would it then make more sense to include the logic in the library which dynamically loads the stimulus controllers?

Basing it off this closed PR created by @seanpdoyle, the following modifications dispatches an event stimulus:ready which solves the issue for us:

function loadController(name, under, application) {
  if (!(name in registeredControllers)) {
+   registeredControllers[name] = false
    import(controllerFilename(name, under))
      .then(module => registerController(name, module, application))
-     .catch(error => console.error(`Failed to autoload controller: ${name}`, error))
+     .catch(error => importError(error, name))
+     .finally(()  => dispatchWhenReady())
  }
}

function registerController(name, module, application) {
- if (!(name in registeredControllers)) {
+ if (!registeredControllers[name]) {
    application.register(name, module.default)
    registeredControllers[name] = true
  }
}

+ function importError(error, name) {
+   delete registeredControllers[name]
+   console.error(`Failed to autoload controller: ${name}`, error)
+ }

+ function dispatchWhenReady() {
+   if(Object.values(registeredControllers).every(Boolean)) {
+     const controllers = Object.keys(registeredControllers);
+     const event = new CustomEvent('stimulus:ready', { detail: { controllers }, bubbles: true });
+     document.dispatchEvent(event);
+   }
+ }

from stimulus-rails.

dhh avatar dhh commented on July 28, 2024

Hmm, not an easy problem to solve, because lazy loading is loading things dynamically. So some controllers might have been loaded already, and good to go. Others only load when new HTML appears that have them in there.

Seems like what we need is essentially turbo:finish or something like that which captures all forms of turbo loading. Do explore that in Turbo 👍

from stimulus-rails.

dhh avatar dhh commented on July 28, 2024

Actually, yes, I do like that option too. I was thinking of turbo:finish, which I also think we should explore. But I'd take the stimulus:ready event too. That's a good idea.

from stimulus-rails.

drewlustro avatar drewlustro commented on July 28, 2024

Hello @dhh @tleish – Is there any continued interest on this one?

I also would be quite interested in a stimulus:ready event (per controller), and perhaps a turbo:finish (once all loading complete). I checked out stimulus-loading.js and I didn't see an event emitted.

On our application, we've moved to lazyLoadControllersFrom for performance reasons, but are noticing a 300–700ms delay from seeing HTML to the page actually being ready for interaction (controllers loaded).

Of course, it could be because we're still loading much unnecessary JS prior to MutationObserver kicking in effect, so maybe it's a "main thread blocked for too long" issue.

In any case, stimulus emitting such an event on lazy load would help validate any hypothesis/diagnostic.

from stimulus-rails.

dhh avatar dhh commented on July 28, 2024

I'm actually starting to think that maybe we shouldn't lazy load at all. That it just makes things too complicated. The majority of apps should just preload all controllers. And the ones who can't do that can just have different includes per page. I think scanning the HTML to lazy load is too clever, too slow, and too error prone.

We already changed the default to eager loading.

from stimulus-rails.

tleish avatar tleish commented on July 28, 2024

it just makes things too complicated

@dhh - Curious what problems you are running into. We occasionally need to handle order dependencies of cross-controller communication using lazy loading, but it hasn't been a major issue.

We see quite a difference in performance initial page load when testing using speed test using lighthouse, we see numbers like:

  • eager load: 68 lighthouse performance score
  • lazy load: 95 lighthouse performance score

from stimulus-rails.

dhh avatar dhh commented on July 28, 2024

Problem is attachment timing. When there are things in the DOM that need to change from a controller. I seem to remember us getting visual jitter from it.

Haven't seen anything like that on lighthouse score differences. Is that a CDN issue maybe?

from stimulus-rails.

tleish avatar tleish commented on July 28, 2024

Numbers posted above are just from running localhots. Only difference between the to runs is the use of @hotwired/stimulus-loading#eagerLoadControllersFrom vs @hotwired/stimulus-loading#lazyLoadControllersFrom

from stimulus-rails.

dhh avatar dhh commented on July 28, 2024

Gotcha. If you actually need those controllers loaded, and they operate on the DOM, I think that difference is artificial.

from stimulus-rails.

tleish avatar tleish commented on July 28, 2024

We have lots of stimulus controllers and js libraries. We need a portion of the controllers for a given page, but not all of them.

For example, I see hey.com has over 230 js modules, with over 150 of them as controllers. Managing which controller to load on which page seems like a pain. Loading all 230 files on every page load also seems overkill, even with http2. Dynamically lazy loading the modules as they are used in the DOM makes it so much easier from a development perspective, cleaner and faster from a user/browser loading experience. Especially when some of those controllers might include large js modules.

I assume this is why hey.com also uses lazyloading:

/* app.hey.com/assets/controllers/index.js */
import { application } from "controllers/application"
import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"

lazyLoadControllersFrom("controllers", application)

It's a slick strategy.

from stimulus-rails.

dhh avatar dhh commented on July 28, 2024

from stimulus-rails.

Related Issues (20)

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.