symfony / stimulus-bridge

Stimulus integration bridge for Symfony projects
https://symfony.com/ux
75 stars 15 forks source link

Lazy controllers for user-land controllers #19

Closed weaverryan closed 3 years ago

weaverryan commented 3 years ago

Hi!

This allows users to make their own controllers "lazy" by adding a special comment above their controllers:

// assets/controllers/hello_controller.js
import { Controller } from 'stimulus';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
    // ...
}

When you do this, your controller (and its dependencies) are not included in the main app.js built file. Instead, they are split into their own chunk/file. This file is loaded asynchronously the moment that the first element appears on the page for this controller (e.g. <div data-controller="hello">). This follows up on #15 (and only the last commit is new to this PR). The /* stimulusFetch: 'lazy' */ is inspired by Webpack's /* webpackMode: 'lazy' */ comments and uses the same mechanism to parse them.

To activate this, you only need to process your controllers through a new loader:

// assets/bootstrap.js

export const app = startStimulusApp(require.context(
-    './controllers',
+    '@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
    true,
    /\.(j|t)sx?$/
));

That looks a bit ugly, but this is code that we'll give users via the recipe anyways. I've tested this in a real app and it works beautifully ❤️ .

Cheers!

tgalopin commented 3 years ago

People use a lot the 'use strict'; syntax to declare strictness. Would it make sense to have 'use lazy'; as a notation instead of a comment?

weaverryan commented 3 years ago

I don’t know! I’ll admit that this is the weirdest part - I’m inventing something. However, comments can be removed in the final, minimized code, which is perfect because the comments are there only to hint to the compiler. So in some ways, it seems more appropriate (though in theory we could find and remove the “use lazy”). And also, I think it would be harder to parse for that string - the comments thing was easy.

If we feel strongly about the change, I can try it. But we do have a mechanism to deprecate the comment later if we don’t like it: we just parse for it in the loader and logger a deprecation. So it’s changeable.

tgalopin commented 3 years ago

After thinking about it I do agree the comment is the most suited option. I'm not sure how it would work with Typescript though: would it be removed by ts-loader before webpack can read it?

(+ needs rebase)

weaverryan commented 3 years ago

I'm not sure how it would work with Typescript though: would it be removed by ts-loader before webpack can read it?

It appears to work fine with Typescript - even in a production/minified build. I expected this - since we're using the same mechanism that Webpack uses - but I just tried it locally on a project.

tgalopin commented 3 years ago

Thanks Ryan.