Skip to content
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

Debugging Solutions for Prerender #264

Closed
blainekasten opened this issue May 14, 2015 · 19 comments
Closed

Debugging Solutions for Prerender #264

blainekasten opened this issue May 14, 2015 · 19 comments

Comments

@blainekasten
Copy link

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

  • find error location
  • Inject the following above the error
alert('ReactRails encountered an error server side rendering, please inspect your issue with your browser dev tools');
debugger;
// error code is here.

thoughts?

@mchristen
Copy link

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.

@blainekasten
Copy link
Author

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.

@rmosolgo
Copy link
Member

👍 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!

@barefootford
Copy link

@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.

@rmosolgo
Copy link
Member

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.

@axhamre
Copy link

axhamre commented Aug 24, 2015

I second @barefootford, whatever error in React I only get "SyntaxError: unknown:" and reference to javascript_include_tag 'application':

react_error

It would be so helpful to get normal React errors! :)

@barefootford
Copy link

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.

@yuku
Copy link
Contributor

yuku commented Oct 15, 2015

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

@shaimo
Copy link

shaimo commented Dec 13, 2015

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!

@tyler-boyd
Copy link

@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.

@noisyscanner
Copy link

noisyscanner commented Apr 19, 2019

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

@BookOfGreg
Copy link
Member

@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.

@avegancafe
Copy link

avegancafe commented May 30, 2019

++ 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

@bryszard
Copy link

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.

@hibachrach
Copy link
Contributor

hibachrach commented Nov 11, 2019

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));

@avegancafe
Copy link

@HarrisonB if we ever happen to meet in person, I owe you a round of drinks. This is exactly what I needed!

hibachrach added a commit to hibachrach/react-rails that referenced this issue Jan 10, 2020
Quoting reactjs#264 (comment)

> 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`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> 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)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
hibachrach added a commit to hibachrach/react-rails that referenced this issue Jan 10, 2020
Quoting reactjs#264 (comment)

> 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`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> 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)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
@adamklepacz
Copy link

adamklepacz commented Mar 27, 2020

@HarrisonB Bro :) saved my life with this script when debugging this 💩 react-rails error :)

@orlando
Copy link
Contributor

orlando commented Apr 14, 2021

why this answer isn't the default #264 (comment)? The Invariant Violation error doesn't give you any hints on how to debug the error.

hibachrach added a commit to hibachrach/react-rails that referenced this issue Aug 18, 2022
Quoting reactjs#264 (comment)

> 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`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> 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)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
hibachrach added a commit to hibachrach/react-rails that referenced this issue Sep 30, 2022
Quoting reactjs#264 (comment)

> 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`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> 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)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
@alkesh26
Copy link
Collaborator

We have a resolution for this issue. Closing it.

fstar-dev added a commit to fstar-dev/react-rails that referenced this issue Jan 27, 2023
Quoting reactjs/react-rails#264 (comment)

> 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`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> 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)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
goldapple911 added a commit to goldapple911/react-rails that referenced this issue Aug 15, 2023
Quoting reactjs/react-rails#264 (comment)

> 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`](https://github.com/reactjs/react-rails/blob/master/react_ujs/src/getConstructor/fromRequireContextWithGlobalFallback.js#L11-L23).
> 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)

This enables us to easily override `getConstructor` to not use global
fallback, avoiding the all-consuming `try...catch`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests