-
Notifications
You must be signed in to change notification settings - Fork 69
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
Delay fragment loading until something else loaded #302
Comments
Also, I'd just like to say thanks for the work put into this project. Implementing rich interfaces using Unpoly is a million times easier than messing around with webpack build files for a standard business application! |
I'm not sure how this would work in practice, but if I was to approach this, I might look at doing something like this:
You wouldn't want the shim compiler to run again, so perhaps you'd set an attribute on the element that knew the shim already ran (since ie. up.compiler('[compiler-one]', function(el) {
if (el.loaded) return
el.loaded = true
await loadScript("/scripts/compiler-one.js")
up.hello(el)
})
up.compiler('[compiler-two]', function(el) {
if (el.loaded) return
el.loaded = true
await loadScript("/scripts/compiler-two.js")
up.hello(el)
})
// I duplicated to illustrate the example but I'd move this into a function to reduce the duplication Re-calling |
I don't think that would work for me since what I'm trying to do is get away from a single point that knows about all compilers (we might well have hundreds).
However your idea of double rendering did spark an idea. I can probably *cancel* the original render, load the scripts and then manually call up.render with the render options and content for the original response.
That way I am in control of when the render happens so can wait until any assets I need are loaded.
Thanks for taking the time to reply
|
If there is a
Can you share why you expect to have that number of compilers?
I would modify @adam12's approach so we don't need to re-call // lazy-compilers.js, always loaded
up.compiler('[one]', function(el) {
await loadScript("/scripts/one.js")
one(el)
})
up.compiler('[two]', function(el) {
await loadScript("/scripts/two.js")
two(el)
})
// one.js, loaded on demand
function one(element) {
...
}
// two.js, loaded on demand
function two(element) {
...
} |
Yes. This was a simplified example. I'm actually looking to add the behaviour TurboLinks / Hotwire has where it will correctly load and merge scripts in the head if they have not been loaded already, but wanted a simple example.
I work on large enterprise applications. Looking at ways of modernising legacy javascript on applications which can easily have 300-400 separate forms which have "behaviour" associated with them - enabling fields when other fields change etc - I believe Unpoly requires all Javascript to be registered via compilers so each form would require one. Rather than having a single central massive file with a large number of compilers, I'd prefer Unpoly to simply load the new scripts required as it needed them. I know this isn't built into Unpoly so was looking to add it using the existing hooks. I figured I could do this as follows
Do you see anything technically wrong with that? As far as I can see, all we are doing is "pausing" the render whilst we load additional compilers and then "resuming" by manually calling render with the original options. As long as we track which scripts have already been loaded, it should be the same as having loaded them all up front, just with a slight delay the first time a compiler needs to be dynamically loaded. |
For reference, I have now written a quick test to try the above logic out. It works perfectly (delays the render until the script has loaded and thus causes the newly loaded compiler to execute on the fragment). However, since I am then doing a local render it does not update the URL in the same way Unpoly does.
Is there a method I can call with the URL which would do the same URL related logic as normally happens after a render? I tried to walk through the logic to find where this occurred, but couldn't find it. |
I see. Have you considered a pattern like this:
// /scripts/forms/login.js
export default function(form) {
// initialize JavaScript behavior on the given form
} <form behavior="/scripts/forms/login.js">
...
</form> up.compiler('[behavior]', async function(element) {
let scriptURL = element.getAttribute('behavior')
let behavior = await import(scriptURL)
behavior.default(element)
})
To change the browser's location bar while rendering content from a string, pass the URL as a |
A different approach to handle this was proposed in RFC: Reconciliation of |
I've read through the RFC and it sounds absolutely perfect - it is vastly more comprehensive than I was expecting, but definitely covers every use case I can think of |
The use cases described in this issue should now be possible. See docs: |
Bug description
What I am trying to do is something along the following lines
The idea is to allow the Unpoly compilers to be loaded dynamically as needed rather than all up front (large legacy codebase so there might be several hundred compilers which I don't want to load up front).
Problem is that I can't seem to make up:fragment:loaded wait for my script to load before inserting the fragment.
Reproduction project
I've made a basic reproduction here
https://glitch.com/edit/#!/nonstop-adhesive-way
which is based to some degree on
https://makandracards.com/makandra/52361-unpoly-loading-large-libraries-on-demand
Effectively, all I'm trying to do is "automate" the method above by inspecting the response html in a fragment and loading appropriate scripts based on the response content.
Steps to reproduce the behavior:
There are good explanations of expected behaviour and what I would hope to see here
https://glitch.com/edit/#!/nonstop-adhesive-way?path=scripts.js%3A38%3A91
Expected behavior
I was hoping to make the up:fragment:inserted wait until my additional script had loaded so that, when it is inserted, the compiler which is part of the new script will be run. Unfortunately, it doesn't which mean the fragment is inserted before my additional script has fully loaded.
The text was updated successfully, but these errors were encountered: