My browser-side JavaScript uses a dynamic import import('/some-url')
which sometimes throws an error.
How can I tell whether the thrown error originates from the loaded JavaScript module, or from the browser because no JavaScript module was found at '/some-url'
?
The error thrown by the browser if '/some-url'
doesn’t return a JavaScript module doesn’t seem to follow any convention:
- In Chrome,
err.message
is'Failed to fetch dynamically imported module: https://stackoverflow.com/some-url'
- In firefox,
err.message
is'error loading dynamically imported module'
.
A hackish way to implement this:
async function isJavaScriptModule(url) {
try {
await import(url);
} catch (err) {
if (isNetworkError(err)) {
return false;
} else {
// The module at `url` may throw an error when loaded.
// It's still a JavaScript module so we return true.
return true;
}
}
return true;
}
function isNetworkError(err) {
const messages = [
"Failed to fetch dynamically imported module",
"error loading dynamically imported module",
];
return messages.some((msg) => err.message.includes(msg));
}
But that isn’t reliable, since browser vendors may change the error message at any time.
Is there a more reliable way to implement this?
3
Answers
Id try fetching, then checking if the fetch worked and returned a js module and then importing:
You can differentiate between the two error types by checking the error instance. If the URL in the import is incorrect, it will result in a
TypeError
instance. Conversely, a custom error within the module will be an instance of Error.Example with a wrapper function:
The demo can be forked from here
There is indeed no easy way to determine this. The script execution could throw the exact same error you’d get with a network error and you’d have no way of knowing where it came from.
So for this you will probably have to fetch again the resource on your own, and perform the same checks that
import()
does.You’ll first want to ensure that you’re allowed to fetch and that the URL is a valid URL. This is handled by the call to
fetch(url)
. If it throws here, your script didn’t execute.Then you will have to check if the
Response
instance’s.ok
is true, otherwise the browser will fail to import the module script.Finally, you’ll want to ensure the
Content-Type
of the resource is correctly set to one of the many JS MIME types (assuming you’re loading a JS module).This last step is probably the most complicated since this "Content-Type" header can come in many forms. I’ll provide a really quickly made sketch below, but you should really search for a better one (e.g jsdom has one).
Ps: Note that in Firefox it seems the returned error’s
.stack
is the empty string when it’s caused by a network error, while it points to the faulty script otherwise. Unfortunately at least Chrome doesn’t do the same and I’m not sure any behavior is specced.