Closed blainekasten closed 2 years ago
In my experience this is a pain point as well. My hackish remedy was to monkeypatch React::Renderer.reset_combined_js! to write out the contents of @@combined_js to a file in tmp/
You can at least this way match up line numbers from the stack trace to actual javascript code, still not ideal but has helped me solve problems with server side rendering.
yeah. I could also see something cool like that being printed to the ruby console. a good example of an error indicator is the babel compiler. When it encounters errors, it spits out a syntax highlighted output of the error line and the surrounding lines. That could also be a great solution.
:+1: Recently I'm using server-rendering more myself, and I've had the same workflow (first make it perfect, then prerender: true
). I'd be happy to pitch in or try something out along the way!
@rmosolgo Before you do server pre-rendering, do you get real React errors/debugging? Right now whenever there is a React error in my app, the component doesn't render and fails silently. No errors on rails server or client side in chrome console.
huh, yeah I usually get normal React errors (or a such-and-such is undefined
if I have a typo in the react_component
helper). Happy to help debug if you care to share some code. I think I'm on React 0.13, not sure if anything changed since then.
I second @barefootford, whatever error in React I only get "SyntaxError: unknown:" and reference to javascript_include_tag 'application':
It would be so helpful to get normal React errors! :)
I'm not sure if there is something that I'm configuring differently, but I had the same story with the first project I used with react-rails, but on my second one I'm getting errors server side and in the console depending on the issue. I haven't had time to debug and figure out what the difference is.
same problem here. In my case, I patch ComponentMount
as follows to retry rendering with prerender: false
when something goes wrong during server rendering:
# config/initializers/react-rails.rb
class React::Rails::ComponentMount
def react_component_with_auto_retry(name, props = {}, options = {}, &block)
react_component_without_auto_retry(name, props, options, &block)
rescue
if options[:prerender] && Rails.env.development?
react_component_without_auto_retry(name, props, options.merge(prerender: false), &block)
else
raise
end
end
alias_method_chain :react_component, :auto_retry
end
Any other insight as to how to debug with prerender:true. I'm getting an error but there is no indication whatsover where it comes from so I really don't know what to do next. It all works well with no prerender... Thanks!
@shaimo Same thing here. No JS warnings without prerender, but as soon as I turn it on I get errors "can't parse [...]"
I'll try updating my javascript runtime, but I am not having any luck yet.
Old thread I know, but putting this here for anyone who might find it in future as I didn't really find much online.
Basically a modified version of the above which didn't work for me on Rails 5.1, Ruby 2.5.3.
This will catch errors rendering and try again without pre-rendering it. We then have an error boundary in the React code that will catch any errors with componentDidCatch
and POST them to our API which logs them. It doesn't help track down errors that are specific to SSR, but at least means users won't get a 500, and for errors that affect client side rendering too, they will get a friendly error page and we will get a report.
# config/initializers/react-rails.rb
class React::Rails::ComponentMount
old_react_component = instance_method(:react_component)
define_method(:react_component) do |name, props = {}, options = {}|
begin
old_react_component.bind(self).(name, props, options)
rescue
old_react_component.bind(self).(name, props, options.merge(prerender: false))
end
end
end
@noisyscanner Thank you for that snippet, that's likely to help a lot of people! Wonder if we could make use of something like that as part of the gem, or at least put it somewhere visible such as readme or wiki page.
++ on this sentiment. I'm getting this following error:
Encountered error "#<ExecJS::ProgramError: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.>" when prerendering HelloWorld with {}
which is caused by even just importing this one specific module. Besides the fact that this error message is pretty misleading, it also doesn't print out where this error happened. I might be understanding it wrong, but it looks like something is aggressively catching errors and components are undefined at render time since their module execution failed. Anyone find better ways of debugging prerender issues? Unfortunately I'm not able to provide a fallback of no ssr, since it's a feature that we heavily rely on
I have a same problem as you @keyboard-clacker -
Encountered error "#<ExecJS::ProgramError: Invariant Violation: Element type is invalid: ...
Error message is wrong - the rendering works for case when it's not prerendered, so it's not the case. It's also quite hard to debug and see where the problem appeared. I suspect it's some dependency on yarn.lock that I've updated, but don't know which and how.
Regarding Encountered error "#<ExecJS::ProgramError: Invariant Violation: Element type is invalid: ...
:
I think one of the core issues is that module lookup uses try...catch
. While the errors are logged to the console shim, that typically doesn't help as a later error (such as the invariant violation) will lead to a fatal error (triggering a 500). If that could be refactored to be a bit more intentional based on environment (instead of just reacting based on exceptions, or at the very least, throwing if the caught exception isn't very specific)
EDIT: Here's something you can do to help with the Invariant Violation
bug:
In app/javascripts/packs/server_rendering.js
, replace ReactRailsUJS.useContext('require.context('components', true));
with
// So that we don't fall back to the global namespace (which leads to hard to
// parse errors).
function fromRequireContext(reqctx) {
return function(className) {
const parts = className.split('.');
const filename = parts.shift();
const keys = parts;
// Load the module:
let component = reqctx('./' + filename);
// Then access each key:
keys.forEach((k) => {
component = component[k];
});
// support `export default`
if (component.__esModule) {
component = component.default;
}
return component;
};
}
ReactRailsUJS.getConstructor = fromRequireContext(require.context('components', true));
@HarrisonB if we ever happen to meet in person, I owe you a round of drinks. This is exactly what I needed!
@HarrisonB Bro :) saved my life with this script when debugging this 💩 react-rails error :)
why this answer isn't the default https://github.com/reactjs/react-rails/issues/264#issuecomment-552326663? The Invariant Violation
error doesn't give you any hints on how to debug the error.
We have a resolution for this issue. Closing it.
In my experience, when using
prerender: true
, if something breaks the server side rendering, the error messages are less than helpful.. My workflow has become anytime that happens to stop prerendering and use browser tools to diagnose where the issue is. The stack trace provided by the gem is no where near the help that comes from browser tools.Have we thought of the idea of in the case of a prerender error to not throw an error, but instead disengage the prerendering. Maybe wrap the code that caused the server error in a
debugger;
call to help users know something is wrong?maybe even include an alert message. So something like this is what I have in mind:
prerender catches error
thoughts?