-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Support async functions for loading the utils script #1838
Support async functions for loading the utils script #1838
Conversation
This makes sure any errors/rejections that occur when trying to load the utilities script asynchronously can be handled by developers of this package. Previously, you'd wind up with "unhandled promise rejection" errors in your console no matter what you did. The previous behavior also prevented testing async loading in Jest, which considers these async errors to be test failures. This also makes sure that the actual error gets passed through to the `itiInstance.promise` property so developers can get access to it, and better understand what the issue was. Previously, you'd just get the promise rejected with `undefined`. Finally, this changes the error message in builds that have the utilties built in. The previous method of producing an error caused *other* things in the library to fail (or really, never complete) and was not especially informative. There is now a more detailed message that shows up as an actual failure in all the right places instead of leaving some stuff hanging.
The argument to `loadUtils` and the value of the `utilsScript` option can now be a function that returns a promise for the utils module object instead of just a string to load them from. This makes it easier to build separate bundles for utils when using bundles like Webpack, Parcel, Vite, etc. as well as providing more flexible options for mocking or loading alternative versions of utils. Fixes jackocnr#1816.
931c2d8
to
954b053
Compare
This is really incredible work. This must be the most professional and comprehensive PR I've ever received! Thank you so much for your hard work here - it is really appreciated. This is a great step forward for the project. 💐 BTW, I agree with your footnote suggestions and would welcome a PR to that effect if you have time. |
Released in v24.6.0 |
Will see if I can find some time for it later this week. 👍 |
@Mr0grog do you know what, on second thought, I don't think it's worth adding a new static method just for the edge case of people who (A) have multiple instances, and (B) use a bad utils URL, just to prevent them from receiving a duplicate error message. The duplicate error message is really not a problem for me in this case. I think the only thing that's important is that it's possible for people to catch this error if they want to. I believe this is already possible, but forgive me, I don't have time to double-check right now - can you confirm? (we should update the readme to make this clear) Additionally, in the next major release, I plan to simplify this utils loading code so that both loadUtilsOnInit and loadUtils stop accepting a string argument and only accept the function that returns a promise which resolves to the utils module. That way, we can remove the plugin's dynamic import which will make things more straight forward. |
Fair enough! FWIW, I do think the idea was about more than those two things, since it also covers errors from the geo lookup, too (the way
That was what the first commit in this PR does. You have to call
FWIW, you'd still need all the same error handling and so on, and this would not have resolved most of the issues I ran into with Jest. |
Right, perfect, thanks.
Ok, good to know, but I'm not worried about handling this just yet.
👍🏻
Sorry, I'm confused - are you saying that this proposed change would make the situation worse? |
No, sorry for being unclear! It would definitely eliminate one conditional branch from As for Jest in particular, this would eliminate the need for the |
That’s not to say there aren’t things you could do to simplify this functionality. There’s some stuff I think I could have done more nicely in |
Fixes #1816.
Sorry this was a bit of a long time coming! I ran into a few messy issues with Jest (partially detailed in #1630) that caused me to have to do the side-note item (making sure there are no unhandled promises) to get the existing tests to run in Jest, but then I ran into complex dynamic import problems in Jest and went back to Jasmine for the new tests, and then eventually figured out the right workarounds for transforming the imports in Jest. 😩 Hopefully these commits are clearly factored enough to better evaluate the different pieces of work.
Anyway, this PR does a few main things:
Make sure the library never leaves promises in an unhandle-able state (thereby sometimes causing internal exceptions that can never be addressed by developers using the package). Specifically, the
loadUtils()
static function returns a promise, but when a new instance calls that function to lazy load the utils, promise rejections were never handled (the instances do get informed about the failure, but through a complex setup that leaves the failure unhandled).I’ve changed things to:
loadUtils()
internally. When users call it directly, however, it is left unhandled and they need to make sure to cover it.undefined
as the reason, and now you get a proper error object with more info, like "couldn’t import ” or “syntax error on line ”.This felt like the minimum change to solve the unhandle-able errors issue, although I think an ideal solution might be a bit different (see footnotes).
I also tweaked the types for
startedLoadingAutoCountry
andstartedLoadingUtilsScript
to always be booleans (previously they were<not-present> | true
) because I noticed some tests were broken because the test cleanup resets them tofalse
instead of resetting them by deleting them (only visible as a fail if those tests run first). This should be pretty minor, I hope.Added a server for the Jasmine tests or for viewing the
demo.html
file over HTTP, so you can test dynamic imports of the utils. (Trying to load from afile://
URL is not allowed in most browsers for security reasons.)The server starts automatically for Jasmine, or you can run
npm run server
ornpx grunt jasmine:interactive
to start a long-running server on port 8000. Then you can load uphttp://localhost:8000/demo.html
orhttp://localhost:8000/spec.html
to debug in a browser. See changes toCONTRIBUTING.md
for more description.Added support for
loadUtils()
to take an async function that resolves to the loaded module and for theutilsScript
option to do the same. Also renamed the option fromutilsScript
→loadUtilsOnInit
, per the discussion.This includes expanded tests to cover actually loading (or failing to load) the code.
Ported the
loadUtilsOnInit
option andloadUtils
static function tests from Jasmine → Jest.As part of this, I moved the Jest config into a separate file so I could add comments, but I can put it back in
package.json
if you’d prefer.Footnote
How load failures are handled: a page with 2 inputs on it that never explicitly handles rejections of
<instance>.promise
will log 2 errors (unhandled rejections) to the browser console. That is, this setup:Will log two errors when
"path/to/utils.js"
fails to load. That’s better than it used to be, when three were logged and one of those could never be suppressed (the one coming fromloadUtils()
directly instead of from<instance>.promise
).However, you get the same error N times, once for each instance on the page, seems annoying. Handling all errors correctly also means developers have to attached handlers to
<instance>.promise
, which seems like a pain. I think a nicer solution here would be:Add a
intlTelInput.handleError(handlerFunction)
static method, or maybe an"error"
event (or a differently named event that doesn’t conflict with the browser’s built-in one) that allows people to install a global error handler. If users don’t install their own handler, we’d have a default one that logs the error. But this gives people a nice, singular hook to send errors to monitoring services like Sentry/Datadog/etc. This could also handle errors from autoloading the country, etc, which has similar issues.Ensure
<instance>.promise
is always handled with a no-op handler. Developers can still catch rejections from it, but if they don’t, they won’t get unhandled rejection errors in their console.This way an error loading the utils script only gets logged once, instead of for every phone input on the page, and there is a clear place to hook up and handle global errors.